diff options
201 files changed, 12525 insertions, 1800 deletions
diff --git a/CodingReadme b/CodingReadme index ba184be5..cbe1fb8b 100644 --- a/CodingReadme +++ b/CodingReadme @@ -239,7 +239,7 @@ C++ Language ------------- Yosys is written in C++11. At the moment only constructs supported by -gcc 4.6 are allowed in Yosys code. This will change in future releases. +gcc 4.8 are allowed in Yosys code. This will change in future releases. In general Yosys uses "int" instead of "size_t". To avoid compiler warnings for implicit type casts, always use "GetSize(foobar)" instead @@ -368,7 +368,7 @@ And if a version of the verific library is currently available: ../../yosys test_navre.ys -Finally run all tests with "make config-{clang,gcc,gcc-4.6}": +Finally run all tests with "make config-{clang,gcc,gcc-4.8}": cd ~yosys make clean @@ -1,9 +1,10 @@ CONFIG := clang # CONFIG := gcc -# CONFIG := gcc-4.6 +# CONFIG := gcc-4.8 # CONFIG := emcc # CONFIG := mxe +# CONFIG := msys2 # features (the more the better) ENABLE_TCL := 1 @@ -29,8 +30,9 @@ SANITIZER = PREFIX ?= /usr/local INSTALL_SUDO := -TARGET_BINDIR := $(DESTDIR)$(PREFIX)/bin -TARGET_DATDIR := $(DESTDIR)$(PREFIX)/share/yosys +BINDIR := $(PREFIX)/bin +LIBDIR := $(PREFIX)/lib +DATDIR := $(PREFIX)/share/yosys EXE = OBJS = @@ -47,9 +49,11 @@ all: top-all YOSYS_SRC := $(dir $(firstword $(MAKEFILE_LIST))) VPATH := $(YOSYS_SRC) -CXXFLAGS += -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -D_YOSYS_ -fPIC -I$(DESTDIR)$(PREFIX)/include -LDFLAGS += -L$(DESTDIR)$(PREFIX)/lib +CXXFLAGS += -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -D_YOSYS_ -fPIC -I$(PREFIX)/include +LDFLAGS += -L$(LIBDIR) LDLIBS = -lstdc++ -lm + +PKG_CONFIG = pkg-config SED = sed BISON = bison @@ -68,7 +72,7 @@ else LDLIBS += -lrt endif -YOSYS_VER := 0.6+$(shell test -d .git && { git log --author=clifford@clifford.at --oneline 5869d26da021.. | wc -l; }) +YOSYS_VER := 0.6+$(shell test -e .git && { git log --author=clifford@clifford.at --oneline 5869d26da021.. | wc -l; }) GIT_REV := $(shell cd $(YOSYS_SRC) && git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN) OBJS = kernel/version_$(GIT_REV).o @@ -78,10 +82,15 @@ 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 = ae7d65e71adc +ABCREV = 8e08604f8ad3 ABCPULL = 1 +ABCURL ?= https://bitbucket.org/alanmi/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" +# set ABCEXTERNAL = <abc-command> to use an external ABC instance +# Note: The in-tree ABC (yosys-abc) will not be installed when ABCEXTERNAL is set. +ABCEXTERNAL = + define newline @@ -105,8 +114,8 @@ ifeq ($(SANITIZER),address) ENABLE_COVER := 0 endif ifeq ($(SANITIZER),memory) -CXXFLAGS += -fPIE -LDFLAGS += -fPIE +CXXFLAGS += -fPIE -fsanitize-memory-track-origins +LDFLAGS += -fPIE -fsanitize-memory-track-origins endif ifeq ($(SANITIZER),cfi) CXXFLAGS += -flto @@ -117,12 +126,12 @@ endif else ifeq ($(CONFIG),gcc) CXX = gcc LD = gcc -CXXFLAGS += -std=gnu++0x -Os +CXXFLAGS += -std=c++11 -Os -else ifeq ($(CONFIG),gcc-4.6) -CXX = gcc-4.6 -LD = gcc-4.6 -CXXFLAGS += -std=gnu++0x -Os +else ifeq ($(CONFIG),gcc-4.8) +CXX = gcc-4.8 +LD = gcc-4.8 +CXXFLAGS += -std=c++11 -Os else ifeq ($(CONFIG),emcc) CXX = emcc @@ -155,18 +164,29 @@ yosys.html: misc/yosys.html $(P) cp misc/yosys.html yosys.html else ifeq ($(CONFIG),mxe) -CXX = /usr/local/src/mxe/usr/bin/i686-pc-mingw32-gcc -LD = /usr/local/src/mxe/usr/bin/i686-pc-mingw32-gcc -CXXFLAGS += -std=gnu++0x -Os -D_POSIX_SOURCE +CXX = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc +LD = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc +CXXFLAGS += -std=c++11 -Os -D_POSIX_SOURCE CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s LDLIBS := $(filter-out -lrt,$(LDLIBS)) -ABCMKARGS += ARCHFLAGS="-DSIZEOF_VOID_P=4 -DSIZEOF_LONG=4 -DSIZEOF_INT=4 -DWIN32_NO_DLL -x c++ -fpermissive -w" +ABCMKARGS += ARCHFLAGS="-DSIZEOF_VOID_P=4 -DSIZEOF_LONG=4 -DSIZEOF_INT=4 -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -x c++ -fpermissive -w" ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=1 CC="$(CXX)" CXX="$(CXX)" EXE = .exe +else ifeq ($(CONFIG),msys2) +CXX = i686-w64-mingw32-gcc +LD = i686-w64-mingw32-gcc +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="-DSIZEOF_VOID_P=4 -DSIZEOF_LONG=4 -DSIZEOF_INT=4 -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -x c++ -fpermissive -w" +ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=0 CC="$(CXX)" CXX="$(CXX)" +EXE = .exe + else ifneq ($(CONFIG),none) -$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, gcc-4.6, emcc, none) +$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, gcc-4.8, emcc, mxe, msys2) endif ifeq ($(ENABLE_LIBYOSYS),1) @@ -182,12 +202,12 @@ endif endif ifeq ($(ENABLE_PLUGINS),1) -CXXFLAGS += -DYOSYS_ENABLE_PLUGINS $(shell pkg-config --silence-errors --cflags libffi) -LDLIBS += $(shell pkg-config --silence-errors --libs libffi || echo -lffi) -ldl +CXXFLAGS += -DYOSYS_ENABLE_PLUGINS $(shell $(PKG_CONFIG) --silence-errors --cflags libffi) +LDLIBS += $(shell $(PKG_CONFIG) --silence-errors --libs libffi || echo -lffi) -ldl endif ifeq ($(ENABLE_TCL),1) -TCL_VERSION ?= tcl$(shell echo 'puts [info tclversion]' | tclsh) +TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')") TCL_INCLUDE ?= /usr/include/$(TCL_VERSION) CXXFLAGS += -I$(TCL_INCLUDE) -DYOSYS_ENABLE_TCL LDLIBS += -l$(TCL_VERSION) @@ -204,8 +224,10 @@ endif ifeq ($(ENABLE_ABC),1) CXXFLAGS += -DYOSYS_ENABLE_ABC +ifeq ($(ABCEXTERNAL),) TARGETS += yosys-abc$(EXE) endif +endif ifeq ($(ENABLE_VERIFIC),1) VERIFIC_DIR ?= /usr/local/src/verific_lib_eval @@ -257,6 +279,7 @@ $(eval $(call add_include_file,kernel/log.h)) $(eval $(call add_include_file,kernel/rtlil.h)) $(eval $(call add_include_file,kernel/register.h)) $(eval $(call add_include_file,kernel/celltypes.h)) +$(eval $(call add_include_file,kernel/celledges.h)) $(eval $(call add_include_file,kernel/consteval.h)) $(eval $(call add_include_file,kernel/sigtools.h)) $(eval $(call add_include_file,kernel/modtools.h)) @@ -267,10 +290,14 @@ $(eval $(call add_include_file,libs/ezsat/ezsat.h)) $(eval $(call add_include_file,libs/ezsat/ezminisat.h)) $(eval $(call add_include_file,libs/sha1/sha1.h)) $(eval $(call add_include_file,passes/fsm/fsmdata.h)) +$(eval $(call add_include_file,frontends/ast/ast.h)) $(eval $(call add_include_file,backends/ilang/ilang_backend.h)) -OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o kernel/yosys.o kernel/cellaigs.o +OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o kernel/yosys.o +OBJS += kernel/cellaigs.o kernel/celledges.o + kernel/log.o: CXXFLAGS += -DYOSYS_SRC='"$(YOSYS_SRC)"' +kernel/yosys.o: CXXFLAGS += -DYOSYS_DATDIR='"$(DATDIR)"' OBJS += libs/bigint/BigIntegerAlgorithms.o libs/bigint/BigInteger.o libs/bigint/BigIntegerUtils.o OBJS += libs/bigint/BigUnsigned.o libs/bigint/BigUnsignedInABase.o @@ -349,9 +376,9 @@ kernel/version_$(GIT_REV).cc: $(YOSYS_SRC)/Makefile $(CXX) --version | tr ' ()' '\n' | grep '^[0-9]' | head -n1` $(filter -f% -m% -O% -DNDEBUG,$(CXXFLAGS)))\"; }" > kernel/version_$(GIT_REV).cc yosys-config: misc/yosys-config.in - $(P) $(SED) -e 's#@CXXFLAGS@#$(subst -I. -I"$(YOSYS_SRC)",-I"$(TARGET_DATDIR)/include",$(CXXFLAGS))#;' \ + $(P) $(SED) -e 's#@CXXFLAGS@#$(subst -I. -I"$(YOSYS_SRC)",-I"$(DATDIR)/include",$(CXXFLAGS))#;' \ -e 's#@CXX@#$(CXX)#;' -e 's#@LDFLAGS@#$(LDFLAGS)#;' -e 's#@LDLIBS@#$(LDLIBS)#;' \ - -e 's#@BINDIR@#$(TARGET_BINDIR)#;' -e 's#@DATDIR@#$(TARGET_DATDIR)#;' < $< > yosys-config + -e 's#@BINDIR@#$(BINDIR)#;' -e 's#@DATDIR@#$(DATDIR)#;' < $< > yosys-config $(Q) chmod +x yosys-config abc/abc-$(ABCREV)$(EXE): @@ -362,8 +389,8 @@ ifneq ($(ABCREV),default) fi $(Q) if test "`cd abc 2> /dev/null && hg identify | cut -f1 -d' '`" != "$(ABCREV)"; then \ test $(ABCPULL) -ne 0 || { echo 'REEBE: NOP abg hc gb qngr naq NOPCHYY frg gb 0 va Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; exit 1; }; \ - echo "Pulling ABC from bitbucket.org:"; set -x; \ - test -d abc || hg clone https://bitbucket.org/alanmi/abc abc; \ + echo "Pulling ABC from $(ABCURL):"; set -x; \ + test -d abc || hg clone $(ABCURL) abc; \ cd abc && $(MAKE) DEP= clean && hg pull && hg update -r $(ABCREV); \ fi endif @@ -408,20 +435,20 @@ vloghtb: $(TARGETS) $(EXTRA_TARGETS) @echo "" install: $(TARGETS) $(EXTRA_TARGETS) - $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(PREFIX)/bin - $(INSTALL_SUDO) install $(TARGETS) $(DESTDIR)$(PREFIX)/bin/ - $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(PREFIX)/share/yosys - $(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(PREFIX)/share/yosys/. + $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(BINDIR) + $(INSTALL_SUDO) install $(TARGETS) $(DESTDIR)$(BINDIR) + $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR) + $(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/. ifeq ($(ENABLE_LIBYOSYS),1) - $(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(PREFIX)/lib/ + $(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR) $(INSTALL_SUDO) ldconfig endif uninstall: - $(INSTALL_SUDO) rm -vf $(addprefix $(DESTDIR)$(PREFIX)/bin/,$(notdir $(TARGETS))) - $(INSTALL_SUDO) rm -rvf $(DESTDIR)$(PREFIX)/share/yosys/ + $(INSTALL_SUDO) rm -vf $(addprefix $(DESTDIR)$(BINDIR),$(notdir $(TARGETS))) + $(INSTALL_SUDO) rm -rvf $(DESTDIR)$(DATDIR) ifeq ($(ENABLE_LIBYOSYS),1) - $(INSTALL_SUDO) rm -vf $(DESTDIR)$(PREFIX)/lib/libyosys.so + $(INSTALL_SUDO) rm -vf $(DESTDIR)$(LIBDIR)/libyosys.so endif update-manual: $(TARGETS) $(EXTRA_TARGETS) @@ -456,7 +483,7 @@ qtcreator: vcxsrc: $(GENFILES) $(EXTRA_TARGETS) rm -rf yosys-win32-vcxsrc-$(YOSYS_VER){,.zip} set -e; for f in `ls $(filter %.cc %.cpp,$(GENFILES)) $(addsuffix .cc,$(basename $(OBJS))) $(addsuffix .cpp,$(basename $(OBJS))) 2> /dev/null`; do \ - echo "Analyse: $$f" >&2; cpp -std=gnu++0x -MM -I. -D_YOSYS_ $$f; done | sed 's,.*:,,; s,//*,/,g; s,/[^/]*/\.\./,/,g; y, \\,\n\n,;' | grep '^[^/]' | sort -u | grep -v kernel/version_ > srcfiles.txt + echo "Analyse: $$f" >&2; cpp -std=c++11 -MM -I. -D_YOSYS_ $$f; done | sed 's,.*:,,; s,//*,/,g; s,/[^/]*/\.\./,/,g; y, \\,\n\n,;' | grep '^[^/]' | sort -u | grep -v kernel/version_ > srcfiles.txt bash misc/create_vcxsrc.sh yosys-win32-vcxsrc $(YOSYS_VER) $(GIT_REV) echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"Yosys (Version Information Unavailable)\"; }" > kernel/version.cc zip yosys-win32-vcxsrc-$(YOSYS_VER)/genfiles.zip $(GENFILES) kernel/version.cc @@ -485,8 +512,8 @@ config-clang: clean config-gcc: clean echo 'CONFIG := gcc' > Makefile.conf -config-gcc-4.6: clean - echo 'CONFIG := gcc-4.6' > Makefile.conf +config-gcc-4.8: clean + echo 'CONFIG := gcc-4.8' > Makefile.conf config-emcc: clean echo 'CONFIG := emcc' > Makefile.conf @@ -501,6 +528,9 @@ config-mxe: clean echo 'ENABLE_PLUGINS := 0' >> Makefile.conf echo 'ENABLE_READLINE := 0' >> Makefile.conf +config-msys2: clean + echo 'CONFIG := msys2' > Makefile.conf + config-gprof: clean echo 'CONFIG := gcc' > Makefile.conf echo 'ENABLE_GPROF := 1' >> Makefile.conf @@ -522,5 +552,5 @@ echo-git-rev: -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.6 config-gprof config-sudo +.PHONY: config-clean config-clang config-gcc config-gcc-4.8 config-gprof config-sudo @@ -3,7 +3,7 @@ | | | yosys -- Yosys Open SYnthesis Suite | | | - | Copyright (C) 2012 - 2015 Clifford Wolf <clifford@clifford.at> | + | Copyright (C) 2012 - 2016 Clifford Wolf <clifford@clifford.at> | | | | Permission to use, copy, modify, and/or distribute this software for any | | purpose with or without fee is hereby granted, provided that the above | @@ -52,12 +52,12 @@ You need a C++ compiler with C++11 support (up-to-date CLANG or GCC is recommended) and some standard tools such as GNU Flex, GNU Bison, and GNU Make. TCL, readline and libffi are optional (see ENABLE_* settings in Makefile). Xdot (graphviz) is used by the "show" command in yosys to display schematics. -For example on Ubuntu Linux 14.04 LTS the following commands will install all +For example on Ubuntu Linux 16.04 LTS the following commands will install all prerequisites for building yosys: - $ yosys_deps="build-essential clang bison flex libreadline-dev gawk - tcl-dev libffi-dev git mercurial graphviz xdot pkg-config python3" - $ sudo apt-get install $yosys_deps + $ sudo apt-get install build-essential clang bison flex \ + libreadline-dev gawk tcl-dev libffi-dev git mercurial \ + graphviz xdot pkg-config python3 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 @@ -308,6 +308,10 @@ Verilog Attributes and non-standard features for everything that comes after the {* ... *} statement. (Reset by adding an empty {* *} statement.) +- In module parameter and port declarations, and cell port and parameter + lists, a trailing comma is ignored. This simplifies writing verilog code + generators a bit in some cases. + - Modules can be declared with "module mod_name(...);" (with three dots instead of a list of module ports). With this syntax it is sufficient to simply declare a module port as 'input' or 'output' in the module @@ -350,8 +354,8 @@ Verilog Attributes and non-standard features endmodule - A limited subset of DPI-C functions is supported. The plugin mechanism - (see "help plugin") can be used load .so files with implementations of - DPI-C routines. As a non-standard extension it is possible to specify + (see "help plugin") can be used to load .so files with implementations + of DPI-C routines. As a non-standard extension it is possible to specify a plugin alias using the "<alias>:" syntax. for example: module dpitest; @@ -366,7 +370,7 @@ Verilog Attributes and non-standard features must be put in parentheses. Examples: WIDTH'd42, (4+2)'b101010 - The system tasks $finish and $display are supported in initial blocks - in and unconditional context (only if/case statements on parameters + in an unconditional context (only if/case statements on parameters and constant values). The intended use for this is synthesis-time DRC. @@ -380,6 +384,47 @@ from SystemVerilog: form. In module context: "assert property (<expression>);" and within an always block: "assert(<expression>);". It is transformed to a $assert cell. +- The "assume" statements from SystemVerilog are also supported. The same + limitations as with the "assert" statement apply. + - The keywords "always_comb", "always_ff" and "always_latch", "logic" and "bit" are supported. +- SystemVerilog packages are supported. Once a SystemVerilog file is read + into a design with "read_verilog", all its packages are available to + SystemVerilog files being read into the same design afterwards. + + +Building the documentation +========================== + +Note that there is no need to build the manual if you just want to read it. +Simply download the PDF from http://www.clifford.at/yosys/documentation.html +instead. + +On Ubuntu, texlive needs these packages to be able to build the manual: + + sudo apt-get install texlive-binaries + sudo apt-get install texlive-science # install algorithm2e.sty + sudo apt-get install texlive-bibtex-extra # gets multibib.sty + sudo apt-get install texlive-fonts-extra # gets skull.sty and dsfont.sty + sudo apt-get install texlive-publishers # IEEEtran.cls + +Also the non-free font luximono should be installed, there is unfortunately +no Ubuntu package for this so it should be installed separately using +`getnonfreefonts`: + + wget https://tug.org/fonts/getnonfreefonts/install-getnonfreefonts + sudo texlua install-getnonfreefonts # will install to /usr/local by default, can be changed by editing BINDIR at MANDIR at the top of the script + getnonfreefonts luximono # installs to /home/user/texmf + +Then execute, from the root of the repository: + + make manual + +Notes: + +- 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`. + diff --git a/backends/blif/blif.cc b/backends/blif/blif.cc index f3b57765..6a379e67 100644 --- a/backends/blif/blif.cc +++ b/backends/blif/blif.cc @@ -41,13 +41,14 @@ struct BlifDumperConfig bool param_mode; bool attr_mode; bool blackbox_mode; + bool noalias_mode; std::string buf_type, buf_in, buf_out; std::map<RTLIL::IdString, std::pair<RTLIL::IdString, RTLIL::IdString>> unbuf_types; std::string true_type, true_out, false_type, false_out, undef_type, undef_out; BlifDumperConfig() : icells_mode(false), conn_mode(false), impltf_mode(false), gates_mode(false), - cname_mode(false), param_mode(false), attr_mode(false), blackbox_mode(false) { } + cname_mode(false), param_mode(false), attr_mode(false), blackbox_mode(false), noalias_mode(false) { } }; struct BlifDumper @@ -86,12 +87,13 @@ struct BlifDumper } vector<shared_str> cstr_buf; + pool<SigBit> cstr_bits_seen; const char *cstr(RTLIL::IdString id) { std::string str = RTLIL::unescape_id(id); for (size_t i = 0; i < str.size(); i++) - if (str[i] == '#' || str[i] == '=') + if (str[i] == '#' || str[i] == '=' || str[i] == '<' || str[i] == '>') str[i] = '?'; cstr_buf.push_back(str); return cstr_buf.back().c_str(); @@ -99,15 +101,17 @@ struct BlifDumper const char *cstr(RTLIL::SigBit sig) { + cstr_bits_seen.insert(sig); + if (sig.wire == NULL) { - if (sig == RTLIL::State::S0) return config->false_type == "-" ? config->false_out.c_str() : "$false"; - if (sig == RTLIL::State::S1) return config->true_type == "-" ? config->true_out.c_str() : "$true"; - return config->undef_type == "-" ? config->undef_out.c_str() : "$undef"; + if (sig == RTLIL::State::S0) return config->false_type == "-" || config->false_type == "+" ? config->false_out.c_str() : "$false"; + if (sig == RTLIL::State::S1) return config->true_type == "-" || config->true_type == "+" ? config->true_out.c_str() : "$true"; + return config->undef_type == "-" || config->undef_type == "+" ? config->undef_out.c_str() : "$undef"; } std::string str = RTLIL::unescape_id(sig.wire->name); for (size_t i = 0; i < str.size(); i++) - if (str[i] == '#' || str[i] == '=') + if (str[i] == '#' || str[i] == '=' || str[i] == '<' || str[i] == '>') str[i] = '?'; if (sig.wire->width != 1) @@ -200,19 +204,25 @@ struct BlifDumper if (!config->impltf_mode) { if (!config->false_type.empty()) { - if (config->false_type != "-") + if (config->false_type == "+") + f << stringf(".names %s\n", config->false_out.c_str()); + else if (config->false_type != "-") f << stringf(".%s %s %s=$false\n", subckt_or_gate(config->false_type), config->false_type.c_str(), config->false_out.c_str()); } else f << stringf(".names $false\n"); if (!config->true_type.empty()) { - if (config->true_type != "-") + if (config->true_type == "+") + f << stringf(".names %s\n1\n", config->true_out.c_str()); + else if (config->true_type != "-") f << stringf(".%s %s %s=$true\n", subckt_or_gate(config->true_type), config->true_type.c_str(), config->true_out.c_str()); } else f << stringf(".names $true\n1\n"); if (!config->undef_type.empty()) { - if (config->undef_type != "-") + if (config->undef_type == "+") + f << stringf(".names %s\n", config->undef_out.c_str()); + else if (config->undef_type != "-") f << stringf(".%s %s %s=$undef\n", subckt_or_gate(config->undef_type), config->undef_type.c_str(), config->undef_out.c_str()); } else @@ -317,14 +327,25 @@ struct BlifDumper continue; } + if (!config->icells_mode && cell->type == "$_DLATCH_N_") { + f << stringf(".latch %s %s al %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")), + cstr(cell->getPort("\\E")), cstr_init(cell->getPort("\\Q"))); + continue; + } + + if (!config->icells_mode && cell->type == "$_DLATCH_P_") { + f << stringf(".latch %s %s ah %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")), + cstr(cell->getPort("\\E")), cstr_init(cell->getPort("\\Q"))); + continue; + } + if (!config->icells_mode && cell->type == "$lut") { f << stringf(".names"); auto &inputs = cell->getPort("\\A"); auto width = cell->parameters.at("\\WIDTH").as_int(); log_assert(inputs.size() == width); - for (int i = width-1; i >= 0; i--) { + for (int i = width-1; i >= 0; i--) f << stringf(" %s", cstr(inputs.extract(i, 1))); - } auto &output = cell->getPort("\\Y"); log_assert(output.size() == 1); f << stringf(" %s", cstr(output)); @@ -340,6 +361,34 @@ struct BlifDumper continue; } + if (!config->icells_mode && cell->type == "$sop") { + f << stringf(".names"); + auto &inputs = cell->getPort("\\A"); + auto width = cell->parameters.at("\\WIDTH").as_int(); + auto depth = cell->parameters.at("\\DEPTH").as_int(); + vector<State> table = cell->parameters.at("\\TABLE").bits; + while (GetSize(table) < 2*width*depth) + table.push_back(State::S0); + log_assert(inputs.size() == width); + for (int i = 0; i < width; i++) + f << stringf(" %s", cstr(inputs.extract(i, 1))); + auto &output = cell->getPort("\\Y"); + log_assert(output.size() == 1); + f << stringf(" %s", cstr(output)); + f << stringf("\n"); + for (int i = 0; i < depth; i++) { + for (int j = 0; j < width; j++) { + bool pat0 = table.at(2*width*i + 2*j + 0) == State::S1; + bool pat1 = table.at(2*width*i + 2*j + 1) == State::S1; + if (pat0 && !pat1) f << "0"; + else if (!pat0 && pat1) f << "1"; + else f << "-"; + } + f << " 1\n"; + } + continue; + } + f << stringf(".%s %s", subckt_or_gate(cell->type.str()), cstr(cell->type)); for (auto &conn : cell->connections()) for (int i = 0; i < conn.second.size(); i++) { @@ -361,14 +410,21 @@ struct BlifDumper for (auto &conn : module->connections()) for (int i = 0; i < conn.first.size(); i++) + { + SigBit lhs_bit = conn.first[i]; + SigBit rhs_bit = conn.second[i]; + + if (config->noalias_mode && cstr_bits_seen.count(lhs_bit) == 0) + continue; + if (config->conn_mode) - f << stringf(".conn %s %s\n", cstr(conn.second.extract(i, 1)), cstr(conn.first.extract(i, 1))); + f << stringf(".conn %s %s\n", cstr(rhs_bit), cstr(lhs_bit)); else if (!config->buf_type.empty()) - f << stringf(".%s %s %s=%s %s=%s\n", subckt_or_gate(config->buf_type), config->buf_type.c_str(), config->buf_in.c_str(), cstr(conn.second.extract(i, 1)), - config->buf_out.c_str(), cstr(conn.first.extract(i, 1))); + f << stringf(".%s %s %s=%s %s=%s\n", subckt_or_gate(config->buf_type), config->buf_type.c_str(), + config->buf_in.c_str(), cstr(rhs_bit), config->buf_out.c_str(), cstr(lhs_bit)); else - f << stringf(".names %s %s\n1 1\n", cstr(conn.second.extract(i, 1)), cstr(conn.first.extract(i, 1))); - + f << stringf(".names %s %s\n1 1\n", cstr(rhs_bit), cstr(lhs_bit)); + } f << stringf(".end\n"); } @@ -406,7 +462,14 @@ struct BlifBackend : public Backend { log(" use the specified cell types to drive nets that are constant 1, 0, or\n"); log(" undefined. when '-' is used as <cell-type>, then <out-port> specifies\n"); log(" the wire name to be used for the constant signal and no cell driving\n"); - log(" that wire is generated.\n"); + log(" that wire is generated. when '+' is used as <cell-type>, then <out-port>\n"); + log(" specifies the wire name to be used for the constant signal and a .names\n"); + log(" statement is generated to drive the wire.\n"); + log("\n"); + log(" -noalias\n"); + log(" if a net name is aliasing another net name, then by default a net\n"); + log(" without fanout is created that is driven by the other net. This option\n"); + log(" suppresses the generation of this nets without fanout.\n"); log("\n"); log("The following options can be useful when the generated file is not going to be\n"); log("read by a BLIF parser but a custom tool. It is recommended to not name the output\n"); @@ -448,7 +511,7 @@ struct BlifBackend : public Backend { std::string false_type, false_out; BlifDumperConfig config; - log_header("Executing BLIF backend.\n"); + log_header(design, "Executing BLIF backend.\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -517,6 +580,10 @@ struct BlifBackend : public Backend { config.impltf_mode = true; continue; } + if (args[argidx] == "-noalias") { + config.noalias_mode = true; + continue; + } break; } extra_args(f, filename, args, argidx); @@ -540,7 +607,7 @@ struct BlifBackend : public Backend { if (module->processes.size() != 0) log_error("Found unmapped processes in module %s: unmapped processes are not supported in BLIF backend!\n", RTLIL::id2cstr(module->name)); if (module->memories.size() != 0) - log_error("Found munmapped emories in module %s: unmapped memories are not supported in BLIF backend!\n", RTLIL::id2cstr(module->name)); + log_error("Found unmapped memories in module %s: unmapped memories are not supported in BLIF backend!\n", RTLIL::id2cstr(module->name)); if (module->name == RTLIL::escape_id(top_module_name)) { BlifDumper::dump(*f, module, design, config); diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index 465723f1..bbe90e85 100644 --- a/backends/btor/btor.cc +++ b/backends/btor/btor.cc @@ -1065,7 +1065,7 @@ struct BtorBackend : public Backend { std::string false_type, false_out; BtorDumperConfig config; - log_header("Executing BTOR backend.\n"); + log_header(design, "Executing BTOR backend.\n"); size_t argidx=1; extra_args(f, filename, args, argidx); diff --git a/backends/btor/verilog2btor.sh b/backends/btor/verilog2btor.sh index 1c537d5b..dfd7f1a8 100755 --- a/backends/btor/verilog2btor.sh +++ b/backends/btor/verilog2btor.sh @@ -22,7 +22,7 @@ hierarchy -top $3; hierarchy -libdir $DIR; hierarchy -check; proc; -opt; opt_const -mux_undef; opt; +opt; opt_expr -mux_undef; opt; rename -hide;;; #techmap -map +/pmux2mux.v;; splice; opt; diff --git a/backends/edif/edif.cc b/backends/edif/edif.cc index 475e43da..d16f1831 100644 --- a/backends/edif/edif.cc +++ b/backends/edif/edif.cc @@ -100,6 +100,11 @@ struct EdifBackend : public Backend { log(" -top top_module\n"); log(" set the specified module as design top module\n"); log("\n"); + log(" -nogndvcc\n"); + log(" do not create \"GND\" and \"VCC\" cells. (this will produce an error\n"); + log(" if the design contains constant nets. use \"hilomap\" to map to custom\n"); + log(" constant drivers first)\n"); + log("\n"); log("Unfortunately there are different \"flavors\" of the EDIF file format. This\n"); log("command generates EDIF files for the Xilinx place&route tools. It might be\n"); log("necessary to make small modifications to this command when a different tool\n"); @@ -108,10 +113,11 @@ struct EdifBackend : public Backend { } virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing EDIF backend.\n"); + log_header(design, "Executing EDIF backend.\n"); std::string top_module_name; std::map<RTLIL::IdString, std::map<RTLIL::IdString, int>> lib_cell_ports; + bool nogndvcc = false; CellTypes ct(design); EdifNames edif_names; @@ -122,6 +128,10 @@ struct EdifBackend : public Backend { top_module_name = args[++argidx]; continue; } + if (args[argidx] == "-nogndvcc") { + nogndvcc = true; + continue; + } break; } extra_args(f, filename, args, argidx); @@ -143,7 +153,7 @@ struct EdifBackend : public Backend { if (module->processes.size() != 0) log_error("Found unmapped processes in module %s: unmapped processes are not supported in EDIF backend!\n", RTLIL::id2cstr(module->name)); if (module->memories.size() != 0) - log_error("Found munmapped emories in module %s: unmapped memories are not supported in EDIF backend!\n", RTLIL::id2cstr(module->name)); + log_error("Found unmapped memories in module %s: unmapped memories are not supported in EDIF backend!\n", RTLIL::id2cstr(module->name)); for (auto cell_it : module->cells_) { @@ -169,21 +179,24 @@ struct EdifBackend : public Backend { *f << stringf(" (edifLevel 0)\n"); *f << stringf(" (technology (numberDefinition))\n"); - *f << stringf(" (cell GND\n"); - *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(" )\n"); - *f << stringf(" )\n"); - - *f << stringf(" (cell VCC\n"); - *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(" )\n"); - *f << stringf(" )\n"); + if (!nogndvcc) + { + *f << stringf(" (cell GND\n"); + *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(" )\n"); + *f << stringf(" )\n"); + + *f << stringf(" (cell VCC\n"); + *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(" )\n"); + *f << stringf(" )\n"); + } for (auto &cell_it : lib_cell_ports) { *f << stringf(" (cell %s\n", EDIF_DEF(cell_it.first)); @@ -279,8 +292,10 @@ struct EdifBackend : public Backend { } *f << stringf(" )\n"); *f << stringf(" (contents\n"); - *f << stringf(" (instance GND (viewRef VIEW_NETLIST (cellRef GND (libraryRef LIB))))\n"); - *f << stringf(" (instance VCC (viewRef VIEW_NETLIST (cellRef VCC (libraryRef LIB))))\n"); + if (!nogndvcc) { + *f << stringf(" (instance GND (viewRef VIEW_NETLIST (cellRef GND (libraryRef LIB))))\n"); + *f << stringf(" (instance VCC (viewRef VIEW_NETLIST (cellRef VCC (libraryRef LIB))))\n"); + } for (auto &cell_it : module->cells_) { RTLIL::Cell *cell = cell_it.second; *f << stringf(" (instance %s\n", EDIF_DEF(cell->name)); @@ -326,6 +341,8 @@ struct EdifBackend : public Backend { for (auto &ref : it.second) *f << stringf(" %s\n", ref.c_str()); if (sig.wire == NULL) { + 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"); if (sig == RTLIL::State::S1) diff --git a/backends/ilang/ilang_backend.cc b/backends/ilang/ilang_backend.cc index adabf05e..03e29c52 100644 --- a/backends/ilang/ilang_backend.cc +++ b/backends/ilang/ilang_backend.cc @@ -391,7 +391,7 @@ struct IlangBackend : public Backend { { bool selected = false; - log_header("Executing ILANG backend.\n"); + log_header(design, "Executing ILANG backend.\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { diff --git a/backends/intersynth/intersynth.cc b/backends/intersynth/intersynth.cc index 72a70e38..34cb52fb 100644 --- a/backends/intersynth/intersynth.cc +++ b/backends/intersynth/intersynth.cc @@ -73,7 +73,7 @@ struct IntersynthBackend : public Backend { } virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing INTERSYNTH backend.\n"); + log_header(design, "Executing INTERSYNTH backend.\n"); log_push(); std::vector<std::string> libfiles; @@ -113,7 +113,7 @@ struct IntersynthBackend : public Backend { } if (libs.size() > 0) - log_header("Continuing INTERSYNTH backend.\n"); + log_header(design, "Continuing INTERSYNTH backend.\n"); std::set<std::string> conntypes_code, celltypes_code; std::string netlists_code; diff --git a/backends/json/json.cc b/backends/json/json.cc index 9bc936a6..4baffa33 100644 --- a/backends/json/json.cc +++ b/backends/json/json.cc @@ -83,12 +83,12 @@ struct JsonWriter return str + " ]"; } - void write_parameters(const dict<IdString, Const> ¶meters) + void write_parameters(const dict<IdString, Const> ¶meters, bool for_module=false) { bool first = true; for (auto ¶m : parameters) { f << stringf("%s\n", first ? "" : ","); - f << stringf(" %s: ", get_name(param.first).c_str()); + f << stringf(" %s%s: ", for_module ? "" : " ", get_name(param.first).c_str()); if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0) f << get_string(param.second.decode_string()); else if (GetSize(param.second.bits) > 32) @@ -111,6 +111,10 @@ struct JsonWriter f << stringf(" %s: {\n", get_name(module->name).c_str()); + f << stringf(" \"attributes\": {"); + write_parameters(module->attributes, /*for_module=*/true); + f << stringf("\n },\n"); + f << stringf(" \"ports\": {"); bool first = true; for (auto n : module->ports) { @@ -411,10 +415,10 @@ struct JsonBackend : public Backend { log(" - the inverted value of the specified input port bit\n"); log("\n"); log(" [ \"and\", <node-index>, <node-index>, <out-list> ]\n"); - log(" - the ANDed value of the speciefied nodes\n"); + log(" - the ANDed value of the specified nodes\n"); log("\n"); log(" [ \"nand\", <node-index>, <node-index>, <out-list> ]\n"); - log(" - the inverted ANDed value of the speciefied nodes\n"); + log(" - the inverted ANDed value of the specified nodes\n"); log("\n"); log(" [ \"true\", <out-list> ]\n"); log(" - the constant value 1\n"); @@ -445,7 +449,7 @@ struct JsonBackend : public Backend { log(" ]\n"); log("\n"); log("Future version of Yosys might add support for additional fields in the JSON\n"); - log("format. A program processing this format must ignore all unkown fields.\n"); + 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) @@ -463,7 +467,7 @@ struct JsonBackend : public Backend { } extra_args(f, filename, args, argidx); - log_header("Executing JSON backend.\n"); + log_header(design, "Executing JSON backend.\n"); JsonWriter json_writer(*f, false, aig_mode); json_writer.write_design(design); diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc index c852921e..9a25f3a2 100644 --- a/backends/smt2/smt2.cc +++ b/backends/smt2/smt2.cc @@ -32,23 +32,43 @@ struct Smt2Worker CellTypes ct; SigMap sigmap; RTLIL::Module *module; - bool bvmode, memmode, regsmode, wiresmode, verbose; + bool bvmode, memmode, wiresmode, verbose; int idcounter; - std::vector<std::string> decls, trans; + std::vector<std::string> decls, trans, hier; std::map<RTLIL::SigBit, RTLIL::Cell*> bit_driver; - std::set<RTLIL::Cell*> exported_cells; + std::set<RTLIL::Cell*> exported_cells, hiercells, hiercells_queue; pool<Cell*> recursive_cells, registers; std::map<RTLIL::SigBit, std::pair<int, int>> fcache; std::map<Cell*, int> memarrays; std::map<int, int> bvsizes; + dict<IdString, char*> ids; - Smt2Worker(RTLIL::Module *module, bool bvmode, bool memmode, bool regsmode, bool wiresmode, bool verbose) : + const char *get_id(IdString n) + { + if (ids.count(n) == 0) { + std::string str = log_id(n); + for (int i = 0; i < GetSize(str); i++) { + if (str[i] == '\\') + str[i] = '/'; + } + ids[n] = strdup(str.c_str()); + } + return ids[n]; + } + + template<typename T> + const char *get_id(T *obj) { + return get_id(obj->name); + } + + Smt2Worker(RTLIL::Module *module, bool bvmode, bool memmode, bool wiresmode, bool verbose) : ct(module->design), sigmap(module), module(module), bvmode(bvmode), memmode(memmode), - regsmode(regsmode), wiresmode(wiresmode), verbose(verbose), idcounter(0) + wiresmode(wiresmode), verbose(verbose), idcounter(0) { - decls.push_back(stringf("(declare-sort |%s_s| 0)\n", log_id(module))); + decls.push_back(stringf("(declare-sort |%s_s| 0)\n", get_id(module))); + decls.push_back(stringf("(declare-fun |%s_is| (|%s_s|) Bool)\n", get_id(module), get_id(module))); for (auto cell : module->cells()) for (auto &conn : cell->connections()) { @@ -66,6 +86,28 @@ struct Smt2Worker } } + ~Smt2Worker() + { + for (auto &it : ids) + free(it.second); + ids.clear(); + } + + const char *get_id(Module *m) + { + return get_id(m->name); + } + + const char *get_id(Cell *c) + { + return get_id(c->name); + } + + const char *get_id(Wire *w) + { + return get_id(w->name); + } + void register_bool(RTLIL::SigBit bit, int id) { if (verbose) log("%*s-> register_bool: %s %d\n", 2+2*GetSize(recursive_cells), "", @@ -121,14 +163,14 @@ struct Smt2Worker if (verbose) log("%*s-> external bool: %s\n", 2+2*GetSize(recursive_cells), "", log_signal(bit)); decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) Bool) ; %s\n", - log_id(module), idcounter, log_id(module), log_signal(bit))); + get_id(module), idcounter, get_id(module), log_signal(bit))); register_bool(bit, idcounter++); } auto f = fcache.at(bit); if (f.second >= 0) - return stringf("(= ((_ extract %d %d) (|%s#%d| %s)) #b1)", f.second, f.second, log_id(module), f.first, state_name); - return stringf("(|%s#%d| %s)", log_id(module), f.first, state_name); + return stringf("(= ((_ extract %d %d) (|%s#%d| %s)) #b1)", f.second, f.second, get_id(module), f.first, state_name); + return stringf("(|%s#%d| %s)", get_id(module), f.first, state_name); } std::string get_bool(RTLIL::SigSpec sig, const char *state_name = "state") @@ -180,10 +222,10 @@ struct Smt2Worker j++; } if (t1.second == 0 && j == bvsizes.at(t1.first)) - subexpr.push_back(stringf("(|%s#%d| %s)", log_id(module), t1.first, state_name)); + subexpr.push_back(stringf("(|%s#%d| %s)", get_id(module), t1.first, state_name)); else subexpr.push_back(stringf("((_ extract %d %d) (|%s#%d| %s))", - t1.second + j - 1, t1.second, log_id(module), t1.first, state_name)); + t1.second + j - 1, t1.second, get_id(module), t1.first, state_name)); continue; } @@ -196,8 +238,8 @@ struct Smt2Worker for (auto bit : sig.extract(i, j)) log_assert(bit_driver.count(bit) == 0); decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) (_ BitVec %d)) ; %s\n", - log_id(module), idcounter, log_id(module), j, log_signal(sig.extract(i, j)))); - subexpr.push_back(stringf("(|%s#%d| %s)", log_id(module), idcounter, state_name)); + get_id(module), idcounter, get_id(module), j, log_signal(sig.extract(i, j)))); + subexpr.push_back(stringf("(|%s#%d| %s)", get_id(module), idcounter, state_name)); register_bv(sig.extract(i, j), idcounter++); } @@ -228,10 +270,11 @@ struct Smt2Worker else processed_expr += ch; } - if (verbose) log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", - log_id(cell)); + if (verbose) + log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", log_id(cell)); + decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n", - log_id(module), idcounter, log_id(module), processed_expr.c_str(), log_signal(bit))); + get_id(module), idcounter, get_id(module), processed_expr.c_str(), log_signal(bit))); register_bool(bit, idcounter++); recursive_cells.erase(cell); } @@ -271,16 +314,16 @@ struct Smt2Worker if (width != GetSize(sig_y) && type != 'b') processed_expr = stringf("((_ extract %d 0) %s)", GetSize(sig_y)-1, processed_expr.c_str()); - if (verbose) log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", - log_id(cell)); + if (verbose) + log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", log_id(cell)); if (type == 'b') { decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n", - log_id(module), idcounter, log_id(module), processed_expr.c_str(), log_signal(sig_y))); + get_id(module), idcounter, get_id(module), processed_expr.c_str(), log_signal(sig_y))); register_boolvec(sig_y, idcounter++); } else { decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n", - log_id(module), idcounter, log_id(module), GetSize(sig_y), processed_expr.c_str(), log_signal(sig_y))); + get_id(module), idcounter, get_id(module), GetSize(sig_y), processed_expr.c_str(), log_signal(sig_y))); register_bv(sig_y, idcounter++); } @@ -302,21 +345,23 @@ struct Smt2Worker } else processed_expr += ch; - if (verbose) log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", - log_id(cell)); + if (verbose) + log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", log_id(cell)); + decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n", - log_id(module), idcounter, log_id(module), processed_expr.c_str(), log_signal(sig_y))); + get_id(module), idcounter, get_id(module), processed_expr.c_str(), log_signal(sig_y))); register_boolvec(sig_y, idcounter++); recursive_cells.erase(cell); } void export_cell(RTLIL::Cell *cell) { - if (verbose) log("%*s=> export_cell %s (%s) [%s]\n", 2+2*GetSize(recursive_cells), "", - log_id(cell), log_id(cell->type), exported_cells.count(cell) ? "old" : "new"); + if (verbose) + log("%*s=> export_cell %s (%s) [%s]\n", 2+2*GetSize(recursive_cells), "", + log_id(cell), log_id(cell->type), exported_cells.count(cell) ? "old" : "new"); if (recursive_cells.count(cell)) - log_error("Found logic loop in module %s! See cell %s.\n", log_id(module), log_id(cell)); + log_error("Found logic loop in module %s! See cell %s.\n", get_id(module), get_id(cell)); if (exported_cells.count(cell)) return; @@ -324,11 +369,21 @@ struct Smt2Worker exported_cells.insert(cell); recursive_cells.insert(cell); + if (cell->type == "$initstate") + { + SigBit bit = sigmap(cell->getPort("\\Y").as_bit()); + decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool (|%s_is| state)) ; %s\n", + get_id(module), idcounter, get_id(module), get_id(module), log_signal(bit))); + register_bool(bit, idcounter++); + recursive_cells.erase(cell); + return; + } + if (cell->type == "$_DFF_P_" || cell->type == "$_DFF_N_") { registers.insert(cell); decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) Bool) ; %s\n", - log_id(module), idcounter, log_id(module), log_signal(cell->getPort("\\Q")))); + get_id(module), idcounter, get_id(module), log_signal(cell->getPort("\\Q")))); register_bool(cell->getPort("\\Q"), idcounter++); recursive_cells.erase(cell); return; @@ -356,12 +411,24 @@ struct Smt2Worker { registers.insert(cell); decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) (_ BitVec %d)) ; %s\n", - log_id(module), idcounter, log_id(module), GetSize(cell->getPort("\\Q")), log_signal(cell->getPort("\\Q")))); + get_id(module), idcounter, get_id(module), GetSize(cell->getPort("\\Q")), log_signal(cell->getPort("\\Q")))); register_bv(cell->getPort("\\Q"), idcounter++); recursive_cells.erase(cell); return; } + if (cell->type == "$anyconst") + { + registers.insert(cell); + decls.push_back(stringf("; yosys-smt2-%s %s#%d %s\n", cell->type.c_str() + 1, get_id(module), idcounter, + cell->attributes.count("\\src") ? cell->attributes.at("\\src").decode_string().c_str() : get_id(cell))); + decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) (_ BitVec %d)) ; %s\n", + get_id(module), idcounter, get_id(module), GetSize(cell->getPort("\\Y")), log_signal(cell->getPort("\\Y")))); + register_bv(cell->getPort("\\Y"), idcounter++); + recursive_cells.erase(cell); + return; + } + if (cell->type == "$and") return export_bvop(cell, "(bvand A B)"); if (cell->type == "$or") return export_bvop(cell, "(bvor A B)"); if (cell->type == "$xor") return export_bvop(cell, "(bvxor A B)"); @@ -372,7 +439,13 @@ struct Smt2Worker if (cell->type == "$sshl") return export_bvop(cell, "(bvshl A B)", 's'); if (cell->type == "$sshr") return export_bvop(cell, "(bvLshr A B)", 's'); - // FIXME: $shift $shiftx + if (cell->type.in("$shift", "$shiftx")) { + if (cell->getParam("\\B_SIGNED").as_bool()) { + /* FIXME */ + } else { + return export_bvop(cell, "(bvlshr A B)", 's'); + } + } if (cell->type == "$lt") return export_bvop(cell, "(bvUlt A B)", 'b'); if (cell->type == "$le") return export_bvop(cell, "(bvUle A B)", 'b'); @@ -418,11 +491,12 @@ struct Smt2Worker processed_expr = stringf("(ite %s %s %s)", get_bool(sig_s[i]).c_str(), get_bv(sig_b.extract(i*width, width)).c_str(), processed_expr.c_str()); - if (verbose) log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", - log_id(cell)); + if (verbose) + log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", log_id(cell)); + RTLIL::SigSpec sig = sigmap(cell->getPort("\\Y")); decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n", - log_id(module), idcounter, log_id(module), width, processed_expr.c_str(), log_signal(sig))); + get_id(module), idcounter, get_id(module), width, processed_expr.c_str(), log_signal(sig))); register_bv(sig, idcounter++); recursive_cells.erase(cell); return; @@ -441,22 +515,27 @@ struct Smt2Worker int rd_ports = cell->getParam("\\RD_PORTS").as_int(); decls.push_back(stringf("(declare-fun |%s#%d#0| (|%s_s|) (Array (_ BitVec %d) (_ BitVec %d))) ; %s\n", - log_id(module), arrayid, log_id(module), abits, width, log_id(cell))); + get_id(module), arrayid, get_id(module), abits, width, get_id(cell))); + decls.push_back(stringf("; yosys-smt2-memory %s %d %d %d\n", get_id(cell), abits, width, rd_ports)); decls.push_back(stringf("(define-fun |%s_m %s| ((state |%s_s|)) (Array (_ BitVec %d) (_ BitVec %d)) (|%s#%d#0| state))\n", - log_id(module), log_id(cell), log_id(module), abits, width, log_id(module), arrayid)); + get_id(module), get_id(cell), get_id(module), abits, width, get_id(module), arrayid)); for (int i = 0; i < rd_ports; i++) { - std::string addr = get_bv(cell->getPort("\\RD_ADDR").extract(abits*i, abits)); + SigSpec addr_sig = cell->getPort("\\RD_ADDR").extract(abits*i, abits); SigSpec data_sig = cell->getPort("\\RD_DATA").extract(width*i, width); + std::string addr = get_bv(addr_sig); if (cell->getParam("\\RD_CLK_ENABLE").extract(i).as_bool()) log_error("Read port %d (%s) of memory %s.%s is clocked. This is not supported by \"write_smt2\"! " "Call \"memory\" with -nordff to avoid this error.\n", i, log_signal(data_sig), log_id(cell), log_id(module)); + decls.push_back(stringf("(define-fun |%s_m:%d %s| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n", + get_id(module), i, get_id(cell), get_id(module), abits, addr.c_str(), log_signal(addr_sig))); + decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d) (select (|%s#%d#0| state) %s)) ; %s\n", - log_id(module), idcounter, log_id(module), width, log_id(module), arrayid, addr.c_str(), log_signal(data_sig))); + get_id(module), idcounter, get_id(module), width, get_id(module), arrayid, addr.c_str(), log_signal(data_sig))); register_bv(data_sig, idcounter++); } @@ -465,6 +544,48 @@ struct Smt2Worker return; } + Module *m = module->design->module(cell->type); + + if (m != nullptr) + { + decls.push_back(stringf("; yosys-smt2-cell %s %s\n", get_id(cell->type), get_id(cell->name))); + string cell_state = stringf("(|%s_h %s| state)", get_id(module), get_id(cell->name)); + + for (auto &conn : cell->connections()) + { + Wire *w = m->wire(conn.first); + SigSpec sig = sigmap(conn.second); + + if (w->port_output && !w->port_input) { + if (GetSize(w) > 1) { + if (bvmode) { + decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) (_ BitVec %d)) ; %s\n", + get_id(module), idcounter, get_id(module), GetSize(w), log_signal(sig))); + register_bv(sig, idcounter++); + } else { + for (int i = 0; i < GetSize(w); i++) { + decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) Bool) ; %s\n", + get_id(module), idcounter, get_id(module), log_signal(sig[i]))); + register_bool(sig[i], idcounter++); + } + } + } else { + decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) Bool) ; %s\n", + get_id(module), idcounter, get_id(module), log_signal(sig))); + register_bool(sig, idcounter++); + } + } + } + + decls.push_back(stringf("(declare-fun |%s_h %s| (|%s_s|) |%s_s|)\n", + get_id(module), get_id(cell->name), get_id(module), get_id(cell->type))); + + hiercells.insert(cell); + hiercells_queue.insert(cell); + recursive_cells.erase(cell); + return; + } + log_error("Unsupported cell type %s for cell %s.%s. (Maybe this cell type would be supported in -bv or -mem mode?)\n", log_id(cell->type), log_id(module), log_id(cell)); } @@ -474,42 +595,39 @@ struct Smt2Worker if (verbose) log("=> export logic driving outputs\n"); pool<SigBit> reg_bits; - if (regsmode) { - for (auto cell : module->cells()) - if (cell->type.in("$_DFF_P_", "$_DFF_N_", "$dff")) { - // not using sigmap -- we want the net directly at the dff output - for (auto bit : cell->getPort("\\Q")) - reg_bits.insert(bit); - } - } + for (auto cell : module->cells()) + if (cell->type.in("$_DFF_P_", "$_DFF_N_", "$dff")) { + // not using sigmap -- we want the net directly at the dff output + for (auto bit : cell->getPort("\\Q")) + reg_bits.insert(bit); + } for (auto wire : module->wires()) { bool is_register = false; - if (regsmode) - for (auto bit : SigSpec(wire)) - if (reg_bits.count(bit)) - is_register = true; + for (auto bit : SigSpec(wire)) + if (reg_bits.count(bit)) + is_register = true; if (wire->port_id || is_register || wire->get_bool_attribute("\\keep") || (wiresmode && wire->name[0] == '\\')) { RTLIL::SigSpec sig = sigmap(wire); if (wire->port_input) - decls.push_back(stringf("; yosys-smt2-input %s %d\n", log_id(wire), wire->width)); + decls.push_back(stringf("; yosys-smt2-input %s %d\n", get_id(wire), wire->width)); if (wire->port_output) - decls.push_back(stringf("; yosys-smt2-output %s %d\n", log_id(wire), wire->width)); + decls.push_back(stringf("; yosys-smt2-output %s %d\n", get_id(wire), wire->width)); if (is_register) - decls.push_back(stringf("; yosys-smt2-register %s %d\n", log_id(wire), wire->width)); + decls.push_back(stringf("; yosys-smt2-register %s %d\n", get_id(wire), wire->width)); if (wire->get_bool_attribute("\\keep") || (wiresmode && wire->name[0] == '\\')) - decls.push_back(stringf("; yosys-smt2-wire %s %d\n", log_id(wire), wire->width)); + decls.push_back(stringf("; yosys-smt2-wire %s %d\n", get_id(wire), wire->width)); if (bvmode && GetSize(sig) > 1) { decls.push_back(stringf("(define-fun |%s_n %s| ((state |%s_s|)) (_ BitVec %d) %s)\n", - log_id(module), log_id(wire), log_id(module), GetSize(sig), get_bv(sig).c_str())); + get_id(module), get_id(wire), get_id(module), GetSize(sig), get_bv(sig).c_str())); } else { for (int i = 0; i < GetSize(sig); i++) if (GetSize(sig) > 1) decls.push_back(stringf("(define-fun |%s_n %s %d| ((state |%s_s|)) Bool %s)\n", - log_id(module), log_id(wire), i, log_id(module), get_bool(sig[i]).c_str())); + get_id(module), get_id(wire), i, get_id(module), get_bool(sig[i]).c_str())); else decls.push_back(stringf("(define-fun |%s_n %s| ((state |%s_s|)) Bool %s)\n", - log_id(module), log_id(wire), log_id(module), get_bool(sig[i]).c_str())); + get_id(module), get_id(wire), get_id(module), get_bool(sig[i]).c_str())); } } } @@ -523,26 +641,28 @@ struct Smt2Worker Const val = wire->attributes.at("\\init"); val.bits.resize(GetSize(sig)); if (bvmode && GetSize(sig) > 1) { - init_list.push_back(stringf("(= %s #b%s) ; %s", get_bv(sig).c_str(), val.as_string().c_str(), log_id(wire))); + init_list.push_back(stringf("(= %s #b%s) ; %s", get_bv(sig).c_str(), val.as_string().c_str(), get_id(wire))); } else { for (int i = 0; i < GetSize(sig); i++) - init_list.push_back(stringf("(= %s %s) ; %s", get_bool(sig[i]).c_str(), val.bits[i] == State::S1 ? "true" : "false", log_id(wire))); + init_list.push_back(stringf("(= %s %s) ; %s", get_bool(sig[i]).c_str(), val.bits[i] == State::S1 ? "true" : "false", get_id(wire))); } } if (verbose) log("=> export logic driving asserts\n"); - vector<int> assert_list, assume_list; + vector<string> assert_list, assume_list; for (auto cell : module->cells()) if (cell->type.in("$assert", "$assume")) { string name_a = get_bool(cell->getPort("\\A")); string name_en = get_bool(cell->getPort("\\EN")); + decls.push_back(stringf("; yosys-smt2-%s %s#%d %s\n", cell->type.c_str() + 1, get_id(module), idcounter, + cell->attributes.count("\\src") ? cell->attributes.at("\\src").decode_string().c_str() : get_id(cell))); decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool (or %s (not %s))) ; %s\n", - log_id(module), idcounter, log_id(module), name_a.c_str(), name_en.c_str(), log_id(cell))); + get_id(module), idcounter, get_id(module), name_a.c_str(), name_en.c_str(), get_id(cell))); if (cell->type == "$assert") - assert_list.push_back(idcounter++); + assert_list.push_back(stringf("(|%s#%d| state)", get_id(module), idcounter++)); else - assume_list.push_back(idcounter++); + assume_list.push_back(stringf("(|%s#%d| state)", get_id(module), idcounter++)); } for (int iter = 1; !registers.empty(); iter++) @@ -558,14 +678,21 @@ struct Smt2Worker { std::string expr_d = get_bool(cell->getPort("\\D")); std::string expr_q = get_bool(cell->getPort("\\Q"), "next_state"); - trans.push_back(stringf(" (= %s %s) ; %s %s\n", expr_d.c_str(), expr_q.c_str(), log_id(cell), log_signal(cell->getPort("\\Q")))); + trans.push_back(stringf(" (= %s %s) ; %s %s\n", expr_d.c_str(), expr_q.c_str(), get_id(cell), log_signal(cell->getPort("\\Q")))); } if (cell->type == "$dff") { std::string expr_d = get_bv(cell->getPort("\\D")); std::string expr_q = get_bv(cell->getPort("\\Q"), "next_state"); - trans.push_back(stringf(" (= %s %s) ; %s %s\n", expr_d.c_str(), expr_q.c_str(), log_id(cell), log_signal(cell->getPort("\\Q")))); + trans.push_back(stringf(" (= %s %s) ; %s %s\n", expr_d.c_str(), expr_q.c_str(), get_id(cell), log_signal(cell->getPort("\\Q")))); + } + + if (cell->type == "$anyconst") + { + std::string expr_d = get_bv(cell->getPort("\\Y")); + std::string expr_q = get_bv(cell->getPort("\\Y"), "next_state"); + trans.push_back(stringf(" (= %s %s) ; %s %s\n", expr_d.c_str(), expr_q.c_str(), get_id(cell), log_signal(cell->getPort("\\Y")))); } if (cell->type == "$mem") @@ -583,56 +710,144 @@ struct Smt2Worker std::string mask = get_bv(cell->getPort("\\WR_EN").extract(width*i, width)); data = stringf("(bvor (bvand %s %s) (bvand (select (|%s#%d#%d| state) %s) (bvnot %s)))", - data.c_str(), mask.c_str(), log_id(module), arrayid, i, addr.c_str(), mask.c_str()); + data.c_str(), mask.c_str(), get_id(module), arrayid, i, addr.c_str(), mask.c_str()); decls.push_back(stringf("(define-fun |%s#%d#%d| ((state |%s_s|)) (Array (_ BitVec %d) (_ BitVec %d)) " "(store (|%s#%d#%d| state) %s %s)) ; %s\n", - log_id(module), arrayid, i+1, log_id(module), abits, width, - log_id(module), arrayid, i, addr.c_str(), data.c_str(), log_id(cell))); + get_id(module), arrayid, i+1, get_id(module), abits, width, + get_id(module), arrayid, i, addr.c_str(), data.c_str(), get_id(cell))); + } + + std::string expr_d = stringf("(|%s#%d#%d| state)", get_id(module), arrayid, wr_ports); + std::string expr_q = stringf("(|%s#%d#0| next_state)", get_id(module), arrayid); + trans.push_back(stringf(" (= %s %s) ; %s\n", expr_d.c_str(), expr_q.c_str(), get_id(cell))); + + Const init_data = cell->getParam("\\INIT"); + int memsize = cell->getParam("\\SIZE").as_int(); + + for (int i = 0; i < memsize; i++) + { + if (i*width >= GetSize(init_data)) + break; + + Const initword = init_data.extract(i*width, width, State::Sx); + bool gen_init_constr = false; + + for (auto bit : initword.bits) + if (bit == State::S0 || bit == State::S1) + gen_init_constr = true; + + if (gen_init_constr) { + init_list.push_back(stringf("(= (select (|%s#%d#0| state) #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)); + } } + } + } + } + + if (verbose) log("=> export logic driving hierarchical cells\n"); - std::string expr_d = stringf("(|%s#%d#%d| state)", log_id(module), arrayid, wr_ports); - std::string expr_q = stringf("(|%s#%d#0| next_state)", log_id(module), arrayid); - trans.push_back(stringf(" (= %s %s) ; %s\n", expr_d.c_str(), expr_q.c_str(), log_id(cell))); + while (!hiercells_queue.empty()) + { + std::set<RTLIL::Cell*> queue; + queue.swap(hiercells_queue); + + for (auto cell : queue) + { + string cell_state = stringf("(|%s_h %s| state)", get_id(module), get_id(cell->name)); + Module *m = module->design->module(cell->type); + log_assert(m != nullptr); + + for (auto &conn : cell->connections()) + { + Wire *w = m->wire(conn.first); + SigSpec sig = sigmap(conn.second); + + if (bvmode || GetSize(w) == 1) { + hier.push_back(stringf(" (= %s (|%s_n %s| %s)) ; %s.%s\n", (GetSize(w) > 1 ? get_bv(sig) : get_bool(sig)).c_str(), + get_id(cell->type), get_id(w), cell_state.c_str(), get_id(cell->type), get_id(w))); + } else { + for (int i = 0; i < GetSize(w); i++) + hier.push_back(stringf(" (= %s (|%s_n %s %d| %s)) ; %s.%s[%d]\n", get_bool(sig[i]).c_str(), + get_id(cell->type), get_id(w), i, cell_state.c_str(), get_id(cell->type), get_id(w), i)); + } } } } + if (verbose) log("=> finalizing SMT2 representation of %s.\n", log_id(module)); + + for (auto c : hiercells) { + assert_list.push_back(stringf("(|%s_a| (|%s_h %s| state))", get_id(c->type), get_id(module), get_id(c->name))); + assume_list.push_back(stringf("(|%s_u| (|%s_h %s| state))", get_id(c->type), get_id(module), get_id(c->name))); + init_list.push_back(stringf("(|%s_i| (|%s_h %s| state))", get_id(c->type), get_id(module), get_id(c->name))); + hier.push_back(stringf(" (|%s_h| (|%s_h %s| state))\n", get_id(c->type), get_id(module), get_id(c->name))); + trans.push_back(stringf(" (|%s_t| (|%s_h %s| state) (|%s_h %s| next_state))\n", + get_id(c->type), get_id(module), get_id(c->name), get_id(module), get_id(c->name))); + } + string assert_expr = assert_list.empty() ? "true" : "(and"; if (!assert_list.empty()) { - for (int i : assert_list) - assert_expr += stringf(" (|%s#%d| state)", log_id(module), i); - assert_expr += ")"; + if (GetSize(assert_list) == 1) { + assert_expr = "\n " + assert_list.front() + "\n"; + } else { + for (auto &str : assert_list) + assert_expr += stringf("\n %s", str.c_str()); + assert_expr += "\n)"; + } } decls.push_back(stringf("(define-fun |%s_a| ((state |%s_s|)) Bool %s)\n", - log_id(module), log_id(module), assert_expr.c_str())); + get_id(module), get_id(module), assert_expr.c_str())); string assume_expr = assume_list.empty() ? "true" : "(and"; if (!assume_list.empty()) { - for (int i : assume_list) - assume_expr += stringf(" (|%s#%d| state)", log_id(module), i); - assume_expr += ")"; + if (GetSize(assume_list) == 1) { + assume_expr = "\n " + assume_list.front() + "\n"; + } else { + for (auto &str : assume_list) + assume_expr += stringf("\n %s", str.c_str()); + assume_expr += "\n)"; + } } decls.push_back(stringf("(define-fun |%s_u| ((state |%s_s|)) Bool %s)\n", - log_id(module), log_id(module), assume_expr.c_str())); + get_id(module), get_id(module), assume_expr.c_str())); string init_expr = init_list.empty() ? "true" : "(and"; if (!init_list.empty()) { - for (auto &str : init_list) - init_expr += stringf("\n\t%s", str.c_str()); - init_expr += "\n)"; + if (GetSize(init_list) == 1) { + init_expr = "\n " + init_list.front() + "\n"; + } else { + for (auto &str : init_list) + init_expr += stringf("\n %s", str.c_str()); + init_expr += "\n)"; + } } decls.push_back(stringf("(define-fun |%s_i| ((state |%s_s|)) Bool %s)\n", - log_id(module), log_id(module), init_expr.c_str())); + get_id(module), get_id(module), init_expr.c_str())); } void write(std::ostream &f) { + f << stringf("; yosys-smt2-module %s\n", get_id(module)); + for (auto it : decls) f << it; - f << stringf("; yosys-smt2-module %s\n", log_id(module)); - f << stringf("(define-fun |%s_t| ((state |%s_s|) (next_state |%s_s|)) Bool ", log_id(module), log_id(module), log_id(module)); + f << stringf("(define-fun |%s_h| ((state |%s_s|)) Bool ", get_id(module), get_id(module)); + if (GetSize(hier) > 1) { + f << "(and\n"; + for (auto it : hier) + f << it; + f << "))\n"; + } else + if (GetSize(hier) == 1) + f << "\n" + hier.front() + ")\n"; + else + f << "true)\n"; + + f << stringf("(define-fun |%s_t| ((state |%s_s|) (next_state |%s_s|)) Bool ", get_id(module), get_id(module), get_id(module)); if (GetSize(trans) > 1) { f << "(and\n"; for (auto it : trans) @@ -643,7 +858,7 @@ struct Smt2Worker f << "\n" + trans.front() + ")"; else f << "true)"; - f << stringf(" ; end of module %s\n", log_id(module)); + f << stringf(" ; end of module %s\n", get_id(module)); } }; @@ -661,10 +876,10 @@ struct Smt2Backend : public Backend { log("\n"); log("The '<mod>_s' sort represents a module state. Additional '<mod>_n' functions\n"); log("are provided that can be used to access the values of the signals in the module.\n"); - log("Only ports, and signals with the 'keep' attribute set are made available via\n"); - log("such functions. Without the -bv option, multi-bit wires are exported as\n"); - log("separate functions of type Bool for the individual bits. With the -bv option\n"); - log("multi-bit wires are exported as single functions of type BitVec.\n"); + log("By default only ports, registers, and wires with the 'keep' attribute set are\n"); + log("made available via such functions. With the -nobv option, multi-bit wires are\n"); + log("exported as separate functions of type Bool for the individual bits. Without\n"); + log("-nobv multi-bit wires are exported as single functions of type BitVec.\n"); log("\n"); log("The '<mod>_t' function evaluates to 'true' when the given pair of states\n"); log("describes a valid state transition.\n"); @@ -676,29 +891,33 @@ struct Smt2Backend : public Backend { log("the assumptions in the module.\n"); log("\n"); log("The '<mod>_i' function evaluates to 'true' when the given state conforms\n"); - log("to the initial state.\n"); + log("to the initial state. Furthermore the '<mod>_is' function should be asserted\n"); + log("to be true for initial states in addition to '<mod>_i', and should be\n"); + log("asserted to be false for non-initial states.\n"); + log("\n"); + log("For hierarchical designs, the '<mod>_h' function must be asserted for each\n"); + log("state to establish the design hierarchy. The '<mod>_h <cellname>' function\n"); + log("evaluates to the state corresponding to the given cell within <mod>.\n"); log("\n"); log(" -verbose\n"); log(" this will print the recursive walk used to export the modules.\n"); log("\n"); - log(" -bv\n"); - log(" enable support for BitVec (FixedSizeBitVectors theory). with this\n"); - log(" option set multi-bit wires are represented using the BitVec sort and\n"); + log(" -nobv\n"); + log(" disable support for BitVec (FixedSizeBitVectors theory). without this\n"); + log(" option multi-bit wires are represented using the BitVec sort and\n"); log(" support for coarse grain cells (incl. arithmetic) is enabled.\n"); log("\n"); - log(" -mem\n"); - log(" enable support for memories (via ArraysEx theory). this option\n"); - log(" also implies -bv. only $mem cells without merged registers in\n"); + log(" -nomem\n"); + log(" disable support for memories (via ArraysEx theory). this option is\n"); + log(" implied by -nobv. only $mem cells without merged registers in\n"); log(" read ports are supported. call \"memory\" with -nordff to make sure\n"); log(" that no registers are merged into $mem read ports. '<mod>_m' functions\n"); log(" will be generated for accessing the arrays that are used to represent\n"); log(" memories.\n"); log("\n"); - log(" -regs\n"); - log(" also create '<mod>_n' functions for all registers.\n"); - log("\n"); log(" -wires\n"); - log(" also create '<mod>_n' functions for all public wires.\n"); + log(" create '<mod>_n' functions for all public wires. by default only ports,\n"); + log(" registers, and wires with the 'keep' attribute are exported.\n"); log("\n"); log(" -tpl <template_file>\n"); log(" use the given template file. the line containing only the token '%%%%'\n"); @@ -756,9 +975,9 @@ struct Smt2Backend : public Backend { virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) { std::ifstream template_f; - bool bvmode = false, memmode = false, regsmode = false, wiresmode = false, verbose = false; + bool bvmode = true, memmode = true, wiresmode = false, verbose = false; - log_header("Executing SMT2 backend.\n"); + log_header(design, "Executing SMT2 backend.\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -769,17 +988,17 @@ struct Smt2Backend : public Backend { log_error("Can't open template file `%s'.\n", args[argidx].c_str()); continue; } - if (args[argidx] == "-bv") { - bvmode = true; + if (args[argidx] == "-bv" || args[argidx] == "-mem") { + log_warning("Options -bv and -mem are now the default. Support for -bv and -mem will be removed in the future.\n"); continue; } - if (args[argidx] == "-mem") { - bvmode = true; - memmode = true; + if (args[argidx] == "-nobv") { + bvmode = false; + memmode = false; continue; } - if (args[argidx] == "-regs") { - regsmode = true; + if (args[argidx] == "-nomem") { + memmode = false; continue; } if (args[argidx] == "-wires") { @@ -808,18 +1027,62 @@ struct Smt2Backend : public Backend { *f << stringf("; SMT-LIBv2 description generated by %s\n", yosys_version_str); - for (auto module : design->modules()) + if (!bvmode) + *f << stringf("; yosys-smt2-nobv\n"); + + if (!memmode) + *f << stringf("; yosys-smt2-nomem\n"); + + std::vector<RTLIL::Module*> sorted_modules; + + // extract module dependencies + std::map<RTLIL::Module*, std::set<RTLIL::Module*>> module_deps; + for (auto &mod_it : design->modules_) { + module_deps[mod_it.second] = std::set<RTLIL::Module*>(); + for (auto &cell_it : mod_it.second->cells_) + if (design->modules_.count(cell_it.second->type) > 0) + module_deps[mod_it.second].insert(design->modules_.at(cell_it.second->type)); + } + + // simple good-enough topological sort + // (O(n*m) on n elements and depth m) + while (module_deps.size() > 0) { + size_t sorted_modules_idx = sorted_modules.size(); + for (auto &it : module_deps) { + for (auto &dep : it.second) + if (module_deps.count(dep) > 0) + goto not_ready_yet; + // log("Next in topological sort: %s\n", RTLIL::id2cstr(it.first->name)); + sorted_modules.push_back(it.first); + not_ready_yet:; + } + if (sorted_modules_idx == sorted_modules.size()) + log_error("Cyclic dependency between modules found! Cycle includes module %s.\n", RTLIL::id2cstr(module_deps.begin()->first->name)); + while (sorted_modules_idx < sorted_modules.size()) + module_deps.erase(sorted_modules.at(sorted_modules_idx++)); + } + + Module *topmod = design->top_module(); + std::string topmod_id; + + for (auto module : sorted_modules) { if (module->get_bool_attribute("\\blackbox") || module->has_memories_warn() || module->has_processes_warn()) continue; log("Creating SMT-LIBv2 representation of module %s.\n", log_id(module)); - Smt2Worker worker(module, bvmode, memmode, regsmode, wiresmode, verbose); + Smt2Worker worker(module, bvmode, memmode, wiresmode, verbose); worker.run(); worker.write(*f); + + if (module == topmod) + topmod_id = worker.get_id(module); } + if (topmod) + *f << stringf("; yosys-smt2-topmod %s\n", topmod_id.c_str()); + *f << stringf("; end of yosys output\n"); if (template_f.is_open()) { diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py index f2911b3e..bb763647 100644 --- a/backends/smt2/smtbmc.py +++ b/backends/smt2/smtbmc.py @@ -19,66 +19,119 @@ import os, sys, getopt, re ##yosys-sys-path## -from smtio import smtio, smtopts, mkvcd +from smtio import SmtIo, SmtOpts, MkVcd +from collections import defaultdict skip_steps = 0 step_size = 1 num_steps = 20 vcdfile = None +vlogtbfile = None +inconstr = list() +outconstr = None +gentrace = False tempind = False +dumpall = False assume_skipped = None +final_only = False topmod = None -so = smtopts() +noinfo = False +so = SmtOpts() def usage(): print(""" yosys-smtbmc [options] <yosys_smt2_output> - -t <num_steps>, -t <skip_steps>:<num_steps> - default: skip_steps=0, num_steps=20 + -t <num_steps> + -t <skip_steps>:<num_steps> + -t <skip_steps>:<step_size>:<num_steps> + default: skip_steps=0, step_size=1, num_steps=20 - -u <start_step> - assume asserts in skipped steps in BMC - - -S <step_size> - proof <step_size> time steps at once - - -c <vcd_filename> - write counter-example to this VCD file - (hint: use 'write_smt2 -wires' for maximum - coverage of signals in generated VCD file) + -g + generate an arbitrary trace that satisfies + all assertions and assumptions. -i instead of BMC run temporal induction -m <module_name> name of the top module + + --smtc <constr_filename> + read constraints file + + --noinfo + only run the core proof, do not collect and print any + additional information (e.g. which assert failed) + + --final-only + only check final constraints, assume base case + + --assume-skipped <start_step> + assume asserts in skipped steps in BMC. + no assumptions are created for skipped steps + before <start_step>. + + --dump-vcd <vcd_filename> + write trace to this VCD file + (hint: use 'write_smt2 -wires' for maximum + coverage of signals in generated VCD file) + + --dump-vlogtb <verilog_filename> + write trace as Verilog test bench + + --dump-smtc <constr_filename> + write trace as constraints file + + --dump-all + when using -g or -i, create a dump file for each + step. The character '%' is replaces in all dump + filenames with the step number. """ + so.helpmsg()) sys.exit(1) try: - opts, args = getopt.getopt(sys.argv[1:], so.optstr + "t:u:S:c:im:") + opts, args = getopt.getopt(sys.argv[1:], so.shortopts + "t:igm:", so.longopts + + ["final-only", "assume-skipped=", "smtc=", "dump-vcd=", "dump-vlogtb=", "dump-smtc=", "dump-all", "noinfo"]) except: usage() for o, a in opts: if o == "-t": - match = re.match(r"(\d+):(.*)", a) - if match: - skip_steps = int(match.group(1)) - num_steps = int(match.group(2)) + a = a.split(":") + if len(a) == 1: + num_steps = int(a[0]) + elif len(a) == 2: + skip_steps = int(a[0]) + num_steps = int(a[1]) + elif len(a) == 3: + skip_steps = int(a[0]) + step_size = int(a[1]) + num_steps = int(a[2]) else: - num_steps = int(a) - elif o == "-u": + assert 0 + elif o == "--assume-skipped": assume_skipped = int(a) - elif o == "-S": - step_size = int(a) - elif o == "-c": + elif o == "--final-only": + final_only = True + elif o == "--smtc": + inconstr.append(a) + elif o == "--dump-vcd": vcdfile = a + elif o == "--dump-vlogtb": + vlogtbfile = a + elif o == "--dump-smtc": + outconstr = a + elif o == "--dump-all": + dumpall = True + elif o == "--noinfo": + noinfo = True elif o == "-i": tempind = True + elif o == "-g": + gentrace = True elif o == "-m": topmod = a elif so.handle(o, a): @@ -90,73 +143,422 @@ if len(args) != 1: usage() -smt = smtio(opts=so) +constr_final_start = None +constr_asserts = defaultdict(list) +constr_assumes = defaultdict(list) + +for fn in inconstr: + current_states = None + current_line = 0 + + with open(fn, "r") as f: + for line in f: + current_line += 1 + + if line.startswith("#"): + continue + + tokens = line.split() + + if len(tokens) == 0: + continue + + if tokens[0] == "initial": + current_states = set() + if not tempind: + current_states.add(0) + continue + + if tokens[0] == "final": + constr_final = True + if len(tokens) == 1: + current_states = set(["final-%d" % i for i in range(0, num_steps+1)]) + constr_final_start = 0 + elif len(tokens) == 2: + i = int(tokens[1]) + assert i < 0 + current_states = set(["final-%d" % i for i in range(-i, num_steps+1)]) + constr_final_start = -i if constr_final_start is None else min(constr_final_start, -i) + else: + assert 0 + continue + + if tokens[0] == "state": + current_states = set() + if not tempind: + for token in tokens[1:]: + tok = token.split(":") + if len(tok) == 1: + current_states.add(int(token)) + elif len(tok) == 2: + lower = int(tok[0]) + if tok[1] == "*": + upper = num_steps + else: + upper = int(tok[1]) + for i in range(lower, upper+1): + current_states.add(i) + else: + assert 0 + continue + + if tokens[0] == "always": + if len(tokens) == 1: + current_states = set(range(0, num_steps+1)) + elif len(tokens) == 2: + i = int(tokens[1]) + assert i < 0 + current_states = set(range(-i, num_steps+1)) + else: + assert 0 + continue + + if tokens[0] == "assert": + assert current_states is not None + + for state in current_states: + constr_asserts[state].append(("%s:%d" % (fn, current_line), " ".join(tokens[1:]))) + + continue + + if tokens[0] == "assume": + assert current_states is not None + + for state in current_states: + constr_assumes[state].append(("%s:%d" % (fn, current_line), " ".join(tokens[1:]))) + + continue + + assert 0 + + +def get_constr_expr(db, state, final=False, getvalues=False): + if final: + if ("final-%d" % state) not in db: + return ([], [], []) if getvalues else "true" + else: + if state not in db: + return ([], [], []) if getvalues else "true" + + netref_regex = re.compile(r'(^|[( ])\[(-?[0-9]+:|)([^\]]+)\](?=[ )]|$)') + + def replace_netref(match): + state_sel = match.group(2) + + if state_sel == "": + st = state + elif state_sel[0] == "-": + st = state + int(state_sel[:-1]) + else: + st = int(state_sel[:-1]) + + expr = smt.net_expr(topmod, "s%d" % st, smt.get_path(topmod, match.group(3))) + + return match.group(1) + expr + + expr_list = list() + for loc, expr in db[("final-%d" % state) if final else state]: + actual_expr = netref_regex.sub(replace_netref, expr) + if getvalues: + expr_list.append((loc, expr, actual_expr)) + else: + expr_list.append(actual_expr) + + if getvalues: + loc_list, expr_list, acual_expr_list = zip(*expr_list) + value_list = smt.get_list(acual_expr_list) + return loc_list, expr_list, value_list + + if len(expr_list) == 0: + return "true" + + if len(expr_list) == 1: + return expr_list[0] + + return "(and %s)" % " ".join(expr_list) -print("%s Solver: %s" % (smt.timestamp(), so.solver)) -smt.setup("QF_AUFBV") -debug_nets = set() -debug_nets_re = re.compile(r"^; yosys-smt2-(input|output|register|wire) (\S+) (\d+)") +smt = SmtIo(opts=so) + +def print_msg(msg): + print("%s %s" % (smt.timestamp(), msg)) + sys.stdout.flush() + +print_msg("Solver: %s" % (so.solver)) with open(args[0], "r") as f: for line in f: - match = debug_nets_re.match(line) - if match: - debug_nets.add(match.group(2)) - if line.startswith("; yosys-smt2-module") and topmod is None: - topmod = line.split()[2] smt.write(line) +if topmod is None: + topmod = smt.topmod + assert topmod is not None +assert topmod in smt.modinfo + + +def write_vcd_trace(steps_start, steps_stop, index): + filename = vcdfile.replace("%", index) + print_msg("Writing trace to VCD file: %s" % (filename)) + + with open(filename, "w") as vcd_file: + vcd = MkVcd(vcd_file) + path_list = list() + + for netpath in sorted(smt.hiernets(topmod)): + hidden_net = False + for n in netpath: + if n.startswith("$"): + hidden_net = True + if not hidden_net: + vcd.add_net([topmod] + netpath, smt.net_width(topmod, netpath)) + path_list.append(netpath) + + for i in range(steps_start, steps_stop): + vcd.set_time(i) + value_list = smt.get_net_bin_list(topmod, path_list, "s%d" % i) + for path, value in zip(path_list, value_list): + vcd.set_net([topmod] + path, value) + + vcd.set_time(steps_stop) + + +def write_vlogtb_trace(steps_start, steps_stop, index): + filename = vlogtbfile.replace("%", index) + print_msg("Writing trace to Verilog testbench: %s" % (filename)) + + with open(filename, "w") as f: + print("module testbench;", file=f) + print(" reg [4095:0] vcdfile;", file=f) + print(" reg clock = 0, genclock = 1;", file=f) + + primary_inputs = list() + clock_inputs = set() + + for name in smt.modinfo[topmod].inputs: + if name in ["clk", "clock", "CLK", "CLOCK"]: + clock_inputs.add(name) + width = smt.modinfo[topmod].wsize[name] + primary_inputs.append((name, width)) + + for name, width in primary_inputs: + if name in clock_inputs: + print(" wire [%d:0] PI_%s = clock;" % (width-1, name), file=f) + else: + print(" reg [%d:0] PI_%s;" % (width-1, name), file=f) + + print(" %s UUT (" % topmod, file=f) + print(",\n".join(" .{name}(PI_{name})".format(name=name) for name, _ in primary_inputs), file=f) + print(" );", file=f) + + print(" initial begin", file=f) + print(" if ($value$plusargs(\"vcd=%s\", vcdfile)) begin", file=f) + print(" $dumpfile(vcdfile);", file=f) + print(" $dumpvars(0, testbench);", file=f) + print(" end", file=f) + print(" while (genclock) begin", file=f) + print(" #5; clock = 0;", file=f) + print(" #5; clock = 1;", file=f) + print(" end", file=f) + print(" end", file=f) + + print(" initial begin", file=f) + + regs = sorted(smt.hiernets(topmod, regs_only=True)) + regvals = smt.get_net_bin_list(topmod, regs, "s%d" % steps_start) + + print(" #1;", file=f) + for reg, val in zip(regs, regvals): + hidden_net = False + for n in reg: + if n.startswith("$"): + hidden_net = True + print(" %sUUT.%s = %d'b%s;" % ("// " if hidden_net else "", ".".join(reg), len(val), val), file=f) + + mems = sorted(smt.hiermems(topmod)) + for mempath in mems: + abits, width, ports = smt.mem_info(topmod, "s%d" % steps_start, mempath) + mem = smt.mem_expr(topmod, "s%d" % steps_start, mempath) + + addr_expr_list = list() + for i in range(steps_start, steps_stop): + for j in range(ports): + addr_expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, j)) + + addr_list = set() + for val in smt.get_list(addr_expr_list): + addr_list.add(smt.bv2int(val)) + + expr_list = list() + for i in addr_list: + expr_list.append("(select %s #b%s)" % (mem, format(i, "0%db" % abits))) + + for i, val in zip(addr_list, smt.get_list(expr_list)): + val = smt.bv2bin(val) + print(" UUT.%s[%d] = %d'b%s;" % (".".join(mempath), i, len(val), val), file=f) + + for i in range(steps_start, steps_stop): + pi_names = [[name] for name, _ in primary_inputs if name not in clock_inputs] + pi_values = smt.get_net_bin_list(topmod, pi_names, "s%d" % i) + + print(" #1;", file=f) + print(" // state %d" % i, file=f) + if i > 0: + print(" @(posedge clock);", file=f) + for name, val in zip(pi_names, pi_values): + print(" PI_%s <= %d'b%s;" % (".".join(name), len(val), val), file=f) + + print(" genclock = 0;", file=f) + print(" end", file=f) + + print("endmodule", file=f) + + +def write_constr_trace(steps_start, steps_stop, index): + filename = outconstr.replace("%", index) + print_msg("Writing trace to constraints file: %s" % (filename)) + + with open(filename, "w") as f: + primary_inputs = list() + + for name in smt.modinfo[topmod].inputs: + width = smt.modinfo[topmod].wsize[name] + primary_inputs.append((name, width)) + + if steps_start == 0: + print("initial", file=f) + else: + print("state %d" % steps_start, file=f) + + regnames = sorted(smt.hiernets(topmod, regs_only=True)) + regvals = smt.get_net_list(topmod, regnames, "s%d" % steps_start) + + for name, val in zip(regnames, regvals): + print("assume (= [%s] %s)" % (".".join(name), val), file=f) + + mems = sorted(smt.hiermems(topmod)) + for mempath in mems: + abits, width, ports = smt.mem_info(topmod, "s%d" % steps_start, mempath) + mem = smt.mem_expr(topmod, "s%d" % steps_start, mempath) + + addr_expr_list = list() + for i in range(steps_start, steps_stop): + for j in range(ports): + addr_expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, j)) + + addr_list = set((smt.bv2int(val) for val in smt.get_list(addr_expr_list))) + + expr_list = list() + for i in addr_list: + expr_list.append("(select %s #b%s)" % (mem, format(i, "0%db" % abits))) + + for i, val in zip(addr_list, smt.get_list(expr_list)): + print("assume (= (select [%s] #b%s) %s)" % (".".join(mempath), format(i, "0%db" % abits), val), file=f) + + for k in range(steps_start, steps_stop): + print("", file=f) + print("state %d" % k, file=f) + + pi_names = [[name] for name, _ in sorted(primary_inputs)] + pi_values = smt.get_net_list(topmod, pi_names, "s%d" % k) + + for name, val in zip(pi_names, pi_values): + print("assume (= [%s] %s)" % (".".join(name), val), file=f) + + +def write_trace(steps_start, steps_stop, index): + if vcdfile is not None: + write_vcd_trace(steps_start, steps_stop, index) + + if vlogtbfile is not None: + write_vlogtb_trace(steps_start, steps_stop, index) + + if outconstr is not None: + write_constr_trace(steps_start, steps_stop, index) + + +def print_failed_asserts_worker(mod, state, path): + assert mod in smt.modinfo + + if smt.get("(|%s_a| %s)" % (mod, state)) in ["true", "#b1"]: + return + + for cellname, celltype in smt.modinfo[mod].cells.items(): + print_failed_asserts_worker(celltype, "(|%s_h %s| %s)" % (mod, cellname, state), path + "." + cellname) + + for assertfun, assertinfo in smt.modinfo[mod].asserts.items(): + if smt.get("(|%s| %s)" % (assertfun, state)) in ["false", "#b0"]: + print_msg("Assert failed in %s: %s" % (path, assertinfo)) -def write_vcd_model(steps): - print("%s Writing model to VCD file." % smt.timestamp()) +def print_failed_asserts(state, final=False): + if noinfo: return + loc_list, expr_list, value_list = get_constr_expr(constr_asserts, state, final=final, getvalues=True) - vcd = mkvcd(open(vcdfile, "w")) - for netname in sorted(debug_nets): - width = len(smt.get_net_bin(topmod, netname, "s0")) - vcd.add_net(netname, width) + for loc, expr, value in zip(loc_list, expr_list, value_list): + if smt.bv2int(value) == 0: + print_msg("Assert %s failed: %s" % (loc, expr)) - for i in range(steps): - vcd.set_time(i) - for netname in debug_nets: - vcd.set_net(netname, smt.get_net_bin(topmod, netname, "s%d" % i)) + if not final: + print_failed_asserts_worker(topmod, "s%d" % state, topmod) - vcd.set_time(steps) + +def print_anyconsts_worker(mod, state, path): + assert mod in smt.modinfo + + for cellname, celltype in smt.modinfo[mod].cells.items(): + print_anyconsts_worker(celltype, "(|%s_h %s| %s)" % (mod, cellname, state), path + "." + cellname) + + for fun, info in smt.modinfo[mod].anyconsts.items(): + print_msg("Value for anyconst in %s (%s): %d" % (path, info, smt.bv2int(smt.get("(|%s| %s)" % (fun, state))))) + + +def print_anyconsts(state): + if noinfo: return + print_anyconsts_worker(topmod, "s%d" % state, topmod) if tempind: retstatus = False skip_counter = step_size for step in range(num_steps, -1, -1): - smt.write("(declare-fun s%d () %s_s)" % (step, topmod)) - smt.write("(assert (%s_u s%d))" % (topmod, step)) + smt.write("(declare-fun s%d () |%s_s|)" % (step, topmod)) + smt.write("(assert (|%s_u| s%d))" % (topmod, step)) + smt.write("(assert (|%s_h| s%d))" % (topmod, step)) + smt.write("(assert (not (|%s_is| s%d)))" % (topmod, step)) + smt.write("(assert %s)" % get_constr_expr(constr_assumes, step)) if step == num_steps: - smt.write("(assert (not (%s_a s%d)))" % (topmod, step)) + smt.write("(assert (not (and (|%s_a| s%d) %s)))" % (topmod, step, get_constr_expr(constr_asserts, step))) else: - smt.write("(assert (%s_t s%d s%d))" % (topmod, step, step+1)) - smt.write("(assert (%s_a s%d))" % (topmod, step)) + smt.write("(assert (|%s_t| s%d s%d))" % (topmod, step, step+1)) + smt.write("(assert (|%s_a| s%d))" % (topmod, step)) + smt.write("(assert %s)" % get_constr_expr(constr_asserts, step)) if step > num_steps-skip_steps: - print("%s Skipping induction in step %d.." % (smt.timestamp(), step)) + print_msg("Skipping induction in step %d.." % (step)) continue skip_counter += 1 if skip_counter < step_size: - print("%s Skipping induction in step %d.." % (smt.timestamp(), step)) + print_msg("Skipping induction in step %d.." % (step)) continue skip_counter = 0 - print("%s Trying induction in step %d.." % (smt.timestamp(), step)) + print_msg("Trying induction in step %d.." % (step)) if smt.check_sat() == "sat": if step == 0: print("%s Temporal induction failed!" % smt.timestamp()) - if vcdfile is not None: - write_vcd_model(num_steps+1) + print_anyconsts(num_steps) + print_failed_asserts(num_steps) + write_trace(step, num_steps+1, '%') + + elif dumpall: + print_anyconsts(num_steps) + print_failed_asserts(num_steps) + write_trace(step, num_steps+1, "%d" % step) else: print("%s Temporal induction successful." % smt.timestamp()) @@ -164,62 +566,116 @@ if tempind: break -else: # not tempind +else: # not tempind step = 0 retstatus = True while step < num_steps: - smt.write("(declare-fun s%d () %s_s)" % (step, topmod)) - smt.write("(assert (%s_u s%d))" % (topmod, step)) + smt.write("(declare-fun s%d () |%s_s|)" % (step, topmod)) + smt.write("(assert (|%s_u| s%d))" % (topmod, step)) + smt.write("(assert (|%s_h| s%d))" % (topmod, step)) + smt.write("(assert %s)" % get_constr_expr(constr_assumes, step)) if step == 0: - smt.write("(assert (%s_i s0))" % (topmod)) + smt.write("(assert (|%s_i| s0))" % (topmod)) + smt.write("(assert (|%s_is| s0))" % (topmod)) else: - smt.write("(assert (%s_t s%d s%d))" % (topmod, step-1, step)) + smt.write("(assert (|%s_t| s%d s%d))" % (topmod, step-1, step)) + smt.write("(assert (not (|%s_is| s%d)))" % (topmod, step)) if step < skip_steps: if assume_skipped is not None and step >= assume_skipped: - print("%s Skipping step %d (and assuming pass).." % (smt.timestamp(), step)) - smt.write("(assert (%s_a s%d))" % (topmod, step)) + print_msg("Skipping step %d (and assuming pass).." % (step)) + smt.write("(assert (|%s_a| s%d))" % (topmod, step)) + smt.write("(assert %s)" % get_constr_expr(constr_asserts, step)) else: - print("%s Skipping step %d.." % (smt.timestamp(), step)) + print_msg("Skipping step %d.." % (step)) step += 1 continue last_check_step = step for i in range(1, step_size): if step+i < num_steps: - smt.write("(declare-fun s%d () %s_s)" % (step+i, topmod)) - smt.write("(assert (%s_u s%d))" % (topmod, step+i)) - smt.write("(assert (%s_t s%d s%d))" % (topmod, step+i-1, step+i)) + smt.write("(declare-fun s%d () |%s_s|)" % (step+i, topmod)) + smt.write("(assert (|%s_u| s%d))" % (topmod, step+i)) + smt.write("(assert (|%s_h| s%d))" % (topmod, step+i)) + smt.write("(assert (|%s_t| s%d s%d))" % (topmod, step+i-1, step+i)) + smt.write("(assert %s)" % get_constr_expr(constr_assumes, step+i)) last_check_step = step+i - if last_check_step == step: - print("%s Checking asserts in step %d.." % (smt.timestamp(), step)) - else: - print("%s Checking asserts in steps %d to %d.." % (smt.timestamp(), step, last_check_step)) - smt.write("(push 1)") + if not gentrace: + if not final_only: + if last_check_step == step: + print_msg("Checking asserts in step %d.." % (step)) + else: + print_msg("Checking asserts in steps %d to %d.." % (step, last_check_step)) + smt.write("(push 1)") - smt.write("(assert (not (and %s)))" % " ".join(["(%s_a s%d)" % (topmod, i) for i in range(step, last_check_step+1)])) + smt.write("(assert (not (and %s)))" % " ".join(["(|%s_a| s%d)" % (topmod, i) for i in range(step, last_check_step+1)] + + [get_constr_expr(constr_asserts, i) for i in range(step, last_check_step+1)])) - if smt.check_sat() == "sat": - print("%s BMC failed!" % smt.timestamp()) - if vcdfile is not None: - write_vcd_model(step+step_size) - retstatus = False - break + if smt.check_sat() == "sat": + print("%s BMC failed!" % smt.timestamp()) + print_anyconsts(step) + for i in range(step, last_check_step+1): + print_failed_asserts(i) + write_trace(0, last_check_step+1, '%') + retstatus = False + break + + smt.write("(pop 1)") - else: # unsat - smt.write("(pop 1)") for i in range(step, last_check_step+1): - smt.write("(assert (%s_a s%d))" % (topmod, i)) + smt.write("(assert (|%s_a| s%d))" % (topmod, i)) + smt.write("(assert %s)" % get_constr_expr(constr_asserts, i)) + + if constr_final_start is not None: + for i in range(step, last_check_step+1): + if i < constr_final_start: + continue + + print_msg("Checking final constraints in step %d.." % (i)) + smt.write("(push 1)") + + smt.write("(assert %s)" % get_constr_expr(constr_assumes, i, final=True)) + smt.write("(assert (not %s))" % get_constr_expr(constr_asserts, i, final=True)) + + if smt.check_sat() == "sat": + print("%s BMC failed!" % smt.timestamp()) + print_anyconsts(i) + print_failed_asserts(i, final=True) + write_trace(0, i+1, '%') + retstatus = False + break + + smt.write("(pop 1)") + if not retstatus: + break + + else: # gentrace + for i in range(step, last_check_step+1): + smt.write("(assert (|%s_a| s%d))" % (topmod, i)) + smt.write("(assert %s)" % get_constr_expr(constr_asserts, i)) + + print_msg("Solving for step %d.." % (last_check_step)) + if smt.check_sat() != "sat": + print("%s No solution found!" % smt.timestamp()) + retstatus = False + break + + elif dumpall: + print_anyconsts(0) + write_trace(0, last_check_step+1, "%d" % step) step += step_size + if gentrace: + print_anyconsts(0) + write_trace(0, num_steps, '%') + smt.write("(exit)") smt.wait() -print("%s Status: %s" % (smt.timestamp(), "PASSED" if retstatus else "FAILED (!)")) +print_msg("Status: %s" % ("PASSED" if retstatus else "FAILED (!)")) sys.exit(0 if retstatus else 1) - diff --git a/backends/smt2/smtio.py b/backends/smt2/smtio.py index 6e8bded7..58554572 100644 --- a/backends/smt2/smtio.py +++ b/backends/smt2/smtio.py @@ -17,36 +17,59 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # -import sys -import subprocess +import sys, subprocess, re +from copy import deepcopy from select import select from time import time -class smtio: - def __init__(self, solver=None, debug_print=None, debug_file=None, timeinfo=None, opts=None): + +hex_dict = { + "0": "0000", "1": "0001", "2": "0010", "3": "0011", + "4": "0100", "5": "0101", "6": "0110", "7": "0111", + "8": "1000", "9": "1001", "A": "1010", "B": "1011", + "C": "1100", "D": "1101", "E": "1110", "F": "1111", + "a": "1010", "b": "1011", "c": "1100", "d": "1101", + "e": "1110", "f": "1111" +} + + +class SmtModInfo: + def __init__(self): + self.inputs = set() + self.outputs = set() + self.registers = set() + self.memories = dict() + self.wires = set() + self.wsize = dict() + self.cells = dict() + self.asserts = dict() + self.anyconsts = dict() + + +class SmtIo: + def __init__(self, opts=None): + self.logic = None + self.logic_qf = True + self.logic_ax = True + self.logic_uf = True + self.logic_bv = True + if opts is not None: + self.logic = opts.logic self.solver = opts.solver self.debug_print = opts.debug_print self.debug_file = opts.debug_file + self.dummy_file = opts.dummy_file self.timeinfo = opts.timeinfo + self.unroll = opts.unroll else: self.solver = "z3" self.debug_print = False self.debug_file = None + self.dummy_file = None self.timeinfo = True - - if solver is not None: - self.solver = solver - - if debug_print is not None: - self.debug_print = debug_print - - if debug_file is not None: - self.debug_file = debug_file - - if timeinfo is not None: - self.timeinfo = timeinfo + self.unroll = False if self.solver == "yices": popen_vargs = ['yices-smt2', '--incremental'] @@ -60,44 +83,265 @@ class smtio: if self.solver == "mathsat": popen_vargs = ['mathsat'] - self.p = subprocess.Popen(popen_vargs, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + if self.solver == "boolector": + popen_vargs = ['boolector', '--smt2', '-i'] + self.unroll = True + + if self.solver == "dummy": + assert self.dummy_file is not None + self.dummy_fd = open(self.dummy_file, "r") + else: + if self.dummy_file is not None: + self.dummy_fd = open(self.dummy_file, "w") + self.p = subprocess.Popen(popen_vargs, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + + if self.unroll: + self.logic_uf = False + self.unroll_idcnt = 0 + self.unroll_buffer = "" + self.unroll_sorts = set() + self.unroll_objs = set() + self.unroll_decls = dict() + self.unroll_cache = dict() + self.unroll_stack = list() + self.start_time = time() - def setup(self, logic="ALL", info=None): - self.write("(set-logic %s)" % logic) - if info is not None: - self.write("(set-info :source |%s|)" % info) - self.write("(set-info :smt-lib-version 2.5)") - self.write("(set-info :category \"industrial\")") + self.modinfo = dict() + self.curmod = None + self.topmod = None + self.setup_done = False + + def setup(self): + assert not self.setup_done + + if self.logic is None: + self.logic = "" + if self.logic_qf: self.logic += "QF_" + if self.logic_ax: self.logic += "A" + if self.logic_uf: self.logic += "UF" + if self.logic_bv: self.logic += "BV" + + self.setup_done = True + self.write("(set-option :produce-models true)") + self.write("(set-logic %s)" % self.logic) def timestamp(self): secs = int(time() - self.start_time) return "## %6d %3d:%02d:%02d " % (secs, secs // (60*60), (secs // 60) % 60, secs % 60) - def write(self, stmt): + def replace_in_stmt(self, stmt, pat, repl): + if stmt == pat: + return repl + + if isinstance(stmt, list): + return [self.replace_in_stmt(s, pat, repl) for s in stmt] + + return stmt + + def unroll_stmt(self, stmt): + if not isinstance(stmt, list): + return stmt + + stmt = [self.unroll_stmt(s) for s in stmt] + + if len(stmt) >= 2 and not isinstance(stmt[0], list) and stmt[0] in self.unroll_decls: + assert stmt[1] in self.unroll_objs + + key = tuple(stmt) + if key not in self.unroll_cache: + decl = deepcopy(self.unroll_decls[key[0]]) + + self.unroll_cache[key] = "|UNROLL#%d|" % self.unroll_idcnt + decl[1] = self.unroll_cache[key] + self.unroll_idcnt += 1 + + if decl[0] == "declare-fun": + if isinstance(decl[3], list) or decl[3] not in self.unroll_sorts: + self.unroll_objs.add(decl[1]) + decl[2] = list() + else: + self.unroll_objs.add(decl[1]) + decl = list() + + elif decl[0] == "define-fun": + arg_index = 1 + for arg_name, arg_sort in decl[2]: + decl[4] = self.replace_in_stmt(decl[4], arg_name, key[arg_index]) + arg_index += 1 + decl[2] = list() + + if len(decl) > 0: + decl = self.unroll_stmt(decl) + self.write(self.unparse(decl), unroll=False) + + return self.unroll_cache[key] + + return stmt + + def write(self, stmt, unroll=True): + if stmt.startswith(";"): + self.info(stmt) + elif not self.setup_done: + self.setup() + stmt = stmt.strip() + + if unroll and self.unroll: + if stmt.startswith(";"): + return + + stmt = re.sub(r" ;.*", "", stmt) + stmt = self.unroll_buffer + stmt + self.unroll_buffer = "" + + s = re.sub(r"\|[^|]*\|", "", stmt) + if s.count("(") != s.count(")"): + self.unroll_buffer = stmt + " " + return + + s = self.parse(stmt) + + if self.debug_print: + print("-> %s" % s) + + if len(s) == 3 and s[0] == "declare-sort" and s[2] == "0": + self.unroll_sorts.add(s[1]) + return + + elif len(s) == 4 and s[0] == "declare-fun" and s[2] == [] and s[3] in self.unroll_sorts: + self.unroll_objs.add(s[1]) + return + + elif len(s) >= 4 and s[0] == "declare-fun": + for arg_sort in s[2]: + if arg_sort in self.unroll_sorts: + self.unroll_decls[s[1]] = s + return + + elif len(s) >= 4 and s[0] == "define-fun": + for arg_name, arg_sort in s[2]: + if arg_sort in self.unroll_sorts: + self.unroll_decls[s[1]] = s + return + + stmt = self.unparse(self.unroll_stmt(s)) + + if stmt == "(push 1)": + self.unroll_stack.append(( + deepcopy(self.unroll_sorts), + deepcopy(self.unroll_objs), + deepcopy(self.unroll_decls), + deepcopy(self.unroll_cache), + )) + + if stmt == "(pop 1)": + self.unroll_sorts, self.unroll_objs, self.unroll_decls, self.unroll_cache = self.unroll_stack.pop() + if self.debug_print: print("> %s" % stmt) + if self.debug_file: print(stmt, file=self.debug_file) self.debug_file.flush() - self.p.stdin.write(bytes(stmt + "\n", "ascii")) - self.p.stdin.flush() + + if self.solver != "dummy": + self.p.stdin.write(bytes(stmt + "\n", "ascii")) + self.p.stdin.flush() + + def info(self, stmt): + if not stmt.startswith("; yosys-smt2-"): + return + + fields = stmt.split() + + if fields[1] == "yosys-smt2-nomem": + if self.logic is None: + self.logic_ax = False + + if fields[1] == "yosys-smt2-nobv": + if self.logic is None: + self.logic_bv = False + + if fields[1] == "yosys-smt2-module": + self.curmod = fields[2] + self.modinfo[self.curmod] = SmtModInfo() + + if fields[1] == "yosys-smt2-cell": + self.modinfo[self.curmod].cells[fields[3]] = fields[2] + + if fields[1] == "yosys-smt2-topmod": + self.topmod = fields[2] + + if fields[1] == "yosys-smt2-input": + self.modinfo[self.curmod].inputs.add(fields[2]) + self.modinfo[self.curmod].wsize[fields[2]] = int(fields[3]) + + if fields[1] == "yosys-smt2-output": + self.modinfo[self.curmod].outputs.add(fields[2]) + self.modinfo[self.curmod].wsize[fields[2]] = int(fields[3]) + + if fields[1] == "yosys-smt2-register": + self.modinfo[self.curmod].registers.add(fields[2]) + self.modinfo[self.curmod].wsize[fields[2]] = int(fields[3]) + + if fields[1] == "yosys-smt2-memory": + self.modinfo[self.curmod].memories[fields[2]] = (int(fields[3]), int(fields[4]), int(fields[5])) + + if fields[1] == "yosys-smt2-wire": + self.modinfo[self.curmod].wires.add(fields[2]) + self.modinfo[self.curmod].wsize[fields[2]] = int(fields[3]) + + if fields[1] == "yosys-smt2-assert": + self.modinfo[self.curmod].asserts[fields[2]] = fields[3] + + if fields[1] == "yosys-smt2-anyconst": + self.modinfo[self.curmod].anyconsts[fields[2]] = fields[3] + + def hiernets(self, top, regs_only=False): + def hiernets_worker(nets, mod, cursor): + for netname in sorted(self.modinfo[mod].wsize.keys()): + if not regs_only or netname in self.modinfo[mod].registers: + nets.append(cursor + [netname]) + for cellname, celltype in sorted(self.modinfo[mod].cells.items()): + hiernets_worker(nets, celltype, cursor + [cellname]) + + nets = list() + hiernets_worker(nets, top, []) + return nets + + def hiermems(self, top): + def hiermems_worker(mems, mod, cursor): + for memname in sorted(self.modinfo[mod].memories.keys()): + mems.append(cursor + [memname]) + for cellname, celltype in sorted(self.modinfo[mod].cells.items()): + hiermems_worker(mems, celltype, cursor + [cellname]) + + mems = list() + hiermems_worker(mems, top, []) + return mems def read(self): stmt = [] count_brackets = 0 while True: - line = self.p.stdout.readline().decode("ascii").strip() + if self.solver == "dummy": + line = self.dummy_fd.readline().strip() + else: + line = self.p.stdout.readline().decode("ascii").strip() + if self.dummy_file is not None: + self.dummy_fd.write(line + "\n") + count_brackets += line.count("(") count_brackets -= line.count(")") stmt.append(line) + if self.debug_print: print("< %s" % line) if count_brackets == 0: break - if not self.p.poll(): + if self.solver != "dummy" and self.p.poll(): print("SMT Solver terminated unexpectedly: %s" % "".join(stmt)) sys.exit(1) @@ -115,43 +359,44 @@ class smtio: print("; running check-sat..", file=self.debug_file) self.debug_file.flush() - self.p.stdin.write(bytes("(check-sat)\n", "ascii")) - self.p.stdin.flush() + if self.solver != "dummy": + self.p.stdin.write(bytes("(check-sat)\n", "ascii")) + self.p.stdin.flush() - if self.timeinfo: - i = 0 - s = "/-\|" + if self.timeinfo: + i = 0 + s = "/-\|" - count = 0 - num_bs = 0 - while select([self.p.stdout], [], [], 0.1) == ([], [], []): - count += 1 + count = 0 + num_bs = 0 + while select([self.p.stdout], [], [], 0.1) == ([], [], []): + count += 1 - if count < 25: - continue + if count < 25: + continue - if count % 10 == 0 or count == 25: - secs = count // 10 + if count % 10 == 0 or count == 25: + secs = count // 10 - if secs < 60: - m = "(%d seconds)" % secs - elif secs < 60*60: - m = "(%d seconds -- %d:%02d)" % (secs, secs // 60, secs % 60) - else: - m = "(%d seconds -- %d:%02d:%02d)" % (secs, secs // (60*60), (secs // 60) % 60, secs % 60) + if secs < 60: + m = "(%d seconds)" % secs + elif secs < 60*60: + m = "(%d seconds -- %d:%02d)" % (secs, secs // 60, secs % 60) + else: + m = "(%d seconds -- %d:%02d:%02d)" % (secs, secs // (60*60), (secs // 60) % 60, secs % 60) - print("%s %s %c" % ("\b \b" * num_bs, m, s[i]), end="", file=sys.stderr) - num_bs = len(m) + 3 + print("%s %s %c" % ("\b \b" * num_bs, m, s[i]), end="", file=sys.stderr) + num_bs = len(m) + 3 - else: - print("\b" + s[i], end="", file=sys.stderr) + else: + print("\b" + s[i], end="", file=sys.stderr) - sys.stderr.flush() - i = (i + 1) % len(s) + sys.stderr.flush() + i = (i + 1) % len(s) - if num_bs != 0: - print("\b \b" * num_bs, end="", file=sys.stderr) - sys.stderr.flush() + if num_bs != 0: + print("\b \b" * num_bs, end="", file=sys.stderr) + sys.stderr.flush() result = self.read() if self.debug_file: @@ -192,9 +437,14 @@ class smtio: return expr, cursor return worker(stmt)[0] + def unparse(self, stmt): + if isinstance(stmt, list): + return "(" + " ".join([self.unparse(s) for s in stmt]) + ")" + return stmt + def bv2hex(self, v): h = "" - v = bv2bin(v) + v = self.bv2bin(v) while len(v) > 0: d = 0 if len(v) > 0 and v[-1] == "1": d += 1 @@ -212,66 +462,130 @@ class smtio: if v.startswith("#b"): return v[2:] if v.startswith("#x"): - digits = [] - for d in v[2:]: - if d == "0": digits.append("0000") - if d == "1": digits.append("0001") - if d == "2": digits.append("0010") - if d == "3": digits.append("0011") - if d == "4": digits.append("0100") - if d == "5": digits.append("0101") - if d == "6": digits.append("0110") - if d == "7": digits.append("0111") - if d == "8": digits.append("1000") - if d == "9": digits.append("1001") - if d in ("a", "A"): digits.append("1010") - if d in ("b", "B"): digits.append("1011") - if d in ("c", "C"): digits.append("1100") - if d in ("d", "D"): digits.append("1101") - if d in ("e", "E"): digits.append("1110") - if d in ("f", "F"): digits.append("1111") - return "".join(digits) + return "".join(hex_dict.get(x) for x in v[2:]) assert False + def bv2int(self, v): + return int(self.bv2bin(v), 2) + def get(self, expr): self.write("(get-value (%s))" % (expr)) return self.parse(self.read())[0][1] - def get_net(self, mod_name, net_name, state_name): - return self.get("(|%s_n %s| %s)" % (mod_name, net_name, state_name)) + def get_list(self, expr_list): + if len(expr_list) == 0: + return [] + self.write("(get-value (%s))" % " ".join(expr_list)) + return [n[1] for n in self.parse(self.read())] + + def get_path(self, mod, path): + assert mod in self.modinfo + path = path.split(".") + + for i in range(len(path)-1): + first = ".".join(path[0:i+1]) + second = ".".join(path[i+1:]) + + if first in self.modinfo[mod].cells: + nextmod = self.modinfo[mod].cells[first] + return [first] + self.get_path(nextmod, second) + + return [".".join(path)] + + def net_expr(self, mod, base, path): + if len(path) == 1: + assert mod in self.modinfo + if path[0] in self.modinfo[mod].wsize: + return "(|%s_n %s| %s)" % (mod, path[0], base) + if path[0] in self.modinfo[mod].memories: + return "(|%s_m %s| %s)" % (mod, path[0], base) + assert 0 + + assert mod in self.modinfo + assert path[0] in self.modinfo[mod].cells + + nextmod = self.modinfo[mod].cells[path[0]] + nextbase = "(|%s_h %s| %s)" % (mod, path[0], base) + return self.net_expr(nextmod, nextbase, path[1:]) + + def net_width(self, mod, net_path): + for i in range(len(net_path)-1): + assert mod in self.modinfo + assert net_path[i] in self.modinfo[mod].cells + mod = self.modinfo[mod].cells[net_path[i]] - def get_net_bool(self, mod_name, net_name, state_name): - v = self.get_net(mod_name, net_name, state_name) - assert v in ["true", "false"] - return 1 if v == "true" else 0 + assert mod in self.modinfo + assert net_path[-1] in self.modinfo[mod].wsize + return self.modinfo[mod].wsize[net_path[-1]] - def get_net_hex(self, mod_name, net_name, state_name): - return self.bv2hex(self.get_net(mod_name, net_name, state_name)) + def mem_expr(self, mod, base, path, portidx=None, infomode=False): + if len(path) == 1: + assert mod in self.modinfo + assert path[0] in self.modinfo[mod].memories + if infomode: + return self.modinfo[mod].memories[path[0]] + return "(|%s_m%s %s| %s)" % (mod, "" if portidx is None else ":%d" % portidx, path[0], base) - def get_net_bin(self, mod_name, net_name, state_name): - return self.bv2bin(self.get_net(mod_name, net_name, state_name)) + assert mod in self.modinfo + assert path[0] in self.modinfo[mod].cells + + nextmod = self.modinfo[mod].cells[path[0]] + nextbase = "(|%s_h %s| %s)" % (mod, path[0], base) + return self.mem_expr(nextmod, nextbase, path[1:], portidx=portidx, infomode=infomode) + + def mem_info(self, mod, base, path): + return self.mem_expr(mod, base, path, infomode=True) + + def get_net(self, mod_name, net_path, state_name): + return self.get(self.net_expr(mod_name, state_name, net_path)) + + def get_net_list(self, mod_name, net_path_list, state_name): + return self.get_list([self.net_expr(mod_name, state_name, n) for n in net_path_list]) + + def get_net_hex(self, mod_name, net_path, state_name): + return self.bv2hex(self.get_net(mod_name, net_path, state_name)) + + def get_net_hex_list(self, mod_name, net_path_list, state_name): + return [self.bv2hex(v) for v in self.get_net_list(mod_name, net_path_list, state_name)] + + def get_net_bin(self, mod_name, net_path, state_name): + return self.bv2bin(self.get_net(mod_name, net_path, state_name)) + + def get_net_bin_list(self, mod_name, net_path_list, state_name): + return [self.bv2bin(v) for v in self.get_net_list(mod_name, net_path_list, state_name)] def wait(self): - self.p.wait() + if self.solver != "dummy": + self.p.wait() -class smtopts: +class SmtOpts: def __init__(self): - self.optstr = "s:d:vp" + self.shortopts = "s:v" + self.longopts = ["unroll", "no-progress", "dump-smt2=", "logic=", "dummy="] self.solver = "z3" self.debug_print = False self.debug_file = None + self.dummy_file = None + self.unroll = False self.timeinfo = True + self.logic = None def handle(self, o, a): if o == "-s": self.solver = a elif o == "-v": self.debug_print = True - elif o == "-p": + elif o == "--unroll": + self.unroll = True + elif o == "--no-progress": self.timeinfo = True - elif o == "-d": + elif o == "--dump-smt2": self.debug_file = open(a, "w") + elif o == "--logic": + self.logic = a + elif o == "--dummy": + self.dummy_file = a else: return False return True @@ -279,47 +593,70 @@ class smtopts: def helpmsg(self): return """ -s <solver> - set SMT solver: z3, cvc4, yices, mathsat + set SMT solver: z3, cvc4, yices, mathsat, boolector, dummy default: z3 + --logic <smt2_logic> + use the specified SMT2 logic (e.g. QF_AUFBV) + + --dummy <filename> + if solver is "dummy", read solver output from that file + otherwise: write solver output to that file + -v enable debug output - -p + --unroll + unroll uninterpreted functions + + --no-progress disable timer display during solving - -d <filename> + --dump-smt2 <filename> write smt2 statements to file """ -class mkvcd: +class MkVcd: def __init__(self, f): self.f = f self.t = -1 self.nets = dict() - def add_net(self, name, width): + def add_net(self, path, width): + path = tuple(path) assert self.t == -1 key = "n%d" % len(self.nets) - self.nets[name] = (key, width) + self.nets[path] = (key, width) - def set_net(self, name, bits): - assert name in self.nets + def set_net(self, path, bits): + path = tuple(path) assert self.t >= 0 - print("b%s %s" % (bits, self.nets[name][0]), file=self.f) + assert path in self.nets + print("b%s %s" % (bits, self.nets[path][0]), file=self.f) def set_time(self, t): assert t >= self.t if t != self.t: if self.t == -1: + print("$var integer 32 t smt_step $end", file=self.f) print("$var event 1 ! smt_clock $end", file=self.f) - for name in sorted(self.nets): - key, width = self.nets[name] - print("$var wire %d %s %s $end" % (width, key, name), file=self.f) + scope = [] + for path in sorted(self.nets): + while len(scope)+1 > len(path) or (len(scope) > 0 and scope[-1] != path[len(scope)-1]): + print("$upscope $end", file=self.f) + scope = scope[:-1] + while len(scope)+1 < len(path): + print("$scope module %s $end" % path[len(scope)], file=self.f) + scope.append(path[len(scope)-1]) + key, width = self.nets[path] + print("$var wire %d %s %s $end" % (width, key, path[-1]), file=self.f) + for i in range(len(scope)): + print("$upscope $end", file=self.f) print("$enddefinitions $end", file=self.f) self.t = t assert self.t >= 0 - print("#%d" % self.t, file=self.f) + print("#%d" % (10 * self.t), file=self.f) print("1!", file=self.f) + print("b%s t" % format(self.t, "032b"), file=self.f) diff --git a/backends/smv/smv.cc b/backends/smv/smv.cc index b29a88ac..162ce490 100644 --- a/backends/smv/smv.cc +++ b/backends/smv/smv.cc @@ -694,7 +694,7 @@ struct SmvBackend : public Backend { std::ifstream template_f; bool verbose = false; - log_header("Executing SMV backend.\n"); + log_header(design, "Executing SMV backend.\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) diff --git a/backends/spice/spice.cc b/backends/spice/spice.cc index 12e2c669..4101cbf9 100644 --- a/backends/spice/spice.cc +++ b/backends/spice/spice.cc @@ -27,13 +27,33 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -static void print_spice_net(std::ostream &f, RTLIL::SigBit s, std::string &neg, std::string &pos, std::string &ncpf, int &nc_counter) +static string spice_id2str(IdString id) +{ + static const char *escape_chars = "$\\[]()<>="; + string s = RTLIL::unescape_id(id); + + for (auto &ch : s) + if (strchr(escape_chars, ch) != nullptr) ch = '_'; + + return s; +} + +static string spice_id2str(IdString id, bool use_inames, idict<IdString, 1> &inums) +{ + if (!use_inames && *id.c_str() == '$') + return stringf("%d", inums(id)); + return spice_id2str(id); +} + +static void print_spice_net(std::ostream &f, RTLIL::SigBit s, std::string &neg, std::string &pos, std::string &ncpf, int &nc_counter, bool use_inames, idict<IdString, 1> &inums) { if (s.wire) { + if (s.wire->port_id) + use_inames = true; if (s.wire->width > 1) - f << stringf(" %s[%d]", RTLIL::id2cstr(s.wire->name), s.offset); + f << stringf(" %s.%d", spice_id2str(s.wire->name, use_inames, inums).c_str(), s.offset); else - f << stringf(" %s", RTLIL::id2cstr(s.wire->name)); + f << stringf(" %s", spice_id2str(s.wire->name, use_inames, inums).c_str()); } else { if (s == RTLIL::State::S0) f << stringf(" %s", neg.c_str()); @@ -44,9 +64,10 @@ static void print_spice_net(std::ostream &f, RTLIL::SigBit s, std::string &neg, } } -static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::Design *design, std::string &neg, std::string &pos, std::string &ncpf, bool big_endian) +static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::Design *design, std::string &neg, std::string &pos, std::string &ncpf, bool big_endian, bool use_inames) { SigMap sigmap(module); + idict<IdString, 1> inums; int cell_counter = 0, conn_counter = 0, nc_counter = 0; for (auto &cell_it : module->cells_) @@ -59,7 +80,7 @@ static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::De if (design->modules_.count(cell->type) == 0) { log_warning("no (blackbox) module for cell type `%s' (%s.%s) found! Guessing order of ports.\n", - RTLIL::id2cstr(cell->type), RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name)); + log_id(cell->type), log_id(module), log_id(cell)); for (auto &conn : cell->connections()) { RTLIL::SigSpec sig = sigmap(conn.second); port_sigs.push_back(sig); @@ -93,18 +114,18 @@ static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::De for (auto &sig : port_sigs) { for (int i = 0; i < sig.size(); i++) { RTLIL::SigSpec s = sig.extract(big_endian ? sig.size() - 1 - i : i, 1); - print_spice_net(f, s, neg, pos, ncpf, nc_counter); + print_spice_net(f, s, neg, pos, ncpf, nc_counter, use_inames, inums); } } - f << stringf(" %s\n", RTLIL::id2cstr(cell->type)); + f << stringf(" %s\n", spice_id2str(cell->type).c_str()); } for (auto &conn : module->connections()) for (int i = 0; i < conn.first.size(); i++) { f << stringf("V%d", conn_counter++); - print_spice_net(f, conn.first.extract(i, 1), neg, pos, ncpf, nc_counter); - print_spice_net(f, conn.second.extract(i, 1), neg, pos, ncpf, nc_counter); + print_spice_net(f, conn.first.extract(i, 1), neg, pos, ncpf, nc_counter, use_inames, inums); + print_spice_net(f, conn.second.extract(i, 1), neg, pos, ncpf, nc_counter, use_inames, inums); f << stringf(" DC 0\n"); } } @@ -132,6 +153,10 @@ struct SpiceBackend : public Backend { log(" -nc_prefix\n"); log(" prefix for not-connected nets (default: _NC)\n"); log("\n"); + log(" -inames\n"); + log(" include names of internal ($-prefixed) nets in outputs\n"); + log(" (default is to use net numbers instead)\n"); + log("\n"); log(" -top top_module\n"); log(" set the specified module as design top module\n"); log("\n"); @@ -140,10 +165,10 @@ struct SpiceBackend : public Backend { { std::string top_module_name; RTLIL::Module *top_module = NULL; - bool big_endian = false; + bool big_endian = false, use_inames = false; std::string neg = "Vss", pos = "Vdd", ncpf = "_NC"; - log_header("Executing SPICE backend.\n"); + log_header(design, "Executing SPICE backend.\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -152,6 +177,10 @@ struct SpiceBackend : public Backend { big_endian = true; continue; } + if (args[argidx] == "-inames") { + use_inames = true; + continue; + } if (args[argidx] == "-neg" && argidx+1 < args.size()) { neg = args[++argidx]; continue; @@ -187,9 +216,9 @@ struct SpiceBackend : public Backend { continue; if (module->processes.size() != 0) - log_error("Found unmapped processes in module %s: unmapped processes are not supported in SPICE backend!\n", RTLIL::id2cstr(module->name)); + log_error("Found unmapped processes in module %s: unmapped processes are not supported in SPICE backend!\n", log_id(module)); if (module->memories.size() != 0) - log_error("Found munmapped emories in module %s: unmapped memories are not supported in SPICE backend!\n", RTLIL::id2cstr(module->name)); + log_error("Found unmapped memories in module %s: unmapped memories are not supported in SPICE backend!\n", log_id(module)); if (module->name == RTLIL::escape_id(top_module_name)) { top_module = module; @@ -206,24 +235,24 @@ struct SpiceBackend : public Backend { ports.at(wire->port_id-1) = wire; } - *f << stringf(".SUBCKT %s", RTLIL::id2cstr(module->name)); + *f << stringf(".SUBCKT %s", spice_id2str(module->name).c_str()); for (RTLIL::Wire *wire : ports) { log_assert(wire != NULL); if (wire->width > 1) { for (int i = 0; i < wire->width; i++) - *f << stringf(" %s[%d]", RTLIL::id2cstr(wire->name), big_endian ? wire->width - 1 - i : i); + *f << stringf(" %s.%d", spice_id2str(wire->name).c_str(), big_endian ? wire->width - 1 - i : i); } else - *f << stringf(" %s", RTLIL::id2cstr(wire->name)); + *f << stringf(" %s", spice_id2str(wire->name).c_str()); } *f << stringf("\n"); - print_spice_module(*f, module, design, neg, pos, ncpf, big_endian); - *f << stringf(".ENDS %s\n\n", RTLIL::id2cstr(module->name)); + print_spice_module(*f, module, design, neg, pos, ncpf, big_endian, use_inames); + *f << stringf(".ENDS %s\n\n", spice_id2str(module->name).c_str()); } if (!top_module_name.empty()) { if (top_module == NULL) log_error("Can't find top module `%s'!\n", top_module_name.c_str()); - print_spice_module(*f, top_module, design, neg, pos, ncpf, big_endian); + print_spice_module(*f, top_module, design, neg, pos, ncpf, big_endian, use_inames); *f << stringf("\n"); } diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 10f10e3c..52cf861d 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -19,11 +19,6 @@ * * A simple and straightforward Verilog backend. * - * Note that RTLIL processes can't always be mapped easily to a Verilog - * process. Therefore this frontend should only be used to export a - * Verilog netlist (i.e. after the "proc" pass has converted all processes - * to logic networks and registers). - * */ #include "kernel/register.h" @@ -38,7 +33,7 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -bool norename, noattr, attr2comment, noexpr; +bool norename, noattr, attr2comment, noexpr, nodec, nostr, defparam; 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; @@ -146,6 +141,9 @@ bool is_reg_wire(RTLIL::SigSpec sig, std::string ®_name) if (sig.size() != chunk.wire->width) { if (sig.size() == 1) reg_name += stringf("[%d]", chunk.wire->start_offset + chunk.offset); + else if (chunk.wire->upto) + reg_name += stringf("[%d:%d]", (chunk.wire->width - (chunk.offset + chunk.width - 1) - 1) + chunk.wire->start_offset, + (chunk.wire->width - chunk.offset - 1) + chunk.wire->start_offset); else reg_name += stringf("[%d:%d]", chunk.wire->start_offset + chunk.offset + chunk.width - 1, chunk.wire->start_offset + chunk.offset); @@ -158,8 +156,10 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o { if (width < 0) width = data.bits.size() - offset; + if (nostr) + goto dump_bits; if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) { - if (width == 32 && !no_decimal) { + if (width == 32 && !no_decimal && !nodec) { int32_t val = 0; for (int i = offset+width-1; i >= offset; i--) { log_assert(i < (int)data.bits.size()); @@ -169,9 +169,9 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o val |= 1 << (i - offset); } if (set_signed && val < 0) - f << stringf("-32'sd %u", -val); + f << stringf("-32'sd%u", -val); else - f << stringf("32'%sd %u", set_signed ? "s" : "", val); + f << stringf("32'%sd%u", set_signed ? "s" : "", val); } else { dump_bits: f << stringf("%d'%sb", width, set_signed ? "s" : ""); @@ -827,12 +827,13 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) std::vector<std::string> lof_reg_declarations; int nread_ports = cell->parameters["\\RD_PORTS"].as_int(); - RTLIL::SigSpec sig_rd_clk, sig_rd_data, sig_rd_addr; + RTLIL::SigSpec sig_rd_clk, sig_rd_en, sig_rd_data, sig_rd_addr; bool use_rd_clk, rd_clk_posedge, rd_transparent; // read ports for (int i=0; i < nread_ports; i++) { sig_rd_clk = cell->getPort("\\RD_CLK").extract(i); + sig_rd_en = cell->getPort("\\RD_EN").extract(i); sig_rd_data = cell->getPort("\\RD_DATA").extract(i*width, width); sig_rd_addr = cell->getPort("\\RD_ADDR").extract(i*abits, abits); use_rd_clk = cell->parameters["\\RD_CLK_ENABLE"].extract(i).as_bool(); @@ -850,15 +851,22 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) // for clocked read ports make something like: // reg [..] temp_id; // always @(posedge clk) - // temp_id <= array_reg[r_addr]; + // 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)) + { + 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); - std::string line = stringf("%s <= %s[%s];\n", temp_id.c_str(), mem_id.c_str(), os.str().c_str()); - clk_to_lof_body[clk_domain_str].push_back(line); + os << stringf("];\n"); + clk_to_lof_body[clk_domain_str].push_back(os.str()); } { std::ostringstream os; @@ -900,13 +908,9 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) } int nwrite_ports = cell->parameters["\\WR_PORTS"].as_int(); - RTLIL::SigSpec sig_wr_clk, sig_wr_data, sig_wr_addr, sig_wr_en, sig_wr_en_bit; - RTLIL::SigBit last_bit; + RTLIL::SigSpec sig_wr_clk, sig_wr_data, sig_wr_addr, sig_wr_en; bool wr_clk_posedge; - RTLIL::SigSpec lof_wen; - dict<RTLIL::SigSpec, int> wen_to_width; SigMap sigmap(active_module); - int n, wen_width; // write ports for (int i=0; i < nwrite_ports; i++) { @@ -914,7 +918,6 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) sig_wr_data = cell->getPort("\\WR_DATA").extract(i*width, width); sig_wr_addr = cell->getPort("\\WR_ADDR").extract(i*abits, abits); sig_wr_en = cell->getPort("\\WR_EN").extract(i*width, width); - sig_wr_en_bit = sig_wr_en.extract(0); wr_clk_posedge = cell->parameters["\\WR_CLK_POLARITY"].extract(i).as_bool(); { std::ostringstream os; @@ -923,48 +926,37 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) if( clk_to_lof_body.count(clk_domain_str) == 0 ) clk_to_lof_body[clk_domain_str] = std::vector<std::string>(); } - // group the wen bits - last_bit = sig_wr_en.extract(0); - lof_wen = RTLIL::SigSpec(last_bit); - wen_to_width.clear(); - wen_to_width[last_bit] = 0; - for (auto ¤t_bit : sig_wr_en.bits()) - { - if (sigmap(current_bit) == sigmap(last_bit)){ - wen_to_width[current_bit] += 1; - } else { - lof_wen.append_bit(current_bit); - wen_to_width[current_bit] = 1; - } - last_bit = current_bit; - } // make something like: // always @(posedge clk) // if (wr_en_bit) memid[w_addr][??] <= w_data[??]; // ... - n = 0; - for (auto &wen_bit : lof_wen) { - wen_width = wen_to_width[wen_bit]; - if (!(wen_bit == RTLIL::SigBit(false))) + for (int i = 0; i < GetSize(sig_wr_en); i++) + { + int start_i = i, width = 1; + SigBit wen_bit = sig_wr_en[i]; + + while (i+1 < GetSize(sig_wr_en) && sigmap(sig_wr_en[i+1]) == sigmap(wen_bit)) + i++, width++; + + if (wen_bit == State::S0) + continue; + + std::ostringstream os; + if (wen_bit != State::S1) { - std::ostringstream os; - if (!(wen_bit == RTLIL::SigBit(true))) - { - os << stringf("if ("); - dump_sigspec(os, wen_bit); - os << stringf(") "); - } - os << stringf("%s[", mem_id.c_str()); - dump_sigspec(os, sig_wr_addr); - if (wen_width == width) - os << stringf("] <= "); - else - os << stringf("][%d:%d] <= ", n+wen_width-1, n); - dump_sigspec(os, sig_wr_data.extract(n, wen_width)); - os << stringf(";\n"); - clk_to_lof_body[clk_domain_str].push_back(os.str()); + os << stringf("if ("); + dump_sigspec(os, wen_bit); + os << stringf(") "); } - n += wen_width; + os << stringf("%s[", mem_id.c_str()); + dump_sigspec(os, sig_wr_addr); + if (width == GetSize(sig_wr_en)) + os << stringf("] <= "); + else + os << stringf("][%d:%d] <= ", i, start_i); + dump_sigspec(os, sig_wr_data.extract(start_i, width)); + os << stringf(";\n"); + clk_to_lof_body[clk_domain_str].push_back(os.str()); } } // Output Verilog that looks something like this: @@ -1029,7 +1021,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) dump_attributes(f, indent, cell->attributes); f << stringf("%s" "%s", indent.c_str(), id(cell->type, false).c_str()); - if (cell->parameters.size() > 0) { + if (!defparam && cell->parameters.size() > 0) { f << stringf(" #("); for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) { if (it != cell->parameters.begin()) @@ -1079,6 +1071,16 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) f << stringf(")"); } f << stringf("\n%s" ");\n", indent.c_str()); + + if (defparam && cell->parameters.size() > 0) { + for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) { + f << stringf("%sdefparam %s.%s = ", indent.c_str(), cell_name.c_str(), id(it->first).c_str()); + bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0; + dump_const(f, it->second, -1, 0, false, is_signed); + f << stringf(";\n"); + } + } + } void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right) @@ -1135,11 +1137,15 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw dump_sigspec(f, sw->signal); f << stringf(")\n"); + bool got_default = false; for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) { - f << stringf("%s ", indent.c_str()); - if ((*it)->compare.size() == 0) - f << stringf("default"); - else { + if ((*it)->compare.size() == 0) { + if (got_default) + continue; + f << stringf("%s default", indent.c_str()); + got_default = true; + } else { + f << stringf("%s ", indent.c_str()); for (size_t i = 0; i < (*it)->compare.size(); i++) { if (i > 0) f << stringf(", "); @@ -1244,6 +1250,12 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module) reset_auto_counter(module); active_module = module; + if (!module->processes.empty()) + log_warning("Module %s contains unmapped RTLIL proccesses. 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)); + f << stringf("\n"); for (auto it = module->processes.begin(); it != module->processes.end(); ++it) dump_process(f, indent + " ", it->second, true); @@ -1340,6 +1352,21 @@ struct VerilogBackend : public Backend { log(" without this option all internal cells are converted to Verilog\n"); log(" expressions.\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(" 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(" as binary numbers.\n"); + log("\n"); + log(" -defparam\n"); + log(" Use 'defparam' statements instead of the Verilog-2001 syntax for\n"); + log(" cell parameters.\n"); + log("\n"); log(" -blackboxes\n"); log(" usually modules with the 'blackbox' attribute are ignored. with\n"); log(" this option set only the modules with the 'blackbox' attribute\n"); @@ -1349,15 +1376,24 @@ struct VerilogBackend : public Backend { log(" only write selected modules. modules must be selected entirely or\n"); log(" not at all.\n"); log("\n"); + log("Note that RTLIL processes can't always be mapped directly to Verilog\n"); + log("always blocks. This frontend should only be used to export an RTLIL\n"); + log("netlist, i.e. after the \"proc\" pass has been used to convert all\n"); + log("processes to logic networks and registers. A warning is generated when\n"); + 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) { - log_header("Executing Verilog backend.\n"); + log_header(design, "Executing Verilog backend.\n"); norename = false; noattr = false; attr2comment = false; noexpr = false; + nodec = false; + nostr = false; + defparam = false; bool blackboxes = false; bool selected = false; @@ -1407,6 +1443,18 @@ struct VerilogBackend : public Backend { noexpr = true; continue; } + if (arg == "-nodec") { + nodec = true; + continue; + } + if (arg == "-nostr") { + nostr = true; + continue; + } + if (arg == "-defparam") { + defparam = true; + continue; + } if (arg == "-blackboxes") { blackboxes = true; continue; diff --git a/examples/cmos/.gitignore b/examples/cmos/.gitignore new file mode 100644 index 00000000..f58d9501 --- /dev/null +++ b/examples/cmos/.gitignore @@ -0,0 +1,4 @@ +counter_tb +counter_tb.vcd +synth.sp +synth.v diff --git a/examples/cmos/README b/examples/cmos/README new file mode 100644 index 00000000..c459b4b5 --- /dev/null +++ b/examples/cmos/README @@ -0,0 +1,13 @@ + +In this directory contains an example for generating a spice output using two +different spice modes, normal analog transient simulation and event-driven +digital simulation as supported by ngspice xspice sub-module. + +Each test bench can be run separately by either running: + +- testbench.sh, to start analog simulation or +- testbench_digital.sh for mixed-signal digital simulation. + +The later case also includes pure verilog simulation using the iverilog +and gtkwave for comparison. + diff --git a/examples/cmos/cmos_cells_digital.sp b/examples/cmos/cmos_cells_digital.sp new file mode 100644 index 00000000..e1cb82a2 --- /dev/null +++ b/examples/cmos/cmos_cells_digital.sp @@ -0,0 +1,31 @@ + +.SUBCKT BUF A Y +.model buffer1 d_buffer +Abuf A Y buffer1 +.ENDS NOT + +.SUBCKT NOT A Y +.model not1 d_inverter +Anot A Y not1 +.ENDS NOT + +.SUBCKT NAND A B Y +.model nand1 d_nand +Anand [A B] Y nand1 +.ENDS NAND + +.SUBCKT NOR A B Y +.model nor1 d_nor +Anand [A B] Y nor1 +.ENDS NOR + +.SUBCKT DLATCH E D Q +.model latch1 d_latch +Alatch D E null null Q nQ latch1 +.ENDS DLATCH + +.SUBCKT DFF C D Q +.model dff1 d_dff +Adff D C null null Q nQ dff1 +.ENDS DFF + diff --git a/examples/cmos/counter_digital.ys b/examples/cmos/counter_digital.ys new file mode 100644 index 00000000..a5e728e0 --- /dev/null +++ b/examples/cmos/counter_digital.ys @@ -0,0 +1,16 @@ + +read_verilog counter.v +read_verilog -lib cmos_cells.v + +proc;; memory;; techmap;; + +dfflibmap -liberty cmos_cells.lib +abc -liberty cmos_cells.lib;; + +# http://vlsiarch.ecen.okstate.edu/flows/MOSIS_SCMOS/latest/cadence/lib/tsmc025/signalstorm/osu025_stdcells.lib +# dfflibmap -liberty osu025_stdcells.lib +# abc -liberty osu025_stdcells.lib;; + +write_verilog synth.v +write_spice -neg 0s -pos 1s synth.sp + diff --git a/examples/cmos/counter_tb.gtkw b/examples/cmos/counter_tb.gtkw new file mode 100644 index 00000000..4a2eac40 --- /dev/null +++ b/examples/cmos/counter_tb.gtkw @@ -0,0 +1,5 @@ +[dumpfile] "counter_tb.vcd" +counter_tb.clk +counter_tb.count[2:0] +counter_tb.en +counter_tb.reset diff --git a/examples/cmos/counter_tb.v b/examples/cmos/counter_tb.v new file mode 100644 index 00000000..bcd7d992 --- /dev/null +++ b/examples/cmos/counter_tb.v @@ -0,0 +1,33 @@ +module counter_tb; + + /* Make a reset pulse and specify dump file */ + reg reset = 0; + initial begin + $dumpfile("counter_tb.vcd"); + $dumpvars(0,counter_tb); + + # 0 reset = 1; + # 4 reset = 0; + # 36 reset = 1; + # 4 reset = 0; + # 6 $finish; + end + + /* Make enable with period of 8 and 6,7 low */ + reg en = 1; + always begin + en = 1; + #6; + en = 0; + #2; + end + + /* Make a regular pulsing clock. */ + reg clk = 0; + always #1 clk = !clk; + + /* UUT */ + wire [2:0] count; + counter c1 (clk, reset, en, count); + +endmodule diff --git a/examples/cmos/testbench.sp b/examples/cmos/testbench.sp index 95d2f67c..e571d281 100644 --- a/examples/cmos/testbench.sp +++ b/examples/cmos/testbench.sp @@ -9,8 +9,8 @@ Vdd Vdd 0 DC 3 .MODEL cmosp PMOS LEVEL=1 VT0=-0.7 KP=50U GAMMA=0.57 LAMBDA=0.05 PHI=0.8 * load design and library -.include synth.sp .include cmos_cells.sp +.include synth.sp * input signals Vclk clk 0 PULSE(0 3 1 0.1 0.1 0.8 2) diff --git a/examples/cmos/testbench_digital.sh b/examples/cmos/testbench_digital.sh new file mode 100644 index 00000000..afaaf4d4 --- /dev/null +++ b/examples/cmos/testbench_digital.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +set -ex + +# iverlog simulation +echo "Doing Verilog simulation with iverilog" +iverilog -o counter_tb counter.v counter_tb.v +./counter_tb; gtkwave counter_tb.gtkw & + +# yosys synthesis +../../yosys counter_digital.ys + +# requires ngspice with xspice support enabled: +ngspice testbench_digital.sp + diff --git a/examples/cmos/testbench_digital.sp b/examples/cmos/testbench_digital.sp new file mode 100644 index 00000000..c5f9d598 --- /dev/null +++ b/examples/cmos/testbench_digital.sp @@ -0,0 +1,26 @@ + +* load design and library +.include cmos_cells_digital.sp +.include synth.sp + +* input signals +Vclk clk 0 PULSE(0 3 1 0.1 0.1 0.8 2) +Vrst rst 0 PULSE(0 3 0.5 0.1 0.1 2.9 40) +Ven en 0 PULSE(0 3 0.5 0.1 0.1 5.9 8) + +Xuut dclk drst den dout0 dout1 dout2 counter +* Bridge to digital +.model adc_buff adc_bridge(in_low = 0.8 in_high=2) +.model dac_buff dac_bridge(out_high = 3.5) +Aad [clk rst en] [dclk drst den] adc_buff +Ada [dout0 dout1 dout2] [out0 out1 out2] dac_buff + + +.tran 0.01 50 + +.control +run +plot v(clk) v(rst)+5 v(en)+10 v(out0)+20 v(out1)+25 v(out2)+30 +.endc + +.end diff --git a/examples/cxx-api/evaldemo.cc b/examples/cxx-api/evaldemo.cc new file mode 100644 index 00000000..e5cc8d8e --- /dev/null +++ b/examples/cxx-api/evaldemo.cc @@ -0,0 +1,55 @@ +/* A simple Yosys plugin. (Copy&paste from http://stackoverflow.com/questions/32093541/how-does-the-yosys-consteval-api-work) + +Usage example: + +$ cat > evaldemo.v <<EOT +module main(input [1:0] A, input [7:0] B, C, D, output [7:0] Y); + assign Y = A == 0 ? B : A == 1 ? C : A == 2 ? D : 42; +endmodule +EOT + +$ yosys-config --build evaldemo.so evaldemo.cc +$ yosys -m evaldemo.so -p evaldemo evaldemo.v +*/ + +#include "kernel/yosys.h" +#include "kernel/consteval.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct EvalDemoPass : public Pass +{ + EvalDemoPass() : Pass("evaldemo") { } + + virtual void execute(vector<string>, Design *design) + { + Module *module = design->top_module(); + + if (module == nullptr) + log_error("No top module found!\n"); + + Wire *wire_a = module->wire("\\A"); + Wire *wire_y = module->wire("\\Y"); + + if (wire_a == nullptr) + log_error("No wire A found!\n"); + + if (wire_y == nullptr) + log_error("No wire Y found!\n"); + + ConstEval ce(module); + for (int v = 0; v < 4; v++) { + ce.push(); + ce.set(wire_a, Const(v, GetSize(wire_a))); + SigSpec sig_y = wire_y, sig_undef; + if (ce.eval(sig_y, sig_undef)) + log("Eval results for A=%d: Y=%s\n", v, log_signal(sig_y)); + else + log("Eval failed for A=%d: Missing value for %s\n", v, log_signal(sig_undef)); + ce.pop(); + } + } +} EvalDemoPass; + +PRIVATE_NAMESPACE_END diff --git a/examples/smtbmc/.gitignore b/examples/smtbmc/.gitignore new file mode 100644 index 00000000..a3f4f0f2 --- /dev/null +++ b/examples/smtbmc/.gitignore @@ -0,0 +1,22 @@ +demo1.smt2 +demo1.yslog +demo2.smt2 +demo2.smtc +demo2.vcd +demo2.yslog +demo2_tb +demo2_tb.v +demo2_tb.vcd +demo3.smt2 +demo3.vcd +demo3.yslog +demo4.smt2 +demo4.vcd +demo4.yslog +demo5.smt2 +demo5.vcd +demo5.yslog +demo6.smt2 +demo6.yslog +demo7.smt2 +demo7.yslog diff --git a/examples/smtbmc/Makefile b/examples/smtbmc/Makefile new file mode 100644 index 00000000..2f7060bd --- /dev/null +++ b/examples/smtbmc/Makefile @@ -0,0 +1,59 @@ + +all: demo1 demo2 demo3 demo4 demo5 demo6 demo7 + +demo1: demo1.smt2 + yosys-smtbmc --dump-vcd demo1.vcd demo1.smt2 + yosys-smtbmc -i --dump-vcd demo1.vcd demo1.smt2 + +demo2: demo2.smt2 + yosys-smtbmc -g --dump-vcd demo2.vcd --dump-smtc demo2.smtc --dump-vlogtb demo2_tb.v demo2.smt2 + iverilog -g2012 -o demo2_tb demo2_tb.v demo2.v + vvp demo2_tb +vcd=demo2_tb.vcd + +demo3: demo3.smt2 + yosys-smtbmc --dump-vcd demo3.vcd --smtc demo3.smtc demo3.smt2 + +demo4: demo4.smt2 + yosys-smtbmc -s yices --dump-vcd demo4.vcd --smtc demo4.smtc demo4.smt2 + +demo5: demo5.smt2 + yosys-smtbmc -g -t 50 --dump-vcd demo5.vcd demo5.smt2 + +demo6: demo6.smt2 + yosys-smtbmc -t 1 demo6.smt2 + +demo7: demo7.smt2 + yosys-smtbmc -t 10 demo7.smt2 + +demo1.smt2: demo1.v + yosys -ql demo1.yslog -p 'read_verilog -formal demo1.v; prep -top demo1 -nordff; write_smt2 -wires demo1.smt2' + +demo2.smt2: demo2.v + yosys -ql demo2.yslog -p 'read_verilog -formal demo2.v; prep -top demo2 -nordff; write_smt2 -wires demo2.smt2' + +demo3.smt2: demo3.v + yosys -ql demo3.yslog -p 'read_verilog -formal demo3.v; prep -top demo3 -nordff; write_smt2 -wires demo3.smt2' + +demo4.smt2: demo4.v + yosys -ql demo4.yslog -p 'read_verilog -formal demo4.v; prep -top demo4 -nordff; write_smt2 -wires demo4.smt2' + +demo5.smt2: demo5.v + yosys -ql demo5.yslog -p 'read_verilog -formal demo5.v; prep -top demo5 -nordff; write_smt2 -wires demo5.smt2' + +demo6.smt2: demo6.v + yosys -ql demo6.yslog -p 'read_verilog demo6.v; prep -top demo6 -nordff; assertpmux; opt -keepdc -fast; write_smt2 -wires demo6.smt2' + +demo7.smt2: demo7.v + yosys -ql demo7.yslog -p 'read_verilog -formal demo7.v; prep -top demo7 -nordff; write_smt2 -wires demo7.smt2' + +clean: + rm -f demo1.yslog demo1.smt2 demo1.vcd + rm -f demo2.yslog demo2.smt2 demo2.vcd demo2.smtc demo2_tb.v demo2_tb demo2_tb.vcd + rm -f demo3.yslog demo3.smt2 demo3.vcd + rm -f demo4.yslog demo4.smt2 demo4.vcd + rm -f demo5.yslog demo5.smt2 demo5.vcd + rm -f demo6.yslog demo6.smt2 + rm -f demo7.yslog demo7.smt2 + +.PHONY: demo1 demo2 demo3 demo4 demo5 demo6 demo7 clean + diff --git a/examples/smtbmc/demo1.v b/examples/smtbmc/demo1.v new file mode 100644 index 00000000..567dde14 --- /dev/null +++ b/examples/smtbmc/demo1.v @@ -0,0 +1,19 @@ +module demo1(input clk, input addtwo, output iseven); + reg [3:0] cnt; + wire [3:0] next_cnt; + + inc inc_inst (addtwo, iseven, cnt, next_cnt); + + always @(posedge clk) + cnt = (iseven ? cnt == 10 : cnt == 11) ? 0 : next_cnt; + +`ifdef FORMAL + assert property (cnt != 15); + initial assume (!cnt[2]); +`endif +endmodule + +module inc(input addtwo, output iseven, input [3:0] a, output [3:0] y); + assign iseven = !a[0]; + assign y = a + (addtwo ? 2 : 1); +endmodule diff --git a/examples/smtbmc/demo2.v b/examples/smtbmc/demo2.v new file mode 100644 index 00000000..34745e89 --- /dev/null +++ b/examples/smtbmc/demo2.v @@ -0,0 +1,29 @@ +// Nothing to prove in this demo. +// Just an example for memories, vcd dumps and vlog testbench dumps. + +`ifdef FORMAL +`define assume(_expr_) assume(_expr_) +`else +`define assume(_expr_) +`endif + +module demo2(input clk, input [4:0] addr, output reg [31:0] data); + reg [31:0] mem [0:31]; + always @(posedge clk) + data <= mem[addr]; + + reg [31:0] used_addr = 0; + reg [31:0] used_dbits = 0; + reg initstate = 1; + + always @(posedge clk) begin + initstate <= 0; + `assume(!used_addr[addr]); + used_addr[addr] <= 1; + if (!initstate) begin + `assume(data != 0); + `assume((used_dbits & data) == 0); + used_dbits <= used_dbits | data; + end + end +endmodule diff --git a/examples/smtbmc/demo3.smtc b/examples/smtbmc/demo3.smtc new file mode 100644 index 00000000..f5e017cf --- /dev/null +++ b/examples/smtbmc/demo3.smtc @@ -0,0 +1,5 @@ +initial +assume [rst] + +always -1 +assert (= [-1:mem] [mem]) diff --git a/examples/smtbmc/demo3.v b/examples/smtbmc/demo3.v new file mode 100644 index 00000000..13b3a197 --- /dev/null +++ b/examples/smtbmc/demo3.v @@ -0,0 +1,18 @@ +// Whatever the initial content of this memory is at reset, it will never change +// see demo3.smtc for assumptions and assertions + +module demo3(input clk, rst, input [15:0] addr, output reg [31:0] data); + reg [31:0] mem [0:2**16-1]; + reg [15:0] addr_q; + + always @(posedge clk) begin + if (rst) begin + data <= mem[0] ^ 123456789; + addr_q <= 0; + end else begin + mem[addr_q] <= data ^ 123456789; + data <= mem[addr] ^ 123456789; + addr_q <= addr; + end + end +endmodule diff --git a/examples/smtbmc/demo4.smtc b/examples/smtbmc/demo4.smtc new file mode 100644 index 00000000..2f91f816 --- /dev/null +++ b/examples/smtbmc/demo4.smtc @@ -0,0 +1,11 @@ +initial +assume [rst] + +always -1 +assume (not [rst]) +assume (=> [-1:inv2] [inv2]) + +final -2 +assume [-1:inv2] +assume (not [-2:inv2]) +assert (= [r1] [r2]) diff --git a/examples/smtbmc/demo4.v b/examples/smtbmc/demo4.v new file mode 100644 index 00000000..3f1b4727 --- /dev/null +++ b/examples/smtbmc/demo4.v @@ -0,0 +1,13 @@ +// Demo for "final" smtc constraints + +module demo4(input clk, rst, inv2, input [15:0] in, output reg [15:0] r1, r2); + always @(posedge clk) begin + if (rst) begin + r1 <= in; + r2 <= -in; + end else begin + r1 <= r1 + in; + r2 <= inv2 ? -(r2 - in) : (r2 - in); + end + end +endmodule diff --git a/examples/smtbmc/demo5.v b/examples/smtbmc/demo5.v new file mode 100644 index 00000000..63ace307 --- /dev/null +++ b/examples/smtbmc/demo5.v @@ -0,0 +1,18 @@ +// Demo for $anyconst + +module demo5 (input clk); + wire [7:0] step_size = $anyconst; + reg [7:0] state = 0, count = 0; + reg [31:0] hash = 0; + + always @(posedge clk) begin + count <= count + 1; + hash <= ((hash << 5) + hash) ^ state; + state <= state + step_size; + end + + always @* begin + if (count == 42) + assert(hash == 32'h A18FAC0A); + end +endmodule diff --git a/examples/smtbmc/demo6.v b/examples/smtbmc/demo6.v new file mode 100644 index 00000000..62a72e2a --- /dev/null +++ b/examples/smtbmc/demo6.v @@ -0,0 +1,14 @@ +// Demo for assertpmux + +module demo6 (input A, B, C, D, E, output reg Y); + always @* begin + Y = 0; + if (A != B) begin + (* parallel_case *) + case (C) + A: Y = D; + B: Y = E; + endcase + end + end +endmodule diff --git a/examples/smtbmc/demo7.v b/examples/smtbmc/demo7.v new file mode 100644 index 00000000..75b3865c --- /dev/null +++ b/examples/smtbmc/demo7.v @@ -0,0 +1,18 @@ +// Demo for memory initialization + +module demo7 (input [2:0] addr); + reg [15:0] memory [0:7]; + + initial begin + memory[0] = 1331; + memory[1] = 1331 + 1; + memory[2] = 1331 + 2; + memory[3] = 1331 + 4; + memory[4] = 1331 + 8; + memory[5] = 1331 + 16; + memory[6] = 1331 + 32; + memory[7] = 1331 + 64; + end + + assert property (1000 < memory[addr] && memory[addr] < 2000); +endmodule diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 834ee82a..fd272400 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -30,15 +30,6 @@ #include "libs/sha1/sha1.h" #include "ast.h" -#include <sstream> -#include <stdarg.h> - -#if defined(__APPLE__) -# include <cmath> -#else -# include <math.h> -#endif - YOSYS_NAMESPACE_BEGIN using namespace AST; @@ -53,13 +44,15 @@ namespace AST { // instanciate global variables (private API) namespace AST_INTERNAL { - bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire; + bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, 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; const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL; RTLIL::SigSpec ignoreThisSignalsInInitial; AstNode *current_always, *current_top_block, *current_block, *current_block_child; AstModule *current_module; + bool current_always_clocked; } // convert node types to string @@ -146,6 +139,8 @@ std::string AST::type2str(AstNodeType type) X(AST_ASSIGN_LE) X(AST_CASE) X(AST_COND) + X(AST_CONDX) + X(AST_CONDZ) X(AST_DEFAULT) X(AST_FOR) X(AST_WHILE) @@ -158,6 +153,7 @@ std::string AST::type2str(AstNodeType type) X(AST_POSEDGE) X(AST_NEGEDGE) X(AST_EDGE) + X(AST_PACKAGE) #undef X default: log_abort(); @@ -180,7 +176,7 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id) // create new node (AstNode constructor) // (the optional child arguments make it easier to create AST trees) -AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2) +AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *child3) { static unsigned int hashidx_count = 123456789; hashidx_count = mkhash_xorshift(hashidx_count); @@ -208,6 +204,8 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2) children.push_back(child1); if (child2) children.push_back(child2); + if (child3) + children.push_back(child3); } // create a (deep recursive) copy of a node @@ -311,6 +309,8 @@ void AstNode::dumpAst(FILE *f, std::string indent) for (size_t i = 0; i < children.size(); i++) children[i]->dumpAst(f, indent + " "); + + fflush(f); } // helper function for AstNode::dumpVlog() @@ -435,16 +435,15 @@ void AstNode::dumpVlog(FILE *f, std::string indent) break; case AST_ALWAYS: - fprintf(f, "%s" "always @(", indent.c_str()); + fprintf(f, "%s" "always @", indent.c_str()); for (auto child : children) { if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE) continue; - if (!first) - fprintf(f, ", "); + fprintf(f, first ? "(" : ", "); child->dumpVlog(f, ""); first = false; } - fprintf(f, ")\n"); + fprintf(f, first ? "*\n" : ")\n"); for (auto child : children) { if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE) child->dumpVlog(f, indent + " "); @@ -501,7 +500,12 @@ void AstNode::dumpVlog(FILE *f, std::string indent) break; case AST_CASE: - fprintf(f, "%s" "case (", indent.c_str()); + if (!children.empty() && children[0]->type == AST_CONDX) + fprintf(f, "%s" "casex (", indent.c_str()); + else if (!children.empty() && children[0]->type == AST_CONDZ) + fprintf(f, "%s" "casez (", indent.c_str()); + else + fprintf(f, "%s" "case (", indent.c_str()); children[0]->dumpVlog(f, ""); fprintf(f, ")\n"); for (size_t i = 1; i < children.size(); i++) { @@ -512,6 +516,8 @@ void AstNode::dumpVlog(FILE *f, std::string indent) break; case AST_COND: + case AST_CONDX: + case AST_CONDZ: for (auto child : children) { if (child->type == AST_BLOCK) { fprintf(f, ":\n"); @@ -528,6 +534,14 @@ void AstNode::dumpVlog(FILE *f, std::string indent) } break; + case AST_ASSIGN: + fprintf(f, "%sassign ", indent.c_str()); + children[0]->dumpVlog(f, ""); + fprintf(f, " = "); + children[1]->dumpVlog(f, ""); + fprintf(f, ";\n"); + break; + case AST_ASSIGN_EQ: case AST_ASSIGN_LE: fprintf(f, "%s", indent.c_str()); @@ -616,6 +630,8 @@ void AstNode::dumpVlog(FILE *f, std::string indent) fprintf(f, "%s" "/** %s **/%s", indent.c_str(), type_name.c_str(), indent.empty() ? "" : "\n"); // dumpAst(f, indent, NULL); } + + fflush(f); } // check if two AST nodes are identical @@ -967,16 +983,25 @@ static AstModule* process_module(AstNode *ast, bool defer) current_module->icells = flag_icells; current_module->autowire = flag_autowire; current_module->fixup_ports(); + + if (flag_dump_rtlil) { + log("Dumping generated RTLIL:\n"); + log_module(current_module); + log("--- END OF RTLIL DUMP ---\n"); + } + return current_module; } // 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 nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire) +void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool dump_rtlil, + bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire) { current_ast = ast; flag_dump_ast1 = dump_ast1; flag_dump_ast2 = dump_ast2; flag_dump_vlog = dump_vlog; + flag_dump_rtlil = dump_rtlil; flag_nolatches = nolatches; flag_nomeminit = nomeminit; flag_nomem2reg = nomem2reg; @@ -996,6 +1021,14 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump for (auto n : global_decls) (*it)->children.push_back(n->clone()); + for (auto n : design->verilog_packages){ + for (auto o : n->children) { + AstNode *cloned_node = o->clone(); + cloned_node->str = n->str + std::string("::") + cloned_node->str.substr(1); + (*it)->children.push_back(cloned_node); + } + } + if (flag_icells && (*it)->str.substr(0, 2) == "\\$") (*it)->str = (*it)->str.substr(1); @@ -1013,6 +1046,8 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump design->add(process_module(*it, defer)); } + else if ((*it)->type == AST_PACKAGE) + design->verilog_packages.push_back((*it)->clone()); else global_decls.push_back(*it); } @@ -1033,7 +1068,7 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, R if (stripped_name.substr(0, 9) == "$abstract") stripped_name = stripped_name.substr(9); - log_header("Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", stripped_name.c_str()); + log_header(design, "Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", stripped_name.c_str()); current_ast = NULL; flag_dump_ast1 = false; diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index b5349db5..cd6e264e 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -122,6 +122,8 @@ namespace AST AST_ASSIGN_LE, AST_CASE, AST_COND, + AST_CONDX, + AST_CONDZ, AST_DEFAULT, AST_FOR, AST_WHILE, @@ -135,7 +137,9 @@ namespace AST AST_POSEDGE, AST_NEGEDGE, - AST_EDGE + AST_EDGE, + + AST_PACKAGE }; // convert an node type to a string (e.g. for debug output) @@ -182,7 +186,7 @@ namespace AST int linenum; // creating and deleting nodes - AstNode(AstNodeType type = AST_NONE, AstNode *child1 = NULL, AstNode *child2 = NULL); + AstNode(AstNodeType type = AST_NONE, AstNode *child1 = NULL, AstNode *child2 = NULL, AstNode *child3 = NULL); AstNode *clone(); void cloneInto(AstNode *other); void delete_children(); @@ -215,8 +219,9 @@ namespace AST void replace_ids(const std::string &prefix, const std::map<std::string, std::string> &rules); void mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places, dict<AstNode*, uint32_t> &mem2reg_flags, dict<AstNode*, uint32_t> &proc_flags, uint32_t &status_flags); - bool mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block); + bool mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block, AstNode *&async_block); bool mem2reg_check(pool<AstNode*> &mem2reg_set); + void mem2reg_remove(pool<AstNode*> &mem2reg_set, vector<AstNode*> &delnodes); void meminfo(int &mem_width, int &mem_size, int &addr_bits); // additional functionality for evaluating constant functions @@ -266,7 +271,8 @@ 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 nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire); + void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool dump_rtlil, bool nolatches, bool nomeminit, + bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire); // parametric modules are supported directly by the AST library // therefore we need our own derivate of RTLIL::Module with overloaded virtual functions @@ -296,13 +302,15 @@ namespace AST namespace AST_INTERNAL { // internal state variables - extern bool flag_dump_ast1, flag_dump_ast2, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire; + extern bool flag_dump_ast1, flag_dump_ast2, 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; extern const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr; extern RTLIL::SigSpec ignoreThisSignalsInInitial; extern AST::AstNode *current_always, *current_top_block, *current_block, *current_block_child; extern AST::AstModule *current_module; + extern bool current_always_clocked; struct ProcessGenerator; } diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 9fc59037..3c57162a 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -241,6 +241,8 @@ struct AST_INTERNAL::ProcessGenerator 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); addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to, true); proc->syncs.push_back(syncrule); } @@ -338,12 +340,14 @@ struct AST_INTERNAL::ProcessGenerator case AST_CASE: for (auto child : ast->children) if (child != ast->children[0]) { - log_assert(child->type == AST_COND); + log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ); collect_lvalues(reg, child, type_eq, type_le, false); } break; case AST_COND: + case AST_CONDX: + case AST_CONDZ: case AST_ALWAYS: case AST_INITIAL: for (auto child : ast->children) @@ -427,6 +431,17 @@ struct AST_INTERNAL::ProcessGenerator { RTLIL::SigSpec unmapped_lvalue = ast->children[0]->genRTLIL(), lvalue = unmapped_lvalue; RTLIL::SigSpec rvalue = ast->children[1]->genWidthRTLIL(lvalue.size(), &subst_rvalue_map.stdmap()); + + pool<SigBit> lvalue_sigbits; + for (int i = 0; i < GetSize(lvalue); i++) { + if (lvalue_sigbits.count(lvalue[i]) > 0) { + unmapped_lvalue.remove(i); + lvalue.remove(i); + rvalue.remove(i--); + } else + lvalue_sigbits.insert(lvalue[i]); + } + lvalue.replace(subst_lvalue_map.stdmap()); if (ast->type == AST_ASSIGN_EQ) { @@ -443,6 +458,7 @@ struct AST_INTERNAL::ProcessGenerator case AST_CASE: { RTLIL::SwitchRule *sw = new RTLIL::SwitchRule; + sw->attributes["\\src"] = stringf("%s:%d", ast->filename.c_str(), ast->linenum); sw->signal = ast->children[0]->genWidthRTLIL(-1, &subst_rvalue_map.stdmap()); current_case->switches.push_back(sw); @@ -467,7 +483,7 @@ struct AST_INTERNAL::ProcessGenerator { if (child == ast->children[0]) continue; - log_assert(child->type == AST_COND); + log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ); subst_lvalue_map.save(); subst_rvalue_map.save(); @@ -525,6 +541,7 @@ struct AST_INTERNAL::ProcessGenerator log_error("Found parameter declaration in block without label at at %s:%d!\n", ast->filename.c_str(), ast->linenum); break; + case AST_NONE: case AST_TCALL: case AST_FOR: break; @@ -589,7 +606,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 with of signal access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); + log_error("Failed to detect width of signal access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); } } else { this_width = id_ast->range_left - id_ast->range_right + 1; @@ -600,7 +617,7 @@ 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 with of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); + log_error("Failed to detect width of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); 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); @@ -732,11 +749,34 @@ 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 with of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); + log_error("Failed to detect width of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); this_width = id2ast->children[0]->range_left - id2ast->children[0]->range_right + 1; width_hint = max(width_hint, this_width); break; + case AST_FCALL: + if (str == "\\$anyconst") { + 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); + width_hint = max(width_hint, int(children[0]->asInt(true))); + } + break; + } + if (str == "\\$past") { + if (GetSize(children) > 0) { + sub_width_hint = 0; + sub_sign_hint = true; + children.at(0)->detectSignWidthWorker(sub_width_hint, sub_sign_hint); + width_hint = max(width_hint, sub_width_hint); + sign_hint = false; + } + break; + } + /* fall through */ + // everything should have been handled above -> print error if not. default: for (auto f : log_files) @@ -782,6 +822,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // simply ignore this nodes. // they are either leftovers from simplify() or are referenced by other nodes // and are only accessed here thru this references + case AST_NONE: case AST_TASK: case AST_FUNCTION: case AST_DPI_FUNCTION: @@ -793,6 +834,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) case AST_GENBLOCK: case AST_GENIF: case AST_GENCASE: + case AST_PACKAGE: break; // remember the parameter, needed for example in techmap @@ -1224,13 +1266,15 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) int mem_width, mem_size, addr_bits; id2ast->meminfo(mem_width, mem_size, addr_bits); + RTLIL::SigSpec addr_sig = children[0]->genRTLIL(); + cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1)); cell->setPort("\\EN", RTLIL::SigSpec(RTLIL::State::Sx, 1)); - cell->setPort("\\ADDR", children[0]->genWidthRTLIL(addr_bits)); + cell->setPort("\\ADDR", addr_sig); cell->setPort("\\DATA", RTLIL::SigSpec(wire)); cell->parameters["\\MEMID"] = RTLIL::Const(str); - cell->parameters["\\ABITS"] = RTLIL::Const(addr_bits); + cell->parameters["\\ABITS"] = RTLIL::Const(GetSize(addr_sig)); cell->parameters["\\WIDTH"] = RTLIL::Const(wire->width); cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(0); @@ -1261,11 +1305,13 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) cell->parameters["\\WORDS"] = RTLIL::Const(num_words); } - cell->setPort("\\ADDR", children[0]->genWidthRTLIL(addr_bits)); + SigSpec addr_sig = children[0]->genRTLIL(); + + cell->setPort("\\ADDR", addr_sig); cell->setPort("\\DATA", children[1]->genWidthRTLIL(current_module->memories[str]->width * num_words)); cell->parameters["\\MEMID"] = RTLIL::Const(str); - cell->parameters["\\ABITS"] = RTLIL::Const(addr_bits); + cell->parameters["\\ABITS"] = RTLIL::Const(GetSize(addr_sig)); cell->parameters["\\WIDTH"] = RTLIL::Const(current_module->memories[str]->width); if (type == AST_MEMWR) { @@ -1283,6 +1329,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) case AST_ASSERT: case AST_ASSUME: { + const char *celltype = "$assert"; + if (type == AST_ASSUME) celltype = "$assume"; + log_assert(children.size() == 2); RTLIL::SigSpec check = children[0]->genRTLIL(); @@ -1294,9 +1343,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) en = current_module->ReduceBool(NEW_ID, en); std::stringstream sstr; - sstr << (type == AST_ASSERT ? "$assert$" : "$assume$") << filename << ":" << linenum << "$" << (autoidx++); + sstr << celltype << "$" << filename << ":" << linenum << "$" << (autoidx++); - RTLIL::Cell *cell = current_module->addCell(sstr.str(), type == AST_ASSERT ? "$assert" : "$assume"); + RTLIL::Cell *cell = current_module->addCell(sstr.str(), celltype); cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); for (auto &attr : attributes) { @@ -1408,6 +1457,40 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) delete always; } break; + case AST_FCALL: { + if (str == "\\$anyconst") + { + string myid = stringf("%s$%d", str.c_str() + 1, autoidx++); + 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); + + 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); + 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); + + Cell *cell = current_module->addCell(myid, str.substr(1)); + cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); + cell->parameters["\\WIDTH"] = width; + + Wire *wire = current_module->addWire(myid + "_wire", width); + wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); + cell->setPort("\\Y", wire); + + is_signed = sign_hint; + return SigSpec(wire); + } + } /* fall through */ + // everything should have been handled above -> print error if not. default: for (auto f : log_files) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 2621be49..57aa648c 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -63,7 +63,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, #if 0 log("-------------\n"); - log("AST simplify[%d] depth %d at %s:%d,\n", stage, recursion_counter, filename.c_str(), linenum); + log("AST simplify[%d] depth %d at %s:%d on %s %p:\n", stage, recursion_counter, filename.c_str(), linenum, type2str(type).c_str(), this); log("const_fold=%d, at_zero=%d, in_lvalue=%d, stage=%d, width_hint=%d, sign_hint=%d, in_param=%d\n", int(const_fold), int(at_zero), int(in_lvalue), int(stage), int(width_hint), int(sign_hint), int(in_param)); // dumpAst(NULL, "> "); @@ -148,14 +148,14 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } } - while (mem2reg_as_needed_pass2(mem2reg_set, this, NULL)) { } + AstNode *async_block = NULL; + while (mem2reg_as_needed_pass2(mem2reg_set, this, NULL, async_block)) { } - for (size_t i = 0; i < children.size(); i++) { - if (mem2reg_set.count(children[i]) > 0) { - delete children[i]; - children.erase(children.begin() + (i--)); - } - } + vector<AstNode*> delnodes; + mem2reg_remove(mem2reg_set, delnodes); + + for (auto node : delnodes) + delete node; } while (simplify(const_fold, at_zero, in_lvalue, 2, width_hint, sign_hint, in_param)) { } @@ -174,8 +174,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } // deactivate all calls to non-synthesis system tasks - // note that $display and $finish are used for synthesis-time DRC so they're not in this list - if ((type == AST_FCALL || type == AST_TCALL) && (str == "$strobe" || str == "$monitor" || str == "$time" || str == "$stop" || + // note that $display, $finish, and $stop are used for synthesis-time DRC so they're not in this list + if ((type == AST_FCALL || type == AST_TCALL) && (str == "$strobe" || str == "$monitor" || str == "$time" || str == "$dumpfile" || str == "$dumpvars" || str == "$dumpon" || str == "$dumpoff" || str == "$dumpall")) { log_warning("Ignoring call to system %s %s at %s:%d.\n", type == AST_FCALL ? "function" : "task", str.c_str(), filename.c_str(), linenum); delete_children(); @@ -193,13 +193,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, // but should be good enough for most uses if ((type == AST_TCALL) && ((str == "$display") || (str == "$write"))) { - size_t nargs = GetSize(children); - if(nargs < 1) + int nargs = GetSize(children); + if (nargs < 1) log_error("System task `%s' got %d arguments, expected >= 1 at %s:%d.\n", str.c_str(), int(children.size()), filename.c_str(), linenum); // First argument is the format string - AstNode *node_string = children[0]->clone(); + AstNode *node_string = children[0]; while (node_string->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } if (node_string->type != AST_CONSTANT) log_error("Failed to evaluate system task `%s' with non-constant 1st argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum); @@ -207,37 +207,57 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, // Other arguments are placeholders. Process the string as we go through it std::string sout; - size_t next_arg = 1; - for(size_t i=0; i<sformat.length(); i++) + int next_arg = 1; + for (size_t i = 0; i < sformat.length(); i++) { // format specifier - if(sformat[i] == '%') + if (sformat[i] == '%') { // If there's no next character, that's a problem - if(i+1 >= sformat.length()) + if (i+1 >= sformat.length()) log_error("System task `%s' called with `%%' at end of string at %s:%d.\n", str.c_str(), filename.c_str(), linenum); char cformat = sformat[++i]; // %% is special, does not need a matching argument - if(cformat == '%') + if (cformat == '%') { sout += '%'; continue; } - // If we're out of arguments, that's a problem! - if(next_arg >= nargs) - log_error("System task `%s' called with more format specifiers than arguments at %s:%d.\n", str.c_str(), filename.c_str(), linenum); - // Simplify the argument - AstNode *node_arg = children[next_arg ++]->clone(); - while (node_arg->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } - if (node_arg->type != AST_CONSTANT) - log_error("Failed to evaluate system task `%s' with non-constant argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + AstNode *node_arg = nullptr; // Everything from here on depends on the format specifier - switch(cformat) + switch (cformat) + { + case 's': + case 'S': + case 'd': + case 'D': + case 'x': + case 'X': + if (next_arg >= GetSize(children)) + log_error("Missing argument for %%%c format specifier in system task `%s' at %s:%d.\n", + cformat, str.c_str(), filename.c_str(), linenum); + + node_arg = children[next_arg++]; + while (node_arg->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } + if (node_arg->type != AST_CONSTANT) + log_error("Failed to evaluate system task `%s' with non-constant argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + break; + + case 'm': + case 'M': + break; + + default: + log_error("System task `%s' called with invalid/unsupported format specifier at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + break; + } + + switch (cformat) { case 's': case 'S': @@ -262,9 +282,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } break; - default: - log_error("System task `%s' called with invalid format specifier at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + case 'm': + case 'M': + sout += log_id(current_module->name); break; + + default: + log_abort(); } } @@ -275,7 +299,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, // Finally, print the message (only include a \n for $display, not for $write) log("%s", sout.c_str()); - if(str == "$display") + if (str == "$display") log("\n"); delete_children(); str = std::string(); @@ -373,9 +397,18 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, auto backup_current_block_child = current_block_child; auto backup_current_top_block = current_top_block; auto backup_current_always = current_always; + auto backup_current_always_clocked = current_always_clocked; if (type == AST_ALWAYS || type == AST_INITIAL) + { current_always = this; + current_always_clocked = false; + + if (type == AST_ALWAYS) + for (auto child : children) + if (child->type == AST_POSEDGE || child->type == AST_NEGEDGE) + current_always_clocked = true; + } int backup_width_hint = width_hint; bool backup_sign_hint = sign_hint; @@ -489,6 +522,11 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, children_are_self_determined = true; break; + case AST_FCALL: + case AST_TCALL: + children_are_self_determined = true; + break; + default: width_hint = -1; sign_hint = false; @@ -504,6 +542,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, detectSignWidth(width_hint, sign_hint); } + if (type == AST_FCALL && str == "\\$past") + detectSignWidth(width_hint, sign_hint); + if (type == AST_TERNARY) { int width_hint_left, width_hint_right; bool sign_hint_left, sign_hint_right; @@ -516,6 +557,18 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } } + if (type == AST_CONDX && children.size() > 0 && children.at(0)->type == AST_CONSTANT) { + for (auto &bit : children.at(0)->bits) + if (bit == State::Sz || bit == State::Sx) + bit = State::Sa; + } + + if (type == AST_CONDZ && children.size() > 0 && children.at(0)->type == AST_CONSTANT) { + for (auto &bit : children.at(0)->bits) + if (bit == State::Sz) + bit = State::Sa; + } + if (const_fold && type == AST_CASE) { while (children[0]->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) { } @@ -524,7 +577,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, new_children.push_back(children[0]); for (int i = 1; i < GetSize(children); i++) { AstNode *child = children[i]; - log_assert(child->type == AST_COND); + log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ); for (auto v : child->children) { if (v->type == AST_DEFAULT) goto keep_const_cond; @@ -616,6 +669,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, current_block_child = backup_current_block_child; current_top_block = backup_current_top_block; current_always = backup_current_always; + current_always_clocked = backup_current_always_clocked; for (auto it = backup_scope.begin(); it != backup_scope.end(); it++) { if (it->second == NULL) @@ -794,7 +848,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, RTLIL::SigSpec sig(children[0]->bits); sig.extend_u0(width, children[0]->is_signed); AstNode *old_child_0 = children[0]; - children[0] = mkconst_bits(sig.as_const().bits, children[0]->is_signed); + children[0] = mkconst_bits(sig.as_const().bits, is_signed); delete old_child_0; } children[0]->is_signed = is_signed; @@ -847,11 +901,14 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int mem_width, mem_size, addr_bits; id2ast->meminfo(mem_width, mem_size, addr_bits); + int data_range_left = id2ast->children[0]->range_left; + int data_range_right = id2ast->children[0]->range_right; + std::stringstream sstr; - sstr << "$mem2bits$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++); + sstr << "$mem2bits$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++); std::string wire_id = sstr.str(); - AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); + AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(data_range_left, true), mkconst_int(data_range_right, true))); wire->str = wire_id; if (current_block) wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false); @@ -1101,7 +1158,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, AstNode *selected_case = NULL; for (size_t i = 1; i < children.size(); i++) { - log_assert(children.at(i)->type == AST_COND); + log_assert(children.at(i)->type == AST_COND || children.at(i)->type == AST_CONDX || children.at(i)->type == AST_CONDZ); AstNode *this_genblock = NULL; for (auto child : children.at(i)->children) { @@ -1316,7 +1373,7 @@ skip_dynamic_range_lvalue_expansion:; if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME) && current_block != NULL) { std::stringstream sstr; - sstr << "$assert$" << filename << ":" << linenum << "$" << (autoidx++); + sstr << "$formal$" << filename << ":" << linenum << "$" << (autoidx++); std::string id_check = sstr.str() + "_CHECK", id_en = sstr.str() + "_EN"; AstNode *wire_check = new AstNode(AST_WIRE); @@ -1328,8 +1385,10 @@ skip_dynamic_range_lvalue_expansion:; AstNode *wire_en = new AstNode(AST_WIRE); wire_en->str = id_en; current_ast_mod->children.push_back(wire_en); - current_ast_mod->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(0, false, 1))))); - current_ast_mod->children.back()->children[0]->children[0]->children[0]->str = id_en; + if (current_always_clocked) { + current_ast_mod->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(0, false, 1))))); + current_ast_mod->children.back()->children[0]->children[0]->children[0]->str = id_en; + } current_scope[wire_en->str] = wire_en; while (wire_en->simplify(true, false, false, 1, -1, false, false)) { } @@ -1350,7 +1409,12 @@ skip_dynamic_range_lvalue_expansion:; assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_REDUCE_BOOL, children[0]->clone())); assign_check->children[0]->str = id_check; - assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1)); + if (current_always == nullptr || current_always->type != AST_INITIAL) { + assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1)); + } else { + assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_FCALL)); + assign_en->children[1]->str = "\\$initstate"; + } assign_en->children[0]->str = id_en; newNode = new AstNode(AST_BLOCK); @@ -1383,6 +1447,50 @@ skip_dynamic_range_lvalue_expansion:; goto apply_newNode; } + // assignment with nontrivial member in left-hand concat expression -> split assignment + if ((type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE) && children[0]->type == AST_CONCAT && width_hint > 0) + { + bool found_nontrivial_member = false; + + for (auto child : children[0]->children) { + if (child->type == AST_IDENTIFIER && child->id2ast != NULL && child->id2ast->type == AST_MEMORY) + found_nontrivial_member = true; + } + + if (found_nontrivial_member) + { + newNode = new AstNode(AST_BLOCK); + + AstNode *wire_tmp = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(width_hint-1, true), mkconst_int(0, true))); + wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", filename.c_str(), linenum, autoidx++); + current_ast_mod->children.push_back(wire_tmp); + current_scope[wire_tmp->str] = wire_tmp; + wire_tmp->attributes["\\nosync"] = AstNode::mkconst_int(1, false); + while (wire_tmp->simplify(true, false, false, 1, -1, false, false)) { } + + AstNode *wire_tmp_id = new AstNode(AST_IDENTIFIER); + wire_tmp_id->str = wire_tmp->str; + + newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, wire_tmp_id, children[1]->clone())); + + int cursor = 0; + for (auto child : children[0]->children) + { + int child_width_hint = -1; + bool child_sign_hint = true; + child->detectSignWidth(child_width_hint, child_sign_hint); + + AstNode *rhs = wire_tmp_id->clone(); + rhs->children.push_back(new AstNode(AST_RANGE, AstNode::mkconst_int(cursor+child_width_hint-1, true), AstNode::mkconst_int(cursor, true))); + newNode->children.push_back(new AstNode(type, child->clone(), rhs)); + + cursor += child_width_hint; + } + + goto apply_newNode; + } + } + // assignment with memory in left-hand side expression -> replace with memory write port if (stage > 1 && (type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE) && children[0]->type == AST_IDENTIFIER && children[0]->id2ast && children[0]->id2ast->type == AST_MEMORY && children[0]->id2ast->children.size() >= 2 && @@ -1404,6 +1512,15 @@ skip_dynamic_range_lvalue_expansion:; int mem_width, mem_size, addr_bits; children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits); + int data_range_left = children[0]->id2ast->children[0]->range_left; + int data_range_right = children[0]->id2ast->children[0]->range_right; + int mem_data_range_offset = std::min(data_range_left, data_range_right); + + int addr_width_hint = -1; + bool addr_sign_hint = true; + children[0]->children[0]->children[0]->detectSignWidthWorker(addr_width_hint, addr_sign_hint); + addr_bits = std::max(addr_bits, addr_width_hint); + AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); wire_addr->str = id_addr; current_ast_mod->children.push_back(wire_addr); @@ -1461,6 +1578,7 @@ skip_dynamic_range_lvalue_expansion:; { int offset = children[0]->children[1]->range_right; int width = children[0]->children[1]->range_left - offset + 1; + offset -= mem_data_range_offset; std::vector<RTLIL::State> padding_x(offset, RTLIL::State::Sx); @@ -1482,6 +1600,9 @@ skip_dynamic_range_lvalue_expansion:; AstNode *right_at_zero_ast = the_range->children.size() >= 2 ? the_range->children[1]->clone() : left_at_zero_ast->clone(); AstNode *offset_ast = right_at_zero_ast->clone(); + if (mem_data_range_offset) + offset_ast = new AstNode(AST_SUB, offset_ast, mkconst_int(mem_data_range_offset, true)); + 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) @@ -1545,6 +1666,153 @@ skip_dynamic_range_lvalue_expansion:; { if (type == AST_FCALL) { + if (str == "\\$initstate") + { + int myidx = autoidx++; + + AstNode *wire = new AstNode(AST_WIRE); + wire->str = stringf("$initstate$%d_wire", myidx); + current_ast_mod->children.push_back(wire); + while (wire->simplify(true, false, false, 1, -1, false, false)) { } + + AstNode *cell = new AstNode(AST_CELL, new AstNode(AST_CELLTYPE), new AstNode(AST_ARGUMENT, new AstNode(AST_IDENTIFIER))); + cell->str = stringf("$initstate$%d", myidx); + cell->children[0]->str = "$initstate"; + cell->children[1]->str = "\\Y"; + cell->children[1]->children[0]->str = wire->str; + cell->children[1]->children[0]->id2ast = wire; + current_ast_mod->children.push_back(cell); + while (cell->simplify(true, false, false, 1, -1, false, false)) { } + + newNode = new AstNode(AST_IDENTIFIER); + newNode->str = wire->str; + newNode->id2ast = wire; + goto apply_newNode; + } + + if (str == "\\$past") + { + if (width_hint <= 0) + goto replace_fcall_later; + + int num_steps = 1; + + if (GetSize(children) != 1 && GetSize(children) != 2) + log_error("System function %s got %d arguments, expected 1 or 2 at %s:%d.\n", + RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum); + + if (!current_always_clocked) + log_error("System function %s is only allowed in clocked blocks at %s:%d.\n", + RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum); + + if (GetSize(children) == 2) + { + AstNode *buf = children[1]->clone(); + while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } + if (buf->type != AST_CONSTANT) + log_error("Failed to evaluate system function `%s' with non-constant value at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + + num_steps = buf->asInt(true); + delete buf; + } + + AstNode *block = nullptr; + + for (auto child : current_always->children) + if (child->type == AST_BLOCK) + block = child; + + log_assert(block != nullptr); + + int myidx = autoidx++; + AstNode *outreg = nullptr; + + for (int i = 0; i < num_steps; i++) + { + AstNode *reg = new AstNode(AST_WIRE, new AstNode(AST_RANGE, + mkconst_int(width_hint-1, true), mkconst_int(0, true))); + + reg->str = stringf("$past$%s:%d$%d$%d", filename.c_str(), linenum, myidx, i); + reg->is_reg = true; + + current_ast_mod->children.push_back(reg); + + while (reg->simplify(true, false, false, 1, -1, false, false)) { } + + AstNode *regid = new AstNode(AST_IDENTIFIER); + regid->str = reg->str; + regid->id2ast = reg; + + AstNode *rhs = nullptr; + + if (outreg == nullptr) { + rhs = children.at(0)->clone(); + } else { + rhs = new AstNode(AST_IDENTIFIER); + rhs->str = outreg->str; + rhs->id2ast = outreg; + } + + block->children.push_back(new AstNode(AST_ASSIGN_LE, regid, rhs)); + outreg = reg; + } + + newNode = new AstNode(AST_IDENTIFIER); + newNode->str = outreg->str; + newNode->id2ast = outreg; + goto apply_newNode; + } + + if (str == "\\$stable" || str == "\\$rose" || str == "\\$fell") + { + if (GetSize(children) != 1) + log_error("System function %s got %d arguments, expected 1 at %s:%d.\n", + RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum); + + if (!current_always_clocked) + log_error("System function %s is only allowed in clocked blocks at %s:%d.\n", + RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum); + + AstNode *present = children.at(0)->clone(); + AstNode *past = clone(); + past->str = "\\$past"; + + if (str == "\\$stable") + newNode = new AstNode(AST_EQ, past, present); + + else if (str == "\\$rose") + newNode = new AstNode(AST_LOGIC_AND, new AstNode(AST_LOGIC_NOT, past), present); + + else if (str == "\\$fell") + newNode = new AstNode(AST_LOGIC_AND, past, new AstNode(AST_LOGIC_NOT, present)); + + else + log_abort(); + + goto apply_newNode; + } + + if (str == "\\$rose" || str == "\\$fell") + { + if (GetSize(children) != 1) + log_error("System function %s got %d arguments, expected 1 at %s:%d.\n", + RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum); + + if (!current_always_clocked) + log_error("System function %s is only allowed in clocked blocks at %s:%d.\n", + RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum); + + newNode = new AstNode(AST_EQ, children.at(0)->clone(), clone()); + newNode->children.at(1)->str = "\\$past"; + goto apply_newNode; + } + + // $anyconst is mapped in AstNode::genRTLIL() + if (str == "\\$anyconst") { + recursion_counter--; + return false; + } + if (str == "\\$clog2") { if (children.size() != 1) @@ -1674,12 +1942,12 @@ skip_dynamic_range_lvalue_expansion:; if (type == AST_TCALL) { - if (str == "$finish") + if (str == "$finish" || str == "$stop") { if (!current_always || current_always->type != AST_INITIAL) - log_error("System task `$finish' outside initial block is unsupported at %s:%d.\n", filename.c_str(), linenum); + log_error("System task `%s' outside initial block is unsupported at %s:%d.\n", str.c_str(), filename.c_str(), linenum); - log_error("System task `$finish' executed at %s:%d.\n", filename.c_str(), linenum); + log_error("System task `%s' executed at %s:%d.\n", str.c_str(), filename.c_str(), linenum); } if (str == "\\$readmemh" || str == "\\$readmemb") @@ -1889,6 +2157,8 @@ skip_dynamic_range_lvalue_expansion:; wire->port_id = 0; wire->is_input = false; wire->is_output = false; + if (!child->is_output) + wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false); wire_cache[child->str] = wire; current_ast_mod->children.push_back(wire); @@ -1949,6 +2219,8 @@ skip_dynamic_range_lvalue_expansion:; did_something = true; } +replace_fcall_later:; + // perform const folding when activated if (const_fold) { @@ -2347,12 +2619,12 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m block->children.back()->children[0]->id2ast = memory; } - if ((cursor == finish_addr) || (increment > 0 && cursor > range_max) || (increment < 0 && cursor < range_min)) - break; cursor += increment; + if ((cursor == finish_addr+increment) || (increment > 0 && cursor > range_max) || (increment < 0 && cursor < range_min)) + break; } - if ((cursor == finish_addr) || (increment > 0 && cursor > range_max) || (increment < 0 && cursor < range_min)) + if ((cursor == finish_addr+increment) || (increment > 0 && cursor > range_max) || (increment < 0 && cursor < range_min)) break; } @@ -2568,16 +2840,54 @@ bool AstNode::mem2reg_check(pool<AstNode*> &mem2reg_set) return true; } +void AstNode::mem2reg_remove(pool<AstNode*> &mem2reg_set, vector<AstNode*> &delnodes) +{ + log_assert(mem2reg_set.count(this) == 0); + + if (mem2reg_set.count(id2ast)) + id2ast = nullptr; + + for (size_t i = 0; i < children.size(); i++) { + if (mem2reg_set.count(children[i]) > 0) { + delnodes.push_back(children[i]); + children.erase(children.begin() + (i--)); + } else { + children[i]->mem2reg_remove(mem2reg_set, delnodes); + } + } +} + // actually replace memories with registers -bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block) +bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block, AstNode *&async_block) { bool did_something = false; if (type == AST_BLOCK) block = this; - if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && block != NULL && - children[0]->mem2reg_check(mem2reg_set) && children[0]->children[0]->children[0]->type != AST_CONSTANT) + if (type == AST_FUNCTION || type == AST_TASK) + return false; + + if (type == AST_ASSIGN && block == NULL && children[0]->mem2reg_check(mem2reg_set)) + { + if (async_block == NULL) { + async_block = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK)); + mod->children.push_back(async_block); + } + + AstNode *newNode = clone(); + newNode->type = AST_ASSIGN_EQ; + async_block->children[0]->children.push_back(newNode); + + newNode = new AstNode(AST_NONE); + newNode->cloneInto(this); + delete newNode; + + did_something = true; + } + + if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && children[0]->mem2reg_check(mem2reg_set) && + children[0]->children[0]->children[0]->type != AST_CONSTANT) { std::stringstream sstr; sstr << "$mem2reg_wr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++); @@ -2653,7 +2963,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, else { std::stringstream sstr; - sstr << "$mem2reg_rd$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++); + sstr << "$mem2reg_rd$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++); std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA"; int mem_width, mem_size, addr_bits; @@ -2733,7 +3043,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, auto children_list = children; for (size_t i = 0; i < children_list.size(); i++) - if (children_list[i]->mem2reg_as_needed_pass2(mem2reg_set, mod, block)) + if (children_list[i]->mem2reg_as_needed_pass2(mem2reg_set, mod, block, async_block)) did_something = true; return did_something; @@ -2958,7 +3268,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) for (size_t i = 1; i < stmt->children.size(); i++) { bool found_match = false; - log_assert(stmt->children.at(i)->type == AST_COND); + log_assert(stmt->children.at(i)->type == AST_COND || stmt->children.at(i)->type == AST_CONDX || stmt->children.at(i)->type == AST_CONDZ); if (stmt->children.at(i)->children.front()->type == AST_DEFAULT) { sel_case = stmt->children.at(i)->children.back(); diff --git a/frontends/blif/blifparse.cc b/frontends/blif/blifparse.cc index ee0e771e..3717a1e5 100644 --- a/frontends/blif/blifparse.cc +++ b/frontends/blif/blifparse.cc @@ -49,12 +49,13 @@ static bool read_next_line(char *&buffer, size_t &buffer_size, int &line_count, } } -void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bool run_clean) +void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bool run_clean, bool sop_mode) { RTLIL::Module *module = nullptr; RTLIL::Const *lutptr = NULL; + RTLIL::Cell *sopcell = NULL; RTLIL::State lut_default_state = RTLIL::State::Sx; - int blif_maxnum = 0; + int blif_maxnum = 0, sopmode = -1; auto blif_wire = [&](const std::string &wire_name) -> Wire* { @@ -116,6 +117,11 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo lut_default_state = RTLIL::State::Sx; } + if (sopcell) { + sopcell = NULL; + sopmode = -1; + } + char *cmd = strtok(buffer, " \t\r\n"); if (!strcmp(cmd, ".model")) { @@ -235,7 +241,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo } if (init != nullptr && (init[0] == '0' || init[0] == '1')) - blif_wire(d)->attributes["\\init"] = Const(init[0] == '1' ? 1 : 0, 1); + blif_wire(q)->attributes["\\init"] = Const(init[0] == '1' ? 1 : 0, 1); if (clock == nullptr) goto no_latch_clock; @@ -244,6 +250,10 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo cell = module->addDff(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q)); else if (!strcmp(edge, "fe")) cell = module->addDff(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q), false); + else if (!strcmp(edge, "ah")) + cell = module->addDlatch(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q)); + else if (!strcmp(edge, "al")) + cell = module->addDlatch(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q), false); else { no_latch_clock: cell = module->addCell(NEW_ID, dff_name); @@ -340,20 +350,33 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo goto continue_without_read; } - RTLIL::Cell *cell = module->addCell(NEW_ID, "$lut"); - cell->parameters["\\WIDTH"] = RTLIL::Const(input_sig.size()); - cell->parameters["\\LUT"] = RTLIL::Const(RTLIL::State::Sx, 1 << input_sig.size()); - cell->setPort("\\A", input_sig); - cell->setPort("\\Y", output_sig); - lutptr = &cell->parameters.at("\\LUT"); - lut_default_state = RTLIL::State::Sx; + if (sop_mode) + { + sopcell = module->addCell(NEW_ID, "$sop"); + sopcell->parameters["\\WIDTH"] = RTLIL::Const(input_sig.size()); + sopcell->parameters["\\DEPTH"] = 0; + sopcell->parameters["\\TABLE"] = RTLIL::Const(); + sopcell->setPort("\\A", input_sig); + sopcell->setPort("\\Y", output_sig); + sopmode = -1; + } + else + { + RTLIL::Cell *cell = module->addCell(NEW_ID, "$lut"); + cell->parameters["\\WIDTH"] = RTLIL::Const(input_sig.size()); + cell->parameters["\\LUT"] = RTLIL::Const(RTLIL::State::Sx, 1 << input_sig.size()); + cell->setPort("\\A", input_sig); + cell->setPort("\\Y", output_sig); + lutptr = &cell->parameters.at("\\LUT"); + lut_default_state = RTLIL::State::Sx; + } continue; } goto error; } - if (lutptr == NULL) + if (lutptr == NULL && sopcell == NULL) goto error; char *input = strtok(buffer, " \t\r\n"); @@ -363,23 +386,60 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo goto error; int input_len = strlen(input); - if (input_len > 8) - goto error; - for (int i = 0; i < (1 << input_len); i++) { - for (int j = 0; j < input_len; j++) { - char c1 = input[j]; - if (c1 != '-') { - char c2 = (i & (1 << j)) != 0 ? '1' : '0'; - if (c1 != c2) - goto try_next_value; + if (sopcell) + { + log_assert(sopcell->parameters["\\WIDTH"].as_int() == input_len); + sopcell->parameters["\\DEPTH"] = sopcell->parameters["\\DEPTH"].as_int() + 1; + + for (int i = 0; i < input_len; i++) + switch (input[i]) { + case '0': + sopcell->parameters["\\TABLE"].bits.push_back(State::S1); + sopcell->parameters["\\TABLE"].bits.push_back(State::S0); + break; + case '1': + sopcell->parameters["\\TABLE"].bits.push_back(State::S0); + sopcell->parameters["\\TABLE"].bits.push_back(State::S1); + break; + default: + sopcell->parameters["\\TABLE"].bits.push_back(State::S0); + sopcell->parameters["\\TABLE"].bits.push_back(State::S0); + break; + } + + if (sopmode == -1) { + sopmode = (*output == '1'); + if (!sopmode) { + SigSpec outnet = sopcell->getPort("\\Y"); + SigSpec tempnet = module->addWire(NEW_ID); + module->addNotGate(NEW_ID, tempnet, outnet); + sopcell->setPort("\\Y", tempnet); } - } - lutptr->bits.at(i) = !strcmp(output, "0") ? RTLIL::State::S0 : RTLIL::State::S1; - try_next_value:; + } else + log_assert(sopmode == (*output == '1')); } - lut_default_state = !strcmp(output, "0") ? RTLIL::State::S1 : RTLIL::State::S0; + if (lutptr) + { + if (input_len > 8) + goto error; + + for (int i = 0; i < (1 << input_len); i++) { + for (int j = 0; j < input_len; j++) { + char c1 = input[j]; + if (c1 != '-') { + char c2 = (i & (1 << j)) != 0 ? '1' : '0'; + if (c1 != c2) + goto try_next_value; + } + } + lutptr->bits.at(i) = !strcmp(output, "0") ? RTLIL::State::S0 : RTLIL::State::S1; + try_next_value:; + } + + lut_default_state = !strcmp(output, "0") ? RTLIL::State::S1 : RTLIL::State::S0; + } } error: @@ -396,23 +456,28 @@ struct BlifFrontend : public Frontend { log("\n"); log("Load modules from a BLIF file into the current design.\n"); log("\n"); + log(" -sop\n"); + log(" Create $sop cells instead of $lut cells\n"); + log("\n"); } virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing BLIF frontend.\n"); + bool sop_mode = false; + + log_header(design, "Executing BLIF frontend.\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; - // if (arg == "-lib") { - // flag_lib = true; - // continue; - // } + if (arg == "-sop") { + sop_mode = true; + continue; + } break; } extra_args(f, filename, args, argidx); - parse_blif(design, *f, "\\DFF", true); + parse_blif(design, *f, "\\DFF", true, sop_mode); } } BlifFrontend; diff --git a/frontends/blif/blifparse.h b/frontends/blif/blifparse.h index 3c01ed37..058087d8 100644 --- a/frontends/blif/blifparse.h +++ b/frontends/blif/blifparse.h @@ -24,7 +24,7 @@ YOSYS_NAMESPACE_BEGIN -extern void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bool run_clean = false); +extern void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bool run_clean = false, bool sop_mode = false); YOSYS_NAMESPACE_END diff --git a/frontends/ilang/ilang_frontend.cc b/frontends/ilang/ilang_frontend.cc index 7361a254..ed678998 100644 --- a/frontends/ilang/ilang_frontend.cc +++ b/frontends/ilang/ilang_frontend.cc @@ -47,7 +47,7 @@ struct IlangFrontend : public Frontend { } virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing ILANG frontend.\n"); + log_header(design, "Executing ILANG frontend.\n"); extra_args(f, filename, args, 1); log("Input filename: %s\n", filename.c_str()); diff --git a/frontends/liberty/liberty.cc b/frontends/liberty/liberty.cc index f02a7323..73d927fa 100644 --- a/frontends/liberty/liberty.cc +++ b/frontends/liberty/liberty.cc @@ -437,7 +437,7 @@ struct LibertyFrontend : public Frontend { bool flag_ignore_miss_dir = false; std::vector<std::string> attributes; - log_header("Executing Liberty frontend.\n"); + log_header(design, "Executing Liberty frontend.\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { @@ -469,6 +469,46 @@ struct LibertyFrontend : public Frontend { LibertyParser parser(*f); int cell_count = 0; + std::map<std::string, std::tuple<int, int, bool>> type_map; + + for (auto type_node : parser.ast->children) + { + if (type_node->id != "type" || type_node->args.size() != 1) + continue; + + std::string type_name = type_node->args.at(0); + int bit_width = -1, bit_from = -1, bit_to = -1; + bool upto = false; + + for (auto child : type_node->children) + { + if (child->id == "base_type" && child->value != "array") + goto next_type; + + if (child->id == "data_type" && child->value != "bit") + goto next_type; + + if (child->id == "bit_width") + bit_width = atoi(child->value.c_str()); + + if (child->id == "bit_from") + bit_from = atoi(child->value.c_str()); + + if (child->id == "bit_to") + bit_to = atoi(child->value.c_str()); + + if (child->id == "downto" && (child->value == "0" || child->value == "false" || child->value == "FALSE")) + upto = true; + } + + if (bit_width != (std::max(bit_from, bit_to) - std::min(bit_from, bit_to) + 1)) + log_error("Incompatible array type '%s': bit_width=%d, bit_from=%d, bit_to=%d.\n", + type_name.c_str(), bit_width, bit_from, bit_to); + + type_map[type_name] = std::tuple<int, int, bool>(bit_width, std::min(bit_from, bit_to), upto); + next_type:; + } + for (auto cell : parser.ast->children) { if (cell->id != "cell" || cell->args.size() != 1) @@ -494,13 +534,14 @@ struct LibertyFrontend : public Frontend { module->attributes[attr] = 1; for (auto node : cell->children) + { if (node->id == "pin" && node->args.size() == 1) { LibertyAst *dir = node->find("direction"); if (!dir || (dir->value != "input" && dir->value != "output" && dir->value != "inout" && dir->value != "internal")) { if (!flag_ignore_miss_dir) { - log_error("Missing or invalid direction for pin %s of cell %s.\n", node->args.at(0).c_str(), log_id(module->name)); + log_error("Missing or invalid direction for pin %s on cell %s.\n", node->args.at(0).c_str(), log_id(module->name)); } else { log("Ignoring cell %s with missing or invalid direction for pin %s.\n", log_id(module->name), node->args.at(0).c_str()); delete module; @@ -511,6 +552,41 @@ struct LibertyFrontend : public Frontend { module->addWire(RTLIL::escape_id(node->args.at(0))); } + if (node->id == "bus" && node->args.size() == 1) + { + if (!flag_lib) + log_error("Error in cell %s: bus interfaces are only supported in -lib mode.\n", log_id(cell_name)); + + LibertyAst *dir = node->find("direction"); + + if (!dir || (dir->value != "input" && dir->value != "output" && dir->value != "inout" && dir->value != "internal")) + log_error("Missing or invalid direction for bus %s on cell %s.\n", node->args.at(0).c_str(), log_id(module->name)); + + if (dir->value == "internal") + continue; + + 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", + node->args.at(0).c_str(), log_id(cell_name)); + + int bus_type_width = std::get<0>(type_map.at(bus_type_node->value)); + int bus_type_offset = std::get<1>(type_map.at(bus_type_node->value)); + bool bus_type_upto = std::get<2>(type_map.at(bus_type_node->value)); + + Wire *wire = module->addWire(RTLIL::escape_id(node->args.at(0)), bus_type_width); + wire->start_offset = bus_type_offset; + wire->upto = bus_type_upto; + + if (dir->value == "input" || dir->value == "inout") + wire->port_input = true; + + if (dir->value == "output" || dir->value == "inout") + wire->port_output = true; + } + } + for (auto node : cell->children) { if (!flag_lib) { diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index b0fdedcc..7dd36a74 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -850,7 +850,7 @@ struct VerificPass : public Pass { #ifdef YOSYS_ENABLE_VERIFIC virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing VERIFIC (loading Verilog and VHDL designs using Verific).\n"); + log_header(design, "Executing VERIFIC (loading Verilog and VHDL designs using Verific).\n"); Message::SetConsoleOutput(0); Message::RegisterCallBackMsg(msg_func); diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index cd8b586c..894723c8 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -63,9 +63,15 @@ struct VerilogFrontend : public Frontend { log(" of SystemVerilog is supported)\n"); log("\n"); log(" -formal\n"); - log(" enable support for assert() and assume() from SystemVerilog\n"); + log(" enable support for SystemVerilog assertions and some Yosys extensions\n"); log(" replace the implicit -D SYNTHESIS with -D FORMAL\n"); log("\n"); + log(" -norestrict\n"); + log(" ignore restrict() assertions\n"); + log("\n"); + log(" -assume-asserts\n"); + log(" treat all assert() statements like assume() statements\n"); + log("\n"); log(" -dump_ast1\n"); log(" dump abstract syntax tree (before simplification)\n"); log("\n"); @@ -75,6 +81,9 @@ struct VerilogFrontend : public Frontend { log(" -dump_vlog\n"); log(" dump ast as Verilog code (after simplification)\n"); log("\n"); + log(" -dump_rtlil\n"); + log(" dump generated RTLIL netlist\n"); + log("\n"); log(" -yydebug\n"); log(" enable parser debug output\n"); log("\n"); @@ -159,12 +168,16 @@ struct VerilogFrontend : public Frontend { log("recommended to use a simulator (for example Icarus Verilog) for checking\n"); log("the syntax of the code, rather than to rely on read_verilog for that.\n"); log("\n"); + log("See the Yosys README file for a list of non-standard Verilog features\n"); + 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) { bool flag_dump_ast1 = false; bool flag_dump_ast2 = false; bool flag_dump_vlog = false; + bool flag_dump_rtlil = false; bool flag_nolatches = false; bool flag_nomeminit = false; bool flag_nomem2reg = false; @@ -172,7 +185,6 @@ struct VerilogFrontend : public Frontend { bool flag_ppdump = false; bool flag_nopp = false; bool flag_nodpi = false; - bool flag_lib = false; bool flag_noopt = false; bool flag_icells = false; bool flag_ignore_redef = false; @@ -184,9 +196,12 @@ struct VerilogFrontend : public Frontend { frontend_verilog_yydebug = false; sv_mode = false; formal_mode = false; + norestrict_mode = false; + assume_asserts_mode = false; + lib_mode = false; default_nettype_wire = true; - log_header("Executing Verilog-2005 frontend.\n"); + log_header(design, "Executing Verilog-2005 frontend.\n"); args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end()); @@ -201,6 +216,14 @@ struct VerilogFrontend : public Frontend { formal_mode = true; continue; } + if (arg == "-norestrict") { + norestrict_mode = true; + continue; + } + if (arg == "-assume-asserts") { + assume_asserts_mode = true; + continue; + } if (arg == "-dump_ast1") { flag_dump_ast1 = true; continue; @@ -213,6 +236,10 @@ struct VerilogFrontend : public Frontend { flag_dump_vlog = true; continue; } + if (arg == "-dump_rtlil") { + flag_dump_rtlil = true; + continue; + } if (arg == "-yydebug") { frontend_verilog_yydebug = true; continue; @@ -246,7 +273,7 @@ struct VerilogFrontend : public Frontend { continue; } if (arg == "-lib") { - flag_lib = true; + lib_mode = true; defines_map["BLACKBOX"] = string(); continue; } @@ -339,7 +366,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_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_ignore_redef, flag_defer, default_nettype_wire); + 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_ignore_redef, flag_defer, default_nettype_wire); if (!flag_nopp) delete lexin; @@ -362,13 +389,13 @@ struct VerilogDefaults : public Pass { log("Add the specified options to the list of default options to read_verilog.\n"); log("\n"); log("\n"); - log(" verilog_defaults -clear"); + log(" verilog_defaults -clear\n"); log("\n"); log("Clear the list of Verilog default options.\n"); log("\n"); log("\n"); - log(" verilog_defaults -push"); - log(" verilog_defaults -pop"); + log(" verilog_defaults -push\n"); + log(" verilog_defaults -pop\n"); log("\n"); log("Push or pop the list of default options to a stack. Note that -push does\n"); log("not imply -clear.\n"); diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h index fb98f4af..606ec20a 100644 --- a/frontends/verilog/verilog_frontend.h +++ b/frontends/verilog/verilog_frontend.h @@ -54,6 +54,15 @@ namespace VERILOG_FRONTEND // running in -formal mode extern bool formal_mode; + // running in -norestrict mode + extern bool norestrict_mode; + + // running in -assume-asserts mode + extern bool assume_asserts_mode; + + // running in -lib mode + extern bool lib_mode; + // lexer input stream extern std::istream *lexin; } diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 69a8ddaa..405aeb97 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -63,6 +63,10 @@ YOSYS_NAMESPACE_END frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); \ return TOK_ID; +#define NON_KEYWORD() \ + frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); \ + return TOK_ID; + #define YY_INPUT(buf,result,max_size) \ result = readsome(*VERILOG_FRONTEND::lexin, buf, max_size) @@ -141,6 +145,8 @@ YOSYS_NAMESPACE_END "endfunction" { return TOK_ENDFUNCTION; } "task" { return TOK_TASK; } "endtask" { return TOK_ENDTASK; } +"package" { SV_KEYWORD(TOK_PACKAGE); } +"endpackage" { SV_KEYWORD(TOK_ENDPACKAGE); } "parameter" { return TOK_PARAMETER; } "localparam" { return TOK_LOCALPARAM; } "defparam" { return TOK_DEFPARAM; } @@ -171,6 +177,7 @@ YOSYS_NAMESPACE_END "assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); } "assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); } +"restrict" { if (formal_mode) return TOK_RESTRICT; SV_KEYWORD(TOK_RESTRICT); } "property" { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); } "logic" { SV_KEYWORD(TOK_REG); } "bit" { SV_KEYWORD(TOK_REG); } @@ -351,6 +358,8 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ { "<<<" { return OP_SSHL; } ">>>" { return OP_SSHR; } +"::" { SV_KEYWORD(TOK_PACKAGESEP); } + "+:" { return TOK_POS_INDEXED; } "-:" { return TOK_NEG_INDEXED; } diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 863fee59..c730ce5b 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -57,7 +57,8 @@ namespace VERILOG_FRONTEND { std::vector<char> case_type_stack; bool do_not_require_port_stubs; bool default_nettype_wire; - bool sv_mode, formal_mode; + bool sv_mode, formal_mode, lib_mode; + bool norestrict_mode, assume_asserts_mode; std::istream *lexin; } YOSYS_NAMESPACE_END @@ -102,6 +103,7 @@ static void free_attr(std::map<std::string, AstNode*> *al) %token <string> TOK_STRING TOK_ID TOK_CONST TOK_REALVAL TOK_PRIMITIVE %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_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL %token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT @@ -111,7 +113,8 @@ 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 TOK_PROPERTY +%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME +%token TOK_RESTRICT TOK_PROPERTY %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 @@ -133,6 +136,9 @@ static void free_attr(std::map<std::string, AstNode*> *al) %left OP_POW %right UNARY_OPS +%define parse.error verbose +%define parse.lac full + %expect 2 %debug @@ -155,6 +161,7 @@ design: task_func_decl design | param_decl design | localparam_decl design | + package design | /* empty */; attr: @@ -212,6 +219,14 @@ hierarchical_id: TOK_ID { $$ = $1; } | + hierarchical_id TOK_PACKAGESEP TOK_ID { + if ($3->substr(0, 1) == "\\") + *$1 += "::" + $3->substr(1); + else + *$1 += "::" + *$3; + delete $3; + $$ = $1; + } | hierarchical_id '.' TOK_ID { if ($3->substr(0, 1) == "\\") *$1 += "." + $3->substr(1); @@ -246,11 +261,10 @@ module_para_opt: '#' '(' { astbuf1 = nullptr; } module_para_list { if (astbuf1) delete astbuf1; } ')' | /* empty */; module_para_list: - single_module_para | - single_module_para ',' module_para_list | - /* empty */; + single_module_para | module_para_list ',' single_module_para; single_module_para: + /* empty */ | TOK_PARAMETER { if (astbuf1) delete astbuf1; astbuf1 = new AstNode(AST_PARAMETER); @@ -302,7 +316,7 @@ module_arg: node->children.push_back($3); if (!node->is_input && !node->is_output) frontend_verilog_yyerror("Module port `%s' is neither input nor output.", $4->c_str()); - if (node->is_reg && node->is_input && !node->is_output) + if (node->is_reg && node->is_input && !node->is_output && !sv_mode) frontend_verilog_yyerror("Input port `%s' is declared as register.", $4->c_str()); ast_stack.back()->children.push_back(node); append_attr(node, $1); @@ -312,6 +326,25 @@ module_arg: do_not_require_port_stubs = true; }; +package: + attr TOK_PACKAGE TOK_ID { + AstNode *mod = new AstNode(AST_PACKAGE); + ast_stack.back()->children.push_back(mod); + ast_stack.push_back(mod); + current_ast_mod = mod; + mod->str = *$3; + append_attr(mod, $1); + } ';' package_body TOK_ENDPACKAGE { + ast_stack.pop_back(); + current_ast_mod = NULL; + }; + +package_body: + package_body package_body_stmt |; + +package_body_stmt: + localparam_decl; + non_opt_delay: '#' '(' expr ')' { delete $3; } | '#' '(' expr ':' expr ':' expr ')' { delete $3; delete $5; delete $7; }; @@ -736,7 +769,7 @@ wire_name: if (port_stubs.count(*$1) != 0) { if (!node->is_input && !node->is_output) frontend_verilog_yyerror("Module port `%s' is neither input nor output.", $1->c_str()); - if (node->is_reg && node->is_input && !node->is_output) + if (node->is_reg && node->is_input && !node->is_output && !sv_mode) frontend_verilog_yyerror("Input port `%s' is declared as register.", $1->c_str()); node->port_id = port_stubs[*$1]; port_stubs.erase(*$1); @@ -825,10 +858,10 @@ cell_parameter_list_opt: '#' '(' cell_parameter_list ')' | /* empty */; cell_parameter_list: - /* empty */ | cell_parameter | - cell_parameter ',' cell_parameter_list; + cell_parameter | cell_parameter_list ',' cell_parameter; cell_parameter: + /* empty */ | expr { AstNode *node = new AstNode(AST_PARASET); astbuf1->children.push_back(node); @@ -843,14 +876,40 @@ cell_parameter: }; cell_port_list: - /* empty */ | cell_port | - cell_port ',' cell_port_list | - /* empty */ ',' { - AstNode *node = new AstNode(AST_ARGUMENT); - astbuf2->children.push_back(node); - } cell_port_list; + cell_port_list_rules { + // remove empty args from end of list + while (!astbuf2->children.empty()) { + AstNode *node = astbuf2->children.back(); + if (node->type != AST_ARGUMENT) break; + if (!node->children.empty()) break; + if (!node->str.empty()) break; + astbuf2->children.pop_back(); + delete node; + } + + // check port types + bool has_positional_args = false; + bool has_named_args = false; + for (auto node : astbuf2->children) { + if (node->type != AST_ARGUMENT) continue; + if (node->str.empty()) + has_positional_args = true; + else + has_named_args = true; + } + + if (has_positional_args && has_named_args) + frontend_verilog_yyerror("Mix of positional and named cell ports."); + }; + +cell_port_list_rules: + cell_port | cell_port_list_rules ',' cell_port; cell_port: + /* empty */ { + AstNode *node = new AstNode(AST_ARGUMENT); + astbuf2->children.push_back(node); + } | expr { AstNode *node = new AstNode(AST_ARGUMENT); astbuf2->children.push_back(node); @@ -937,18 +996,30 @@ opt_label: assert: TOK_ASSERT '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_ASSERT, $3)); + ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $3)); } | TOK_ASSUME '(' expr ')' ';' { ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $3)); + } | + TOK_RESTRICT '(' expr ')' ';' { + if (norestrict_mode) + delete $3; + else + ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $3)); }; assert_property: TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_ASSERT, $4)); + ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $4)); } | TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' { ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4)); + } | + TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' { + if (norestrict_mode) + delete $4; + else + ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4)); }; simple_behavioral_stmt: @@ -1099,7 +1170,9 @@ case_body: case_item: { - AstNode *node = new AstNode(AST_COND); + AstNode *node = new AstNode( + case_type_stack.size() && case_type_stack.back() == 'x' ? AST_CONDX : + case_type_stack.size() && case_type_stack.back() == 'z' ? AST_CONDZ : AST_COND); ast_stack.back()->children.push_back(node); ast_stack.push_back(node); } case_select { @@ -1119,7 +1192,9 @@ gen_case_body: gen_case_item: { - AstNode *node = new AstNode(AST_COND); + AstNode *node = new AstNode( + case_type_stack.size() && case_type_stack.back() == 'x' ? AST_CONDX : + case_type_stack.size() && case_type_stack.back() == 'z' ? AST_CONDZ : AST_COND); ast_stack.back()->children.push_back(node); ast_stack.push_back(node); } case_select { @@ -1154,6 +1229,8 @@ rvalue: $$ = new AstNode(AST_IDENTIFIER, $2); $$->str = *$1; delete $1; + if ($2 == nullptr && formal_mode && ($$->str == "\\$initstate" || $$->str == "\\$anyconst")) + $$->type = AST_FCALL; } | hierarchical_id non_opt_multirange { $$ = new AstNode(AST_IDENTIFIER, $2); @@ -1278,7 +1355,7 @@ basic_expr: if ($4->substr(0, 1) != "'") frontend_verilog_yyerror("Syntax error."); AstNode *bits = $2; - AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true); + AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); if (val == NULL) log_error("Value conversion failed: `%s'\n", $4->c_str()); $$ = new AstNode(AST_TO_BITS, bits, val); @@ -1289,7 +1366,7 @@ basic_expr: frontend_verilog_yyerror("Syntax error."); AstNode *bits = new AstNode(AST_IDENTIFIER); bits->str = *$1; - AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true); + AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); if (val == NULL) log_error("Value conversion failed: `%s'\n", $2->c_str()); $$ = new AstNode(AST_TO_BITS, bits, val); @@ -1297,24 +1374,24 @@ basic_expr: delete $2; } | TOK_CONST TOK_CONST { - $$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true); + $$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); if ($$ == NULL || (*$2)[0] != '\'') log_error("Value conversion failed: `%s%s'\n", $1->c_str(), $2->c_str()); delete $1; delete $2; } | TOK_CONST { - $$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true); + $$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); if ($$ == NULL) log_error("Value conversion failed: `%s'\n", $1->c_str()); delete $1; } | TOK_REALVAL { $$ = new AstNode(AST_REALVALUE); - char *p = strdup($1->c_str()), *q; - for (int i = 0, j = 0; !p[j]; j++) - if (p[j] != '_') - p[i++] = p[j], p[i] = 0; + char *p = (char*)malloc(GetSize(*$1) + 1), *q; + for (int i = 0, j = 0; j < GetSize(*$1); j++) + if ((*$1)[j] != '_') + p[i++] = (*$1)[j], p[i] = 0; $$->realvalue = strtod(p, &q); log_assert(*q == 0); delete $1; diff --git a/frontends/vhdl2verilog/vhdl2verilog.cc b/frontends/vhdl2verilog/vhdl2verilog.cc index 80bf243f..6f9c0e3f 100644 --- a/frontends/vhdl2verilog/vhdl2verilog.cc +++ b/frontends/vhdl2verilog/vhdl2verilog.cc @@ -74,7 +74,7 @@ struct Vhdl2verilogPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing VHDL2VERILOG (importing VHDL designs using vhdl2verilog).\n"); + log_header(design, "Executing VHDL2VERILOG (importing VHDL designs using vhdl2verilog).\n"); log_push(); std::string out_file, top_entity; @@ -173,7 +173,7 @@ struct Vhdl2verilogPass : public Pass { Frontend::frontend_call(design, &ff, stringf("%s/vhdl2verilog_output.v", tempdir_name.c_str()), "verilog"); } - log_header("Removing temp directory `%s':\n", tempdir_name.c_str()); + log_header(design, "Removing temp directory `%s':\n", tempdir_name.c_str()); remove_directory(tempdir_name); log_pop(); } diff --git a/kernel/celledges.cc b/kernel/celledges.cc new file mode 100644 index 00000000..556e8b82 --- /dev/null +++ b/kernel/celledges.cc @@ -0,0 +1,209 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/celledges.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +void bitwise_unary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) +{ + IdString A = "\\A", Y = "\\Y"; + + bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); + int a_width = GetSize(cell->getPort(A)); + int y_width = GetSize(cell->getPort(Y)); + + for (int i = 0; i < y_width; i++) + { + if (i < a_width) + db->add_edge(cell, A, i, Y, i, -1); + else if (is_signed && a_width > 0) + db->add_edge(cell, A, a_width-1, Y, i, -1); + } +} + +void bitwise_binary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) +{ + IdString A = "\\A", B = "\\B", Y = "\\Y"; + + bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); + int a_width = GetSize(cell->getPort(A)); + int b_width = GetSize(cell->getPort(B)); + int y_width = GetSize(cell->getPort(Y)); + + if (cell->type == "$and" && !is_signed) { + if (a_width > b_width) + a_width = b_width; + else + b_width = a_width; + } + + for (int i = 0; i < y_width; i++) + { + if (i < a_width) + db->add_edge(cell, A, i, Y, i, -1); + else if (is_signed && a_width > 0) + db->add_edge(cell, A, a_width-1, Y, i, -1); + + if (i < b_width) + db->add_edge(cell, B, i, Y, i, -1); + else if (is_signed && b_width > 0) + db->add_edge(cell, B, b_width-1, Y, i, -1); + } +} + +void arith_neg_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) +{ + IdString A = "\\A", Y = "\\Y"; + + bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); + int a_width = GetSize(cell->getPort(A)); + int y_width = GetSize(cell->getPort(Y)); + + if (is_signed && a_width == 1) + y_width = std::min(y_width, 1); + + for (int i = 0; i < y_width; i++) + for (int k = 0; k <= i && k < a_width; k++) + db->add_edge(cell, A, k, Y, i, -1); +} + +void arith_binary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) +{ + IdString A = "\\A", B = "\\B", Y = "\\Y"; + + bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); + int a_width = GetSize(cell->getPort(A)); + int b_width = GetSize(cell->getPort(B)); + int y_width = GetSize(cell->getPort(Y)); + + if (!is_signed && cell->type != "$sub") { + int ab_width = std::max(a_width, b_width); + y_width = std::min(y_width, ab_width+1); + } + + for (int i = 0; i < y_width; i++) + { + for (int k = 0; k <= i; k++) + { + if (k < a_width) + db->add_edge(cell, A, k, Y, i, -1); + + if (k < b_width) + db->add_edge(cell, B, k, Y, i, -1); + } + } +} + +void reduce_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) +{ + IdString A = "\\A", Y = "\\Y"; + + int a_width = GetSize(cell->getPort(A)); + + for (int i = 0; i < a_width; i++) + db->add_edge(cell, A, i, Y, 0, -1); +} + +void compare_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) +{ + IdString A = "\\A", B = "\\B", Y = "\\Y"; + + int a_width = GetSize(cell->getPort(A)); + int b_width = GetSize(cell->getPort(B)); + + for (int i = 0; i < a_width; i++) + db->add_edge(cell, A, i, Y, 0, -1); + + for (int i = 0; i < b_width; i++) + db->add_edge(cell, B, i, Y, 0, -1); +} + +void mux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) +{ + IdString A = "\\A", B = "\\B", S = "\\S", Y = "\\Y"; + + int a_width = GetSize(cell->getPort(A)); + int b_width = GetSize(cell->getPort(B)); + int s_width = GetSize(cell->getPort(S)); + + for (int i = 0; i < a_width; i++) + { + db->add_edge(cell, A, i, Y, i, -1); + + for (int k = i; k < b_width; k += a_width) + db->add_edge(cell, B, k, Y, i, -1); + + for (int k = 0; k < s_width; k++) + db->add_edge(cell, S, k, Y, i, -1); + } +} + +PRIVATE_NAMESPACE_END + +bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL::Cell *cell) +{ + if (cell->type.in("$not", "$pos")) { + bitwise_unary_op(this, cell); + return true; + } + + if (cell->type.in("$and", "$or", "$xor", "$xnor")) { + bitwise_binary_op(this, cell); + return true; + } + + if (cell->type == "$neg") { + arith_neg_op(this, cell); + return true; + } + + if (cell->type.in("$add", "$sub")) { + arith_binary_op(this, cell); + return true; + } + + if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool", "$logic_not")) { + reduce_op(this, cell); + return true; + } + + // FIXME: + // if (cell->type.in("$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx")) { + // shift_op(this, cell); + // return true; + // } + + if (cell->type.in("$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt")) { + compare_op(this, cell); + return true; + } + + if (cell->type.in("$mux", "$pmux")) { + mux_op(this, cell); + return true; + } + + // FIXME: $mul $div $mod $slice $concat + // FIXME: $lut $sop $alu $lcu $macc $fa + + return false; +} + diff --git a/kernel/celledges.h b/kernel/celledges.h new file mode 100644 index 00000000..6aab9ed4 --- /dev/null +++ b/kernel/celledges.h @@ -0,0 +1,63 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef CELLEDGES_H +#define CELLEDGES_H + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +YOSYS_NAMESPACE_BEGIN + +struct AbstractCellEdgesDatabase +{ + virtual ~AbstractCellEdgesDatabase() { } + virtual void add_edge(RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit, RTLIL::IdString to_port, int to_bit, int delay) = 0; + bool add_edges_from_cell(RTLIL::Cell *cell); +}; + +struct FwdCellEdgesDatabase : AbstractCellEdgesDatabase +{ + SigMap &sigmap; + 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 { + 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); + } +}; + +struct RevCellEdgesDatabase : AbstractCellEdgesDatabase +{ + SigMap &sigmap; + 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 { + 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); + } +}; + +YOSYS_NAMESPACE_END + +#endif diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 40fdca36..900c12d0 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -85,7 +85,7 @@ struct CellTypes std::vector<RTLIL::IdString> unary_ops = { "$not", "$pos", "$neg", "$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool", - "$logic_not", "$slice", "$lut" + "$logic_not", "$slice", "$lut", "$sop" }; std::vector<RTLIL::IdString> binary_ops = { @@ -116,6 +116,8 @@ struct CellTypes setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true); setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true); + setup_type("$initstate", pool<RTLIL::IdString>(), {Y}, true); + setup_type("$anyconst", pool<RTLIL::IdString>(), {Y}, true); setup_type("$equiv", {A, B}, {Y}, true); } @@ -357,6 +359,44 @@ struct CellTypes return t; } + if (cell->type == "$sop") + { + int width = cell->parameters.at("\\WIDTH").as_int(); + int depth = cell->parameters.at("\\DEPTH").as_int(); + std::vector<RTLIL::State> t = cell->parameters.at("\\TABLE").bits; + + while (GetSize(t) < width*depth*2) + t.push_back(RTLIL::S0); + + RTLIL::State default_ret = State::S0; + + for (int i = 0; i < depth; i++) + { + bool match = true; + bool match_x = true; + + for (int j = 0; j < width; j++) { + RTLIL::State a = arg1.bits.at(j); + if (t.at(2*width*i + 2*j + 0) == State::S1) { + if (a == State::S1) match_x = false; + if (a != State::S0) match = false; + } + if (t.at(2*width*i + 2*j + 1) == State::S1) { + if (a == State::S0) match_x = false; + if (a != State::S1) match = false; + } + } + + if (match) + return State::S1; + + if (match_x) + default_ret = State::Sx; + } + + return default_ret; + } + 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; diff --git a/kernel/driver.cc b/kernel/driver.cc index 02e332f9..5cfc4171 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -183,8 +183,8 @@ int main(int argc, char **argv) printf(" -b backend\n"); printf(" use this backend for the output file specified on the command line\n"); printf("\n"); - printf(" -f backend\n"); - printf(" use the specified front for the input files on the command line\n"); + printf(" -f frontend\n"); + printf(" use the specified frontend for the input files on the command line\n"); printf("\n"); printf(" -H\n"); printf(" print the command list\n"); @@ -213,6 +213,11 @@ 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(" 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"); + printf("\n"); printf(" -V\n"); printf(" print version information and exit\n"); printf("\n"); @@ -233,7 +238,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:")) != -1) + while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:D:")) != -1) { switch (opt) { @@ -315,6 +320,28 @@ int main(int argc, char **argv) scriptfile = optarg; scriptfile_tcl = true; break; + case 'D': + { + auto args = split_tokens(optarg, ":"); + if (!args.empty() && args[0] == "ALL") { + if (GetSize(args) != 1) { + fprintf(stderr, "Invalid number of tokens in -D ALL.\n"); + exit(1); + } + log_hdump_all = true; + } else { + if (!args.empty() && !args[0].empty() && args[0].back() == '.') + args[0].pop_back(); + if (GetSize(args) == 1) + args.push_back("yosys_dump_" + args[0] + ".il"); + if (GetSize(args) != 2) { + fprintf(stderr, "Invalid number of tokens in -D.\n"); + exit(1); + } + log_hdump[args[0]].insert(args[1]); + } + } + break; default: fprintf(stderr, "Run '%s -h' for help.\n", argv[0]); exit(1); @@ -482,6 +509,11 @@ int main(int argc, char **argv) free(hist_list); #endif + log_flush(); +#ifdef _WIN32 + _Exit(0); +#endif + yosys_shutdown(); return 0; diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 280b1693..3c824b8c 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -10,6 +10,7 @@ // ------------------------------------------------------- #ifndef HASHLIB_H +#define HASHLIB_H #include <stdexcept> #include <algorithm> @@ -136,8 +137,8 @@ struct hash_cstr_ops { static inline unsigned int hash(const char *a) { unsigned int hash = mkhash_init; while (*a) - hash = mkhash(hash, *(a++)); - return hash; + hash = mkhash(hash, *(a++)); + return hash; } }; @@ -156,7 +157,7 @@ struct hash_obj_ops { } template<typename T> static inline unsigned int hash(const T *a) { - return a->hash(); + return a ? a->hash() : 0; } }; diff --git a/kernel/log.cc b/kernel/log.cc index 4f395c75..3f1d8881 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -40,6 +40,8 @@ YOSYS_NAMESPACE_BEGIN std::vector<FILE*> log_files; std::vector<std::ostream*> log_streams; +std::map<std::string, std::set<std::string>> log_hdump; +bool log_hdump_all = false; FILE *log_errfile = NULL; SHA1 *log_hasher = NULL; @@ -136,7 +138,7 @@ void logv(const char *format, va_list ap) *f << str; } -void logv_header(const char *format, va_list ap) +void logv_header(RTLIL::Design *design, const char *format, va_list ap) { bool pop_errfile = false; @@ -149,12 +151,24 @@ void logv_header(const char *format, va_list ap) pop_errfile = true; } + std::string header_id; + for (int c : header_count) - log("%d.", c); - log(" "); + header_id += stringf("%s%d", header_id.empty() ? "" : ".", c); + + log("%s. ", header_id.c_str()); logv(format, ap); log_flush(); + if (log_hdump_all) + log_hdump[header_id].insert("yosys_dump_" + header_id + ".il"); + + 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()); + Pass::call(design, {"dump", "-o", filename}); + } + if (pop_errfile) log_files.pop_back(); } @@ -194,7 +208,7 @@ void logv_error(const char *format, va_list ap) log_files = backup_log_files; throw 0; #else - exit(1); + _Exit(1); #endif } @@ -206,11 +220,11 @@ void log(const char *format, ...) va_end(ap); } -void log_header(const char *format, ...) +void log_header(RTLIL::Design *design, const char *format, ...) { va_list ap; va_start(ap, format); - logv_header(format, ap); + logv_header(design, format, ap); va_end(ap); } @@ -400,6 +414,24 @@ const char *log_signal(const RTLIL::SigSpec &sig, bool autoint) } } +const char *log_const(const RTLIL::Const &value, bool autoint) +{ + if ((value.flags & RTLIL::CONST_FLAG_STRING) == 0) + return log_signal(value, autoint); + + std::string str = "\"" + value.decode_string() + "\""; + + if (string_buf.size() < 100) { + string_buf.push_back(str); + return string_buf.back().c_str(); + } else { + if (++string_buf_index == 100) + string_buf_index = 0; + string_buf[string_buf_index] = str; + return string_buf[string_buf_index].c_str(); + } +} + const char *log_id(RTLIL::IdString str) { log_id_cache.insert(str); @@ -413,6 +445,13 @@ const char *log_id(RTLIL::IdString str) return p+1; } +void log_module(RTLIL::Module *module, std::string indent) +{ + std::stringstream buf; + ILANG_BACKEND::dump_module(buf, indent, module, module->design, false); + log("%s", buf.str().c_str()); +} + void log_cell(RTLIL::Cell *cell, std::string indent) { std::stringstream buf; diff --git a/kernel/log.h b/kernel/log.h index 28baf988..53480db3 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -47,6 +47,8 @@ struct log_cmd_error_exception { }; extern std::vector<FILE*> log_files; extern std::vector<std::ostream*> log_streams; +extern std::map<std::string, std::set<std::string>> log_hdump; +extern bool log_hdump_all; extern FILE *log_errfile; extern SHA1 *log_hasher; @@ -58,12 +60,12 @@ extern int log_verbose_level; extern string log_last_error; void logv(const char *format, va_list ap); -void logv_header(const char *format, va_list ap); +void logv_header(RTLIL::Design *design, const char *format, va_list ap); void logv_warning(const char *format, va_list ap); YS_NORETURN void logv_error(const char *format, va_list ap) YS_ATTRIBUTE(noreturn); void log(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); -void log_header(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)); YS_NORETURN void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn); YS_NORETURN void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn); @@ -77,12 +79,14 @@ void log_reset_stack(); void log_flush(); 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) { return log_id(obj->name); } +void log_module(RTLIL::Module *module, std::string indent = ""); void log_cell(RTLIL::Cell *cell, std::string indent = ""); #ifndef NDEBUG @@ -161,11 +165,13 @@ struct PerformanceTimer } static int64_t query() { -#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) +# if _WIN32 + return 0; +# elif defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) struct timespec ts; clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts); return int64_t(ts.tv_sec)*1000000000 + ts.tv_nsec; -#elif defined(RUSAGE_SELF) +# elif defined(RUSAGE_SELF) struct rusage rusage; int64_t t; if (getrusage(RUSAGE_SELF, &rusage) == -1) { @@ -175,11 +181,9 @@ struct PerformanceTimer t = 1000000000ULL * (int64_t) rusage.ru_utime.tv_sec + (int64_t) rusage.ru_utime.tv_usec * 1000ULL; t += 1000000000ULL * (int64_t) rusage.ru_stime.tv_sec + (int64_t) rusage.ru_stime.tv_usec * 1000ULL; return t; -#elif _WIN32 - return 0; -#else - #error Dont know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?). -#endif +# else +# error Dont know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?). +# endif } void reset() { @@ -230,6 +234,32 @@ static inline void log_dump_args_worker(const char *p YS_ATTRIBUTE(unused)) { lo void log_dump_val_worker(RTLIL::IdString v); void log_dump_val_worker(RTLIL::SigSpec v); +template<typename K, typename T, typename OPS> +static inline void log_dump_val_worker(dict<K, T, OPS> &v) { + log("{"); + bool first = true; + for (auto &it : v) { + log(first ? " " : ", "); + log_dump_val_worker(it.first); + log(": "); + log_dump_val_worker(it.second); + first = false; + } + log(" }"); +} + +template<typename K, typename OPS> +static inline void log_dump_val_worker(pool<K, OPS> &v) { + log("{"); + bool first = true; + for (auto &it : v) { + log(first ? " " : ", "); + log_dump_val_worker(it); + first = false; + } + log(" }"); +} + template<typename T> static inline void log_dump_val_worker(T *ptr) { log("%p", ptr); } diff --git a/kernel/register.cc b/kernel/register.cc index 49a67324..7a1d0b44 100644 --- a/kernel/register.cc +++ b/kernel/register.cc @@ -80,6 +80,7 @@ Pass::pre_post_exec_state_t Pass::pre_execute() state.begin_ns = PerformanceTimer::query(); state.parent_pass = current_pass; current_pass = this; + clear_flags(); return state; } @@ -99,6 +100,10 @@ void Pass::help() log("\n"); } +void Pass::clear_flags() +{ +} + void Pass::cmd_log_args(const std::vector<std::string> &args) { if (args.size() <= 1) @@ -160,7 +165,7 @@ void Pass::call(RTLIL::Design *design, std::string command) while (!cmd_buf.empty() && (cmd_buf.back() == ' ' || cmd_buf.back() == '\t' || cmd_buf.back() == '\r' || cmd_buf.back() == '\n')) cmd_buf.resize(cmd_buf.size()-1); - log_header("Shell command: %s\n", cmd_buf.c_str()); + log_header(design, "Shell command: %s\n", cmd_buf.c_str()); int retCode = run_command(cmd_buf); if (retCode != 0) log_cmd_error("Shell command returned error code %d.\n", retCode); @@ -282,6 +287,60 @@ void Pass::call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::vec design->selected_active_module = backup_selected_active_module; } +bool ScriptPass::check_label(std::string label, std::string info) +{ + if (active_design == nullptr) { + log("\n"); + if (info.empty()) + log(" %s:\n", label.c_str()); + else + log(" %s: %s\n", label.c_str(), info.c_str()); + return true; + } else { + if (!active_run_from.empty() && active_run_from == active_run_to) { + block_active = (label == active_run_from); + } else { + if (label == active_run_from) + block_active = true; + if (label == active_run_to) + block_active = false; + } + return block_active; + } +} + +void ScriptPass::run(std::string command, std::string info) +{ + if (active_design == nullptr) { + if (info.empty()) + log(" %s\n", command.c_str()); + else + log(" %s %s\n", command.c_str(), info.c_str()); + } else + Pass::call(active_design, command); +} + +void ScriptPass::run_script(RTLIL::Design *design, std::string run_from, std::string run_to) +{ + help_mode = false; + active_design = design; + block_active = run_from.empty(); + active_run_from = run_from; + active_run_to = run_to; + script(); +} + +void ScriptPass::help_script() +{ + clear_flags(); + help_mode = true; + active_design = nullptr; + block_active = true; + active_run_from.clear(); + active_run_to.clear(); + script(); +} + Frontend::Frontend(std::string name, std::string short_help) : Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "read_" + name, short_help), frontend_name(name.rfind("=", 0) == 0 ? name.substr(1) : name) @@ -323,7 +382,8 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s bool called_with_fp = f != NULL; next_args.clear(); - for (; argidx < args.size(); argidx++) + + if (argidx < args.size()) { std::string arg = args[argidx]; @@ -360,6 +420,12 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s f = new std::istringstream(last_here_document); } else { rewrite_filename(filename); + vector<string> filenames = glob_filename(filename); + filename = filenames.front(); + if (GetSize(filenames) > 1) { + next_args.insert(next_args.end(), args.begin(), args.begin()+argidx); + next_args.insert(next_args.end(), filenames.begin()+1, filenames.end()); + } std::ifstream *ff = new std::ifstream; ff->open(filename.c_str()); if (ff->fail()) @@ -375,12 +441,13 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s cmd_error(args, i, "Found option, expected arguments."); if (argidx+1 < args.size()) { - next_args.insert(next_args.begin(), args.begin(), args.begin()+argidx); - next_args.insert(next_args.begin()+argidx, args.begin()+argidx+1, args.end()); + if (next_args.empty()) + next_args.insert(next_args.end(), args.begin(), args.begin()+argidx); + next_args.insert(next_args.end(), args.begin()+argidx+1, args.end()); args.erase(args.begin()+argidx+1, args.end()); } - break; } + if (f == NULL) cmd_error(args, argidx, "No filename given."); diff --git a/kernel/register.h b/kernel/register.h index 0ef07b76..8024c56a 100644 --- a/kernel/register.h +++ b/kernel/register.h @@ -31,6 +31,7 @@ struct Pass virtual ~Pass(); virtual void help(); + virtual void clear_flags(); virtual void execute(std::vector<std::string> args, RTLIL::Design *design) = 0; int call_counter; @@ -63,6 +64,22 @@ struct Pass static void done_register(); }; +struct ScriptPass : Pass +{ + bool block_active, help_mode; + RTLIL::Design *active_design; + std::string active_run_from, active_run_to; + + ScriptPass(std::string name, std::string short_help = "** document me **") : Pass(name, short_help) { } + + virtual void script() = 0; + + bool check_label(std::string label, std::string info = std::string()); + void run(std::string command, std::string info = std::string()); + void run_script(RTLIL::Design *design, std::string run_from = std::string(), std::string run_to = std::string()); + void help_script(); +}; + struct Frontend : Pass { // for reading of here documents diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index a706491e..32efe4f0 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -304,6 +304,8 @@ RTLIL::Design::~Design() { for (auto it = modules_.begin(); it != modules_.end(); ++it) delete it->second; + for (auto n : verilog_packages) + delete n; } RTLIL::ObjRange<RTLIL::Module*> RTLIL::Design::modules() @@ -845,6 +847,15 @@ namespace { return; } + if (cell->type == "$sop") { + param("\\DEPTH"); + param("\\TABLE"); + port("\\A", param("\\WIDTH")); + port("\\Y", 1); + check_expected(); + return; + } + if (cell->type == "$sr") { param_bool("\\SET_POLARITY"); param_bool("\\CLR_POLARITY"); @@ -1006,16 +1017,21 @@ namespace { return; } - if (cell->type == "$assert") { + if (cell->type.in("$assert", "$assume")) { port("\\A", 1); port("\\EN", 1); check_expected(); return; } - if (cell->type == "$assume") { - port("\\A", 1); - port("\\EN", 1); + if (cell->type == "$initstate") { + port("\\Y", 1); + check_expected(); + return; + } + + if (cell->type == "$anyconst") { + port("\\Y", param("\\WIDTH")); check_expected(); return; } @@ -1466,6 +1482,7 @@ void RTLIL::Module::connect(const RTLIL::SigSig &conn) log_backtrace("-X- ", yosys_xtrace-1); } + log_assert(GetSize(conn.first) == GetSize(conn.second)); connections_.push_back(conn); } @@ -1784,6 +1801,14 @@ RTLIL::Cell* RTLIL::Module::addAssert(RTLIL::IdString name, RTLIL::SigSpec sig_a return cell; } +RTLIL::Cell* RTLIL::Module::addAssume(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en) +{ + RTLIL::Cell *cell = addCell(name, "$assume"); + cell->setPort("\\A", sig_a); + cell->setPort("\\EN", sig_en); + return cell; +} + RTLIL::Cell* RTLIL::Module::addEquiv(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y) { RTLIL::Cell *cell = addCell(name, "$equiv"); @@ -1950,6 +1975,22 @@ RTLIL::Cell* RTLIL::Module::addDlatchsrGate(RTLIL::IdString name, RTLIL::SigSpec return cell; } +RTLIL::SigSpec RTLIL::Module::Anyconst(RTLIL::IdString name, int width) +{ + RTLIL::SigSpec sig = addWire(NEW_ID, width); + Cell *cell = addCell(name, "$anyconst"); + cell->setParam("\\WIDTH", width); + cell->setPort("\\Y", sig); + return sig; +} + +RTLIL::SigSpec RTLIL::Module::Initstate(RTLIL::IdString name) +{ + RTLIL::SigSpec sig = addWire(NEW_ID); + Cell *cell = addCell(name, "$initstate"); + cell->setPort("\\Y", sig); + return sig; +} RTLIL::Wire::Wire() { @@ -2133,7 +2174,7 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed) return; } - if (type == "$lut") { + if (type == "$lut" || type == "$sop") { parameters["\\WIDTH"] = GetSize(connections_["\\A"]); return; } diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 940e36ab..a426e0bd 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -792,6 +792,7 @@ struct RTLIL::Design int refcount_modules_; dict<RTLIL::IdString, RTLIL::Module*> modules_; + std::vector<AST::AstNode*> verilog_packages; std::vector<RTLIL::Selection> selection_stack; dict<RTLIL::IdString, RTLIL::Selection> selection_vars; @@ -1003,6 +1004,7 @@ public: RTLIL::Cell* addLut (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, RTLIL::Const lut); RTLIL::Cell* addTribuf (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_y); RTLIL::Cell* addAssert (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en); + RTLIL::Cell* addAssume (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en); RTLIL::Cell* addEquiv (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y); RTLIL::Cell* addSr (RTLIL::IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, RTLIL::SigSpec sig_q, bool set_polarity = true, bool clr_polarity = true); @@ -1101,6 +1103,9 @@ public: RTLIL::SigBit Oai3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c); RTLIL::SigBit Aoi4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d); RTLIL::SigBit Oai4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d); + + RTLIL::SigSpec Anyconst (RTLIL::IdString name, int width = 1); + RTLIL::SigSpec Initstate (RTLIL::IdString name); }; struct RTLIL::Wire : public RTLIL::AttrObject diff --git a/kernel/satgen.h b/kernel/satgen.h index d44d61f1..0a65b490 100644 --- a/kernel/satgen.h +++ b/kernel/satgen.h @@ -70,6 +70,7 @@ struct SatGen std::map<std::string, RTLIL::SigSpec> asserts_a, asserts_en; std::map<std::string, RTLIL::SigSpec> assumes_a, assumes_en; std::map<std::string, std::map<RTLIL::SigBit, int>> imported_signals; + std::map<std::pair<std::string, int>, bool> initstates; bool ignore_div_by_zero; bool model_undef; @@ -266,6 +267,13 @@ struct SatGen ez->assume(ez->OR(undef, ez->IFF(y, yy))); } + void setInitState(int timestep) + { + auto key = make_pair(prefix, timestep); + log_assert(initstates.count(key) == 0 || initstates.at(key) == true); + initstates[key] = true; + } + bool importCell(RTLIL::Cell *cell, int timestep = -1) { bool arith_undef_handled = false; @@ -1048,6 +1056,88 @@ struct SatGen return true; } + if (cell->type == "$sop") + { + std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); + int y = importDefSigSpec(cell->getPort("\\Y"), timestep).at(0); + + int width = cell->getParam("\\WIDTH").as_int(); + int depth = cell->getParam("\\DEPTH").as_int(); + + vector<State> table_raw = cell->getParam("\\TABLE").bits; + while (GetSize(table_raw) < 2*width*depth) + table_raw.push_back(State::S0); + + vector<vector<int>> table(depth); + + for (int i = 0; i < depth; i++) + for (int j = 0; j < width; j++) + { + bool pat0 = (table_raw[2*width*i + 2*j + 0] == State::S1); + bool pat1 = (table_raw[2*width*i + 2*j + 1] == State::S1); + + if (pat0 && !pat1) + table.at(i).push_back(0); + else if (!pat0 && pat1) + table.at(i).push_back(1); + else + table.at(i).push_back(-1); + } + + if (model_undef) + { + std::vector<int> products, undef_products; + std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); + int undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep).at(0); + + for (int i = 0; i < depth; i++) + { + std::vector<int> cmp_a, cmp_ua, cmp_b; + + for (int j = 0; j < width; j++) + if (table.at(i).at(j) >= 0) { + cmp_a.push_back(a.at(j)); + cmp_ua.push_back(undef_a.at(j)); + cmp_b.push_back(table.at(i).at(j) ? ez->CONST_TRUE : ez->CONST_FALSE); + } + + std::vector<int> masked_a = ez->vec_or(cmp_a, cmp_ua); + std::vector<int> masked_b = ez->vec_or(cmp_b, cmp_ua); + + int masked_eq = ez->vec_eq(masked_a, masked_b); + int any_undef = ez->expression(ezSAT::OpOr, cmp_ua); + + undef_products.push_back(ez->AND(any_undef, masked_eq)); + products.push_back(ez->AND(ez->NOT(any_undef), masked_eq)); + } + + int yy = ez->expression(ezSAT::OpOr, products); + ez->SET(undef_y, ez->AND(ez->NOT(yy), ez->expression(ezSAT::OpOr, undef_products))); + undefGating(y, yy, undef_y); + } + else + { + std::vector<int> products; + + for (int i = 0; i < depth; i++) + { + std::vector<int> cmp_a, cmp_b; + + for (int j = 0; j < width; j++) + if (table.at(i).at(j) >= 0) { + cmp_a.push_back(a.at(j)); + cmp_b.push_back(table.at(i).at(j) ? ez->CONST_TRUE : ez->CONST_FALSE); + } + + products.push_back(ez->vec_eq(cmp_a, cmp_b)); + } + + ez->SET(y, ez->expression(ezSAT::OpOr, products)); + } + + return true; + } + if (cell->type == "$fa") { std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); @@ -1229,6 +1319,28 @@ struct SatGen return true; } + if (cell->type == "$anyconst") + { + if (timestep < 2) + return true; + + std::vector<int> d = importDefSigSpec(cell->getPort("\\Y"), timestep-1); + std::vector<int> q = importDefSigSpec(cell->getPort("\\Y"), timestep); + + std::vector<int> qq = model_undef ? ez->vec_var(q.size()) : q; + ez->assume(ez->vec_eq(d, qq)); + + if (model_undef) + { + std::vector<int> undef_d = importUndefSigSpec(cell->getPort("\\D"), timestep-1); + std::vector<int> undef_q = importUndefSigSpec(cell->getPort("\\Q"), timestep); + + ez->assume(ez->vec_eq(undef_d, undef_q)); + undefGating(q, qq, undef_q); + } + return true; + } + if (cell->type == "$_BUF_" || cell->type == "$equiv") { std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); @@ -1248,6 +1360,25 @@ struct SatGen return true; } + if (cell->type == "$initstate") + { + auto key = make_pair(prefix, timestep); + if (initstates.count(key) == 0) + initstates[key] = false; + + std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); + log_assert(GetSize(y) == 1); + ez->SET(y[0], initstates[key] ? ez->CONST_TRUE : ez->CONST_FALSE); + + if (model_undef) { + std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + log_assert(GetSize(undef_y) == 1); + ez->SET(undef_y[0], ez->CONST_FALSE); + } + + return true; + } + if (cell->type == "$assert") { std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); diff --git a/kernel/yosys.cc b/kernel/yosys.cc index eba1aef1..08fee974 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -37,11 +37,13 @@ # 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/stat.h> +# include <glob.h> #endif #include <limits.h> @@ -104,7 +106,7 @@ void yosys_banner() log(" | |\n"); log(" | yosys -- Yosys Open SYnthesis Suite |\n"); log(" | |\n"); - log(" | Copyright (C) 2012 - 2015 Clifford Wolf <clifford@clifford.at> |\n"); + log(" | Copyright (C) 2012 - 2016 Clifford Wolf <clifford@clifford.at> |\n"); log(" | |\n"); log(" | Permission to use, copy, modify, and/or distribute this software for any |\n"); log(" | purpose with or without fee is hereby granted, provided that the above |\n"); @@ -547,6 +549,29 @@ const char *create_prompt(RTLIL::Design *design, int recursion_counter) return buffer; } +std::vector<std::string> glob_filename(const std::string &filename_pattern) +{ + std::vector<std::string> results; + +#ifdef _WIN32 + results.push_back(filename_pattern); +#else + glob_t globbuf; + + int err = glob(filename_pattern.c_str(), 0, NULL, &globbuf); + + if(err == 0) { + for (size_t i = 0; i < globbuf.gl_pathc; i++) + results.push_back(globbuf.gl_pathv[i]); + globfree(&globbuf); + } else { + results.push_back(filename_pattern); + } +#endif + + return results; +} + void rewrite_filename(std::string &filename) { if (filename.substr(0, 1) == "\"" && filename.substr(GetSize(filename)-1) == "\"") @@ -622,7 +647,7 @@ struct TclPass : public Pass { } TclPass; #endif -#if defined(__linux__) +#if defined(__linux__) || defined(__CYGWIN__) std::string proc_self_dirname() { char path[PATH_MAX]; @@ -687,7 +712,7 @@ std::string proc_share_dirname() std::string proc_share_dirname() { std::string proc_self_path = proc_self_dirname(); -# ifdef _WIN32 +# if defined(_WIN32) && !defined(YOSYS_WIN32_UNIX_DIR) std::string proc_share_path = proc_self_path + "share\\"; if (check_file_exists(proc_share_path, true)) return proc_share_path; @@ -701,6 +726,11 @@ std::string proc_share_dirname() proc_share_path = proc_self_path + "../share/yosys/"; if (check_file_exists(proc_share_path, true)) return proc_share_path; +# ifdef YOSYS_DATDIR + proc_share_path = YOSYS_DATDIR "/"; + if (check_file_exists(proc_share_path, true)) + return proc_share_path; +# endif # endif log_error("proc_share_dirname: unable to determine share/ directory!\n"); } @@ -758,6 +788,8 @@ 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") + command = "vhdl"; else if (filename.size() > 4 && filename.substr(filename.size()-5) == ".blif") command = "blif"; else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") @@ -1093,8 +1125,8 @@ struct HistoryPass : public Pass { } HistoryPass; #endif -struct ScriptPass : public Pass { - ScriptPass() : Pass("script", "execute commands from script file") { } +struct ScriptCmdPass : public Pass { + ScriptCmdPass() : Pass("script", "execute commands from script file") { } virtual void help() { log("\n"); log(" script <filename> [<from_label>:<to_label>]\n"); @@ -1120,7 +1152,6 @@ struct ScriptPass : public Pass { else extra_args(args, 2, design, false); } -} ScriptPass; +} ScriptCmdPass; YOSYS_NAMESPACE_END - diff --git a/kernel/yosys.h b/kernel/yosys.h index c8bc46b6..aab6b584 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -51,6 +51,7 @@ #include <initializer_list> #include <stdexcept> #include <memory> +#include <cmath> #include <sstream> #include <fstream> @@ -91,9 +92,9 @@ # define mkdir _mkdir # define popen _popen # define pclose _pclose -# define PATH_MAX MAX_PATH # ifndef __MINGW32__ +# define PATH_MAX MAX_PATH # define isatty _isatty # define fileno _fileno # endif @@ -279,6 +280,7 @@ RTLIL::Design *yosys_get_design(); std::string proc_self_dirname(); std::string proc_share_dirname(); const char *create_prompt(RTLIL::Design *design, int recursion_counter); +std::vector<std::string> glob_filename(const std::string &filename_pattern); void rewrite_filename(std::string &filename); void run_pass(std::string command, RTLIL::Design *design = nullptr); diff --git a/manual/APPNOTE_012_Verilog_to_BTOR.tex b/manual/APPNOTE_012_Verilog_to_BTOR.tex index 245a6b0b..1bc27787 100644 --- a/manual/APPNOTE_012_Verilog_to_BTOR.tex +++ b/manual/APPNOTE_012_Verilog_to_BTOR.tex @@ -208,7 +208,7 @@ read_verilog -sv $1; hierarchy -top $3; hierarchy -libdir $DIR; hierarchy -check; proc; opt; -opt_const -mux_undef; opt; +opt_expr -mux_undef; opt; rename -hide;;; splice; opt; memory_dff -wr_only; memory_collect;; @@ -263,7 +263,7 @@ read_verilog -sv $1; hierarchy -top $3; hierarchy -libdir $DIR; hierarchy -check; proc; opt; -opt_const -mux_undef; opt; +opt_expr -mux_undef; opt; rename -hide;;; splice; opt; memory;; diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex index c648eb1f..bd73ae23 100644 --- a/manual/CHAPTER_CellLib.tex +++ b/manual/CHAPTER_CellLib.tex @@ -421,7 +421,7 @@ pass. The combinatorial logic cells can be mapped to physical cells from a Liber using the {\tt abc} pass. \begin{fixme} -Add information about {\tt \$assert}, {\tt \$assume}, and {\tt \$equiv} cells. +Add information about {\tt \$assert}, {\tt \$assume}, {\tt \$equiv}, {\tt \$initstate}, and {\tt \$anyconst} cells. \end{fixme} \begin{fixme} @@ -429,6 +429,10 @@ Add information about {\tt \$slice} and {\tt \$concat} cells. \end{fixme} \begin{fixme} +Add information about {\tt \$lut} and {\tt \$sop} cells. +\end{fixme} + +\begin{fixme} Add information about {\tt \$alu}, {\tt \$macc}, {\tt \$fa}, and {\tt \$lcu} cells. \end{fixme} diff --git a/manual/CHAPTER_Optimize.tex b/manual/CHAPTER_Optimize.tex index d09b3c47..eee92ef5 100644 --- a/manual/CHAPTER_Optimize.tex +++ b/manual/CHAPTER_Optimize.tex @@ -15,23 +15,23 @@ passes that each perform a simple optimization: \begin{itemize} \item Once at the beginning of {\tt opt}: \begin{itemize} -\item {\tt opt\_const} -\item {\tt opt\_share -nomux} +\item {\tt opt\_expr} +\item {\tt opt\_merge -nomux} \end{itemize} \item Repeat until result is stable: \begin{itemize} \item {\tt opt\_muxtree} \item {\tt opt\_reduce} -\item {\tt opt\_share} +\item {\tt opt\_merge} \item {\tt opt\_rmdff} \item {\tt opt\_clean} -\item {\tt opt\_const} +\item {\tt opt\_expr} \end{itemize} \end{itemize} The following section describes each of the {\tt opt\_*} passes. -\subsection{The opt\_const pass} +\subsection{The opt\_expr pass} This pass performs const folding on the internal combinational cell types described in Chap.~\ref{chapter:celllib}. This means a cell with all constant @@ -57,11 +57,11 @@ this pass can also optimize cells with some constant inputs. $a$ & 1 & $a$ \\ 1 & $b$ & $b$ \\ \end{tabular} - \caption{Const folding rules for {\tt\$\_AND\_} cells as used in {\tt opt\_const}.} - \label{tab:opt_const_and} + \caption{Const folding rules for {\tt\$\_AND\_} cells as used in {\tt opt\_expr}.} + \label{tab:opt_expr_and} \end{table} -Table~\ref{tab:opt_const_and} shows the replacement rules used for optimizing +Table~\ref{tab:opt_expr_and} shows the replacement rules used for optimizing an {\tt\$\_AND\_} gate. The first three rules implement the obvious const folding rules. Note that `any' might include dynamic values calculated by other parts of the circuit. The following three lines propagate undef (X) states. @@ -76,10 +76,10 @@ an undef value or a 1 and therefore the output can be set to undef. The last two lines simply replace an {\tt\$\_AND\_} gate with one constant-1 input with a buffer. -Besides this basic const folding the {\tt opt\_const} pass can replace 1-bit wide +Besides this basic const folding the {\tt opt\_expr} pass can replace 1-bit wide {\tt \$eq} and {\tt \$ne} cells with buffers or not-gates if one input is constant. -The {\tt opt\_const} pass is very conservative regarding optimizing {\tt \$mux} cells, +The {\tt opt\_expr} pass is very conservative regarding optimizing {\tt \$mux} cells, as these cells are often used to model decision-trees and breaking these trees can interfere with other optimizations. @@ -130,7 +130,7 @@ This pass identifies unused signals and cells and removes them from the design. creates an \B{unused\_bits} attribute on wires with unused bits. This attribute can be used for debugging or by other optimization passes. -\subsection{The opt\_share pass} +\subsection{The opt\_merge pass} This pass performs trivial resource sharing. This means that this pass identifies cells with identical inputs and replaces them with a single instance of the cell. @@ -222,6 +222,10 @@ This heuristic has proven to work very well. It is possible to overwrite it by s and setting \B{fsm\_encoding}{\tt = "none"} on registers that match the above criteria but should not be considered FSM state registers. +Note however that marking state registers with \B{fsm\_encoding} that are not +suitable for FSM recoding can cause synthesis to fail or produce invalid +results. + \subsection{FSM Extraction} The {\tt fsm\_extract} pass operates on all state signals marked with the diff --git a/manual/CHAPTER_Overview.tex b/manual/CHAPTER_Overview.tex index 032c0f8c..964875d5 100644 --- a/manual/CHAPTER_Overview.tex +++ b/manual/CHAPTER_Overview.tex @@ -488,8 +488,8 @@ select.cc}, {\tt show.cc}, \dots) and a couple of other small utility libraries. \item {\tt passes/} \\ This directory contains a subdirectory for each pass or group of passes. For example as of this writing the directory {\tt passes/opt/} contains the code for seven -passes: {\tt opt}, {\tt opt\_const}, {\tt opt\_muxtree}, {\tt opt\_reduce}, -{\tt opt\_rmdff}, {\tt opt\_rmunused} and {\tt opt\_share}. +passes: {\tt opt}, {\tt opt\_expr}, {\tt opt\_muxtree}, {\tt opt\_reduce}, +{\tt opt\_rmdff}, {\tt opt\_rmunused} and {\tt opt\_merge}. \item {\tt techlibs/} \\ This directory contains simulation models and standard implementations for the @@ -513,7 +513,7 @@ Yosys. So it is not needed to add additional commands to a central list of comma \end{sloppypar} Good starting points for reading example source code to learn how to write passes -are {\tt passes/opt/opt\_rmdff.cc} and {\tt passes/opt/opt\_share.cc}. +are {\tt passes/opt/opt\_rmdff.cc} and {\tt passes/opt/opt\_merge.cc}. See the top-level README file for a quick {\it Getting Started} guide and build instructions. The Yosys build is based solely on Makefiles. diff --git a/manual/CHAPTER_Prog/stubnets.cc b/manual/CHAPTER_Prog/stubnets.cc index 976107fb..eb77bd40 100644 --- a/manual/CHAPTER_Prog/stubnets.cc +++ b/manual/CHAPTER_Prog/stubnets.cc @@ -103,7 +103,7 @@ struct StubnetsPass : public Pass { // variables to mirror information from passed options bool report_bits = 0; - log_header("Executing STUBNETS pass (find stub nets).\n"); + log_header(design, "Executing STUBNETS pass (find stub nets).\n"); // parse options size_t argidx; diff --git a/manual/PRESENTATION_ExSyn.tex b/manual/PRESENTATION_ExSyn.tex index 1b56374d..655720eb 100644 --- a/manual/PRESENTATION_ExSyn.tex +++ b/manual/PRESENTATION_ExSyn.tex @@ -144,16 +144,16 @@ The {\tt opt} command implements a series of simple optimizations. It also is a macro command that calls other commands: \begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -opt_const # const folding -opt_share -nomux # merging identical cells +opt_expr # const folding and simple expression rewriting +opt_merge -nomux # merging identical cells do opt_muxtree # remove never-active branches from multiplexer tree opt_reduce # consolidate trees of boolean ops to reduce functions - opt_share # merging identical cells + opt_merge # merging identical cells opt_rmdff # remove/simplify registers with constant inputs opt_clean # remove unused objects (cells, wires) from design - opt_const # const folding + opt_expr # const folding and simple expression rewriting while [changed design] \end{lstlisting} @@ -161,7 +161,7 @@ The command {\tt clean} can be used as alias for {\tt opt\_clean}. And {\tt ;;} can be used as shortcut for {\tt clean}. For example: \begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -proc; opt; memory; opt_const;; fsm;; +proc; opt; memory; opt_expr;; fsm;; \end{lstlisting} \end{frame} diff --git a/manual/PRESENTATION_Prog.tex b/manual/PRESENTATION_Prog.tex index 6b105a70..b85eda89 100644 --- a/manual/PRESENTATION_Prog.tex +++ b/manual/PRESENTATION_Prog.tex @@ -477,7 +477,7 @@ log("Name of this module: %s\n", log_id(module->name)); \medskip Use {\tt log\_header()} and {\tt log\_push()}/{\tt log\_pop()} to structure log messages: \begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] -log_header("Doing important stuff!\n"); +log_header(design, "Doing important stuff!\n"); log_push(); for (int i = 0; i < 10; i++) log("Log message #%d.\n", i); @@ -534,7 +534,7 @@ struct MyPass : public Pass { log("Modules in current design:\n"); for (auto mod : design->modules()) log(" %s (%d wires, %d cells)\n", log_id(mod), - GetSize(mod->wires), GetSize(mod->cells)); + GetSize(mod->wires()), GetSize(mod->cells())); } } MyPass; \end{lstlisting} diff --git a/manual/PRESENTATION_Prog/my_cmd.cc b/manual/PRESENTATION_Prog/my_cmd.cc index 1d28ce97..d99bfe1e 100644 --- a/manual/PRESENTATION_Prog/my_cmd.cc +++ b/manual/PRESENTATION_Prog/my_cmd.cc @@ -65,7 +65,7 @@ struct Test2Pass : public Pass { log("Mapped signal x: %s\n", log_signal(sigmap(x))); - log_header("Doing important stuff!\n"); + log_header(design, "Doing important stuff!\n"); log_push(); for (int i = 0; i < 10; i++) log("Log message #%d.\n", i); diff --git a/manual/command-reference-manual.tex b/manual/command-reference-manual.tex index 99d4a1fa..425d89b6 100644 --- a/manual/command-reference-manual.tex +++ b/manual/command-reference-manual.tex @@ -3783,10 +3783,10 @@ The following node-types may be used: - the inverted value of the specified input port bit [ "and", <node-index>, <node-index>, <out-list> ] - - the ANDed value of the speciefied nodes + - the ANDed value of the specified nodes [ "nand", <node-index>, <node-index>, <out-list> ] - - the inverted ANDed value of the speciefied nodes + - the inverted ANDed value of the specified nodes [ "true", <out-list> ] - the constant value 1 @@ -3817,7 +3817,7 @@ inferred by the following code: ] Future version of Yosys might add support for additional fields in the JSON -format. A program processing this format must ignore all unkown fields. +format. A program processing this format must ignore all unknown fields. \end{lstlisting} \section{write\_smt2 -- write design to SMT-LIBv2 file} diff --git a/manual/manual.tex b/manual/manual.tex index ecc7e4c9..67982cbc 100644 --- a/manual/manual.tex +++ b/manual/manual.tex @@ -151,14 +151,14 @@ availability of a Free and Open Source (FOSS) synthesis tool that can be used as basis for custom tools would be helpful. In the absence of such a tool, the Yosys Open SYnthesis Suite (Yosys) was -developped. This document covers the design and implementation of this tool. +developed. This document covers the design and implementation of this tool. At the moment the main focus of Yosys lies on the high-level aspects of digital synthesis. The pre-existing FOSS logic-synthesis tool ABC is used by Yosys to perform advanced gate-level optimizations. An evaluation of Yosys based on real-world designs is included. It is shown that Yosys can be used as-is to synthesize such designs. The results produced -by Yosys in this tests where successflly verified using formal verification +by Yosys in this tests where successfully verified using formal verification and are comparable in quality to the results produced by a commercial synthesis tool. @@ -172,7 +172,7 @@ University of Technology \cite{BACC}. AIG & And-Inverter-Graph \\ ASIC & Application-Specific Integrated Circuit \\ AST & Abstract Syntax Tree \\ -BDD & Binary Decicion Diagram \\ +BDD & Binary Decision Diagram \\ BLIF & Berkeley Logic Interchange Format \\ EDA & Electronic Design Automation \\ EDIF & Electronic Design Interchange Format \\ diff --git a/passes/cmds/check.cc b/passes/cmds/check.cc index 2ad84838..b3622cb1 100644 --- a/passes/cmds/check.cc +++ b/passes/cmds/check.cc @@ -68,7 +68,7 @@ struct CheckPass : public Pass { } extra_args(args, argidx, design); - log_header("Executing CHECK pass (checking for obvious problems).\n"); + log_header(design, "Executing CHECK pass (checking for obvious problems).\n"); for (auto module : design->selected_whole_modules_warn()) { diff --git a/passes/cmds/connwrappers.cc b/passes/cmds/connwrappers.cc index 7828dce1..c9ab226d 100644 --- a/passes/cmds/connwrappers.cc +++ b/passes/cmds/connwrappers.cc @@ -198,7 +198,7 @@ struct ConnwrappersPass : public Pass { } extra_args(args, argidx, design); - log_header("Executing CONNWRAPPERS pass (connect extended ports of wrapper cells).\n"); + log_header(design, "Executing CONNWRAPPERS pass (connect extended ports of wrapper cells).\n"); for (auto &mod_it : design->modules_) if (design->selected(mod_it.second)) diff --git a/passes/cmds/cover.cc b/passes/cmds/cover.cc index 5644066a..1475475c 100644 --- a/passes/cmds/cover.cc +++ b/passes/cmds/cover.cc @@ -124,7 +124,7 @@ struct CoverPass : public Pass { extra_args(args, argidx, design); if (do_log) { - log_header("Printing code coverage counters.\n"); + log_header(design, "Printing code coverage counters.\n"); log("\n"); } diff --git a/passes/cmds/plugin.cc b/passes/cmds/plugin.cc index e2d80d9b..828c671d 100644 --- a/passes/cmds/plugin.cc +++ b/passes/cmds/plugin.cc @@ -31,19 +31,23 @@ std::map<std::string, std::string> loaded_plugin_aliases; #ifdef YOSYS_ENABLE_PLUGINS void load_plugin(std::string filename, std::vector<std::string> aliases) { + std::string orig_filename = filename; + if (filename.find('/') == std::string::npos) filename = "./" + filename; if (!loaded_plugins.count(filename)) { void *hdl = dlopen(filename.c_str(), RTLD_LAZY|RTLD_LOCAL); + if (hdl == NULL && orig_filename.find('/') == std::string::npos) + hdl = dlopen((proc_share_dirname() + "plugins/" + orig_filename + ".so").c_str(), RTLD_LAZY|RTLD_LOCAL); if (hdl == NULL) log_cmd_error("Can't load module `%s': %s\n", filename.c_str(), dlerror()); - loaded_plugins[filename] = hdl; + loaded_plugins[orig_filename] = hdl; Pass::init_register(); } for (auto &alias : aliases) - loaded_plugin_aliases[alias] = filename; + loaded_plugin_aliases[alias] = orig_filename; } #else void load_plugin(std::string, std::vector<std::string>) diff --git a/passes/cmds/qwp.cc b/passes/cmds/qwp.cc index 8ec815a7..1b800b6d 100644 --- a/passes/cmds/qwp.cc +++ b/passes/cmds/qwp.cc @@ -40,6 +40,7 @@ struct QwpConfig { bool ltr; bool alpha; + bool verbose; double grid; std::ofstream dump_file; @@ -47,6 +48,7 @@ struct QwpConfig QwpConfig() { ltr = false; alpha = false; + verbose = false; grid = 1.0 / 16; } }; @@ -211,10 +213,16 @@ struct QwpWorker // // M := [AA Ay] + if (config.verbose) + log("> System size: %d^2\n", GetSize(nodes)); + // Row major order int N = GetSize(nodes), N1 = N+1; vector<double> M(N * N1); + if (config.verbose) + log("> Edge constraints: %d\n", GetSize(edges)); + // Edge constraints: // A[i,:] := [ 0 0 .... 0 weight 0 ... 0 -weight 0 ... 0 0], y[i] := 0 // @@ -232,6 +240,9 @@ struct QwpWorker M[idx2 + idx1*N1] += -weight * weight; } + if (config.verbose) + log("> Node constraints: %d\n", GetSize(nodes)); + // Node constraints: // A[i,:] := [ 0 0 .... 0 weight 0 ... 0 0], y[i] := weight * pos // @@ -263,6 +274,9 @@ struct QwpWorker } #endif + if (config.verbose) + log("> Solving\n"); + // Solve "AA*x = Ay" // (least squares fit for "A*x = y") // @@ -277,6 +291,9 @@ struct QwpWorker // gaussian elimination for (int i = 0; i < N; i++) { + if (config.verbose && ((i+1) % (N/15)) == 0) + log("> Solved %d%%: %d/%d\n", (100*(i+1))/N, i+1, N); + // find best row int best_row = queue.front(); int best_row_queue_idx = 0; @@ -312,6 +329,9 @@ struct QwpWorker } } + if (config.verbose) + log("> Solved\n"); + log_assert(queue.empty()); log_assert(GetSize(pivot_cache) == N); @@ -334,6 +354,9 @@ struct QwpWorker } #endif + if (config.verbose) + log("> Update nodes\n"); + // update node positions for (int i = 0; i < N; i++) { @@ -778,6 +801,9 @@ struct QwpPass : public Pass { log(" -dump <html_file_name>\n"); log(" Dump a protocol of the placement algorithm to the html file.\n"); log("\n"); + log(" -v\n"); + log(" Verbose solver output for profiling or debugging\n"); + log("\n"); log("Note: This implementation of a quadratic wirelength placer uses exact\n"); log("dense matrix operations. It is only a toy-placer for small circuits.\n"); log("\n"); @@ -787,7 +813,7 @@ struct QwpPass : public Pass { QwpConfig config; xorshift32_state = 123456789; - log_header("Executing QWP pass (quadratic wirelength placer).\n"); + log_header(design, "Executing QWP pass (quadratic wirelength placer).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { @@ -799,6 +825,10 @@ struct QwpPass : public Pass { config.alpha = true; continue; } + if (args[argidx] == "-v") { + config.verbose = true; + continue; + } if (args[argidx] == "-grid" && argidx+1 < args.size()) { config.grid = 1.0 / atoi(args[++argidx].c_str()); continue; diff --git a/passes/cmds/scc.cc b/passes/cmds/scc.cc index 532026f2..bb6d7447 100644 --- a/passes/cmds/scc.cc +++ b/passes/cmds/scc.cc @@ -181,10 +181,10 @@ struct SccWorker cell2scc[cell] = sccList.size(); scc.insert(cell); sccList.push_back(scc); - workQueue.erase(cell); log("\n"); - } else - run(cell, 0, maxDepth); + } + + run(cell, 0, maxDepth); } log("Found %d SCCs in module %s.\n", int(sccList.size()), RTLIL::id2cstr(module->name)); @@ -264,7 +264,7 @@ struct SccPass : public Pass { int maxDepth = -1; int expect = -1; - log_header("Executing SCC pass (detecting logic loops).\n"); + log_header(design, "Executing SCC pass (detecting logic loops).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc index 3e64dd84..d2e1a2e2 100644 --- a/passes/cmds/select.cc +++ b/passes/cmds/select.cc @@ -952,7 +952,7 @@ struct SelectPass : public Pass { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); log(" select [ -add | -del | -set <name> ] {-read <filename> | <selection>}\n"); - log(" select [ -assert-none | -assert-any ] {-read <filename> | <selection>}\n"); + log(" select [ <assert_option> ] {-read <filename> | <selection>}\n"); log(" select [ -list | -write <filename> | -count | -clear ]\n"); log(" select -module <modname>\n"); log("\n"); @@ -988,6 +988,14 @@ struct SelectPass : public Pass { log(" do not modify the current selection. instead assert that the given\n"); log(" selection contains exactly N objects.\n"); log("\n"); + log(" -assert-max N\n"); + log(" do not modify the current selection. instead assert that the given\n"); + log(" selection contains less than or exactly N objects.\n"); + log("\n"); + log(" -assert-min N\n"); + log(" do not modify the current selection. instead assert that the given\n"); + log(" selection contains at least N objects.\n"); + log("\n"); log(" -list\n"); log(" list all objects in the current selection\n"); log("\n"); @@ -1168,6 +1176,8 @@ struct SelectPass : public Pass { bool assert_none = false; bool assert_any = false; int assert_count = -1; + int assert_max = -1; + int assert_min = -1; std::string write_file, read_file; std::string set_name, sel_str; @@ -1197,6 +1207,14 @@ struct SelectPass : public Pass { assert_count = atoi(args[++argidx].c_str()); continue; } + if (arg == "-assert-max" && argidx+1 < args.size()) { + assert_max = atoi(args[++argidx].c_str()); + continue; + } + if (arg == "-assert-min" && argidx+1 < args.size()) { + assert_min = atoi(args[++argidx].c_str()); + continue; + } if (arg == "-clear") { clear_mode = true; continue; @@ -1273,14 +1291,14 @@ struct SelectPass : public Pass { if (none_mode && args.size() != 2) log_cmd_error("Option -none can not be combined with any other options.\n"); - if (add_mode + del_mode + assert_none + assert_any + (assert_count >= 0) > 1) - log_cmd_error("Options -add, -del, -assert-none, -assert-any or -assert-count can not be combined.\n"); + if (add_mode + del_mode + assert_none + assert_any + (assert_count >= 0) + (assert_max >= 0) + (assert_min >= 0) > 1) + log_cmd_error("Options -add, -del, -assert-none, -assert-any, assert-count, -assert-max or -assert-min can not be combined.\n"); - if ((list_mode || !write_file.empty() || count_mode) && (add_mode || del_mode || assert_none || assert_any || assert_count >= 0)) - log_cmd_error("Options -list, -write and -count can not be combined with -add, -del, -assert-none, -assert-any or -assert-count.\n"); + if ((list_mode || !write_file.empty() || count_mode) && (add_mode || del_mode || assert_none || assert_any || assert_count >= 0 || assert_max >= 0 || assert_min >= 0)) + log_cmd_error("Options -list, -write and -count can not be combined with -add, -del, -assert-none, -assert-any, assert-count, -assert-max, or -assert-min.\n"); - if (!set_name.empty() && (list_mode || !write_file.empty() || count_mode || add_mode || del_mode || assert_none || assert_any || assert_count >= 0)) - log_cmd_error("Option -set can not be combined with -list, -write, -count, -add, -del, -assert-none, -assert-any or -assert-count.\n"); + if (!set_name.empty() && (list_mode || !write_file.empty() || count_mode || add_mode || del_mode || assert_none || assert_any || assert_count >= 0 || assert_max >= 0 || assert_min >= 0)) + log_cmd_error("Option -set can not be combined with -list, -write, -count, -add, -del, -assert-none, -assert-any, -assert-count, -assert-max, or -assert-min.\n"); if (work_stack.size() == 0 && got_module) { RTLIL::Selection sel; @@ -1385,7 +1403,7 @@ struct SelectPass : public Pass { return; } - if (assert_count >= 0) + if (assert_count >= 0 || assert_max >= 0 || assert_min >= 0) { int total_count = 0; if (work_stack.size() == 0) @@ -1407,9 +1425,15 @@ struct SelectPass : public Pass { if (sel->selected_member(mod_it.first, it.first)) total_count++; } - if (assert_count != total_count) + if (assert_count >= 0 && assert_count != total_count) log_error("Assertion failed: selection contains %d elements instead of the asserted %d:%s\n", total_count, assert_count, sel_str.c_str()); + if (assert_max >= 0 && assert_max < total_count) + log_error("Assertion failed: selection contains %d elements, more than the maximum number %d:%s\n", + total_count, assert_max, sel_str.c_str()); + if (assert_min >= 0 && assert_min > total_count) + log_error("Assertion failed: selection contains %d elements, less than the minimum number %d:%s\n", + total_count, assert_min, sel_str.c_str()); return; } diff --git a/passes/cmds/setattr.cc b/passes/cmds/setattr.cc index 75c738b6..9b05ae32 100644 --- a/passes/cmds/setattr.cc +++ b/passes/cmds/setattr.cc @@ -215,6 +215,12 @@ struct ChparamPass : public Pass { } break; } + + for (int i = argidx; i < GetSize(args); i++) + if (design->module("$abstract\\" + args[i]) != nullptr && + design->module(RTLIL::escape_id(args[i])) == nullptr) + args[i] = "$abstract\\" + args[i]; + extra_args(args, argidx, design); do_setunset(new_parameters, setunset_list); diff --git a/passes/cmds/setundef.cc b/passes/cmds/setundef.cc index 9ca2e874..26b2eb87 100644 --- a/passes/cmds/setundef.cc +++ b/passes/cmds/setundef.cc @@ -79,11 +79,15 @@ struct SetundefPass : public Pass { log(" replace with random bits using the specified integer als seed\n"); log(" value for the random number generator.\n"); log("\n"); + log(" -init\n"); + log(" also create/update init values for flip-flops\n"); + log("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { bool got_value = false; bool undriven_mode = false; + bool init_mode = false; SetundefWorker worker; size_t argidx; @@ -103,6 +107,10 @@ struct SetundefPass : public Pass { worker.next_bit_mode = 1; continue; } + if (args[argidx] == "-init") { + init_mode = true; + continue; + } if (args[argidx] == "-random" && !got_value && argidx+1 < args.size()) { got_value = true; worker.next_bit_mode = 2; @@ -118,12 +126,8 @@ struct SetundefPass : public Pass { if (!got_value) log_cmd_error("One of the options -zero, -one, or -random <seed> must be specified.\n"); - for (auto &mod_it : design->modules_) + for (auto module : design->selected_modules()) { - RTLIL::Module *module = mod_it.second; - if (!design->selected(module)) - continue; - if (undriven_mode) { if (!module->processes.empty()) @@ -151,6 +155,86 @@ struct SetundefPass : public Pass { } } + if (init_mode) + { + SigMap sigmap(module); + pool<SigBit> ffbits; + pool<Wire*> initwires; + + pool<IdString> fftypes; + fftypes.insert("$dff"); + fftypes.insert("$dffe"); + fftypes.insert("$dffsr"); + fftypes.insert("$adff"); + + std::vector<char> list_np = {'N', 'P'}, list_01 = {'0', '1'}; + + for (auto c1 : list_np) + fftypes.insert(stringf("$_DFF_%c_", c1)); + + for (auto c1 : list_np) + for (auto c2 : list_np) + fftypes.insert(stringf("$_DFFE_%c%c_", c1, c2)); + + for (auto c1 : list_np) + for (auto c2 : list_np) + for (auto c3 : list_01) + fftypes.insert(stringf("$_DFF_%c%c%c_", c1, c2, c3)); + + for (auto c1 : list_np) + for (auto c2 : list_np) + for (auto c3 : list_np) + fftypes.insert(stringf("$_DFFSR_%c%c%c_", c1, c2, c3)); + + for (auto cell : module->cells()) + { + if (!fftypes.count(cell->type)) + continue; + + for (auto bit : sigmap(cell->getPort("\\Q"))) + ffbits.insert(bit); + } + + for (auto wire : module->wires()) + { + if (!wire->attributes.count("\\init")) + continue; + + for (auto bit : sigmap(wire)) + ffbits.erase(bit); + + initwires.insert(wire); + } + + for (int wire_types = 0; wire_types < 2; wire_types++) + for (auto wire : module->wires()) + { + if (wire->name[0] == (wire_types ? '\\' : '$')) + next_wire: + continue; + + for (auto bit : sigmap(wire)) + if (!ffbits.count(bit)) + goto next_wire; + + for (auto bit : sigmap(wire)) + ffbits.erase(bit); + + initwires.insert(wire); + } + + for (auto wire : initwires) + { + Const &initval = wire->attributes["\\init"]; + + for (int i = 0; i < GetSize(wire); i++) + if (GetSize(initval) <= i) + initval.bits.push_back(worker.next_bit()); + else if (initval.bits[i] == State::Sx) + initval.bits[i] = worker.next_bit(); + } + } + module->rewrite_sigspecs(worker); } } diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc index 3b03d680..3a3939a8 100644 --- a/passes/cmds/show.cc +++ b/passes/cmds/show.cc @@ -582,8 +582,9 @@ struct ShowPass : public Pass { log(" Run the specified command with the graphics file as parameter.\n"); log("\n"); log(" -format <format>\n"); - log(" Generate a graphics file in the specified format.\n"); - log(" Usually <format> is 'svg' or 'ps'.\n"); + log(" Generate a graphics file in the specified format. Use 'dot' to just\n"); + log(" generate a .dot file, or other <format> strings such as 'svg' or 'ps'\n"); + log(" to generate files in other formats (this calls the 'dot' command).\n"); log("\n"); log(" -lib <verilog_or_ilang_file>\n"); log(" Use the specified library file for determining whether cell ports are\n"); @@ -646,12 +647,13 @@ struct ShowPass : public Pass { log("unless another prefix is specified using -prefix <prefix>.\n"); log("\n"); log("Yosys on Windows and YosysJS use different defaults: The output is written\n"); - log("to 'show.dot' in the current directory and new viewer is launched.\n"); + log("to 'show.dot' in the current directory and new viewer is launched each time\n"); + log("the 'show' command is executed.\n"); log("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Generating Graphviz representation of design.\n"); + log_header(design, "Generating Graphviz representation of design.\n"); log_push(); std::vector<std::pair<std::string, RTLIL::Selection>> color_selections; @@ -759,7 +761,7 @@ struct ShowPass : public Pass { } extra_args(args, argidx, design); - if (format != "ps") { + if (format != "ps" && format != "dot") { int modcount = 0; for (auto &mod_it : design->modules_) { if (mod_it.second->get_bool_attribute("\\blackbox")) @@ -770,7 +772,7 @@ struct ShowPass : public Pass { modcount++; } if (modcount > 1) - log_cmd_error("For formats different than 'ps' only one module must be selected.\n"); + log_cmd_error("For formats different than 'ps' or 'dot' only one module must be selected.\n"); } for (auto filename : libfiles) { @@ -784,7 +786,7 @@ struct ShowPass : public Pass { } if (libs.size() > 0) - log_header("Continuing show pass.\n"); + log_header(design, "Continuing show pass.\n"); std::string dot_file = stringf("%s.dot", prefix.c_str()); std::string out_file = stringf("%s.%s", prefix.c_str(), format.empty() ? "svg" : format.c_str()); @@ -806,7 +808,7 @@ struct ShowPass : public Pass { log_cmd_error("Nothing there to show.\n"); if (format != "dot" && !format.empty()) { - std::string cmd = stringf("dot -T%s -o '%s.new' '%s' && mv '%s.new' '%s'", format.c_str(), out_file.c_str(), dot_file.c_str(), out_file.c_str(), out_file.c_str()); + std::string cmd = stringf("dot -T%s '%s' > '%s.new' && mv '%s.new' '%s'", format.c_str(), dot_file.c_str(), out_file.c_str(), out_file.c_str(), out_file.c_str()); log("Exec: %s\n", cmd.c_str()); if (run_command(cmd) != 0) log_cmd_error("Shell command failed!\n"); diff --git a/passes/cmds/splice.cc b/passes/cmds/splice.cc index 2556fb74..7418ec4d 100644 --- a/passes/cmds/splice.cc +++ b/passes/cmds/splice.cc @@ -341,7 +341,7 @@ struct SplicePass : public Pass { if (!ports.empty() && !no_ports.empty()) log_cmd_error("The options -port and -no_port are exclusive!\n"); - log_header("Executing SPLICE pass (creating cells for signal splicing).\n"); + log_header(design, "Executing SPLICE pass (creating cells for signal splicing).\n"); for (auto &mod_it : design->modules_) { diff --git a/passes/cmds/splitnets.cc b/passes/cmds/splitnets.cc index 0d7892d7..14eeb066 100644 --- a/passes/cmds/splitnets.cc +++ b/passes/cmds/splitnets.cc @@ -109,7 +109,7 @@ struct SplitnetsPass : public Pass { bool flag_driver = false; std::string format = "[]:"; - log_header("Executing SPLITNETS pass (splitting up multi-bit signals).\n"); + log_header(design, "Executing SPLITNETS pass (splitting up multi-bit signals).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 048933fc..362a0edf 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -232,7 +232,7 @@ struct StatPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Printing statistics.\n"); + log_header(design, "Printing statistics.\n"); bool width_mode = false; RTLIL::Module *top_mod = NULL; diff --git a/passes/cmds/tee.cc b/passes/cmds/tee.cc index a0484090..3db2dbf0 100644 --- a/passes/cmds/tee.cc +++ b/passes/cmds/tee.cc @@ -45,10 +45,14 @@ struct TeePass : public Pass { log(" -a logfile\n"); log(" Write output to this file, append if exists.\n"); log("\n"); + log(" +INT, -INT\n"); + log(" Add/subract INT from the -v setting for this command.\n"); + log("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { std::vector<FILE*> backup_log_files, files_to_close; + int backup_log_verbose_level = log_verbose_level; backup_log_files = log_files; size_t argidx; @@ -70,6 +74,10 @@ struct TeePass : public Pass { files_to_close.push_back(f); continue; } + if (GetSize(args[argidx]) >= 2 && (args[argidx][0] == '-' || args[argidx][0] == '+') && args[argidx][1] >= '0' && args[argidx][1] <= '9') { + log_verbose_level += atoi(args[argidx].c_str()); + continue; + } break; } @@ -85,6 +93,8 @@ struct TeePass : public Pass { for (auto cf : files_to_close) fclose(cf); + + log_verbose_level = backup_log_verbose_level; log_files = backup_log_files; } } TeePass; diff --git a/passes/cmds/torder.cc b/passes/cmds/torder.cc index 50317c02..56223610 100644 --- a/passes/cmds/torder.cc +++ b/passes/cmds/torder.cc @@ -48,7 +48,7 @@ struct TorderPass : public Pass { bool noautostop = false; dict<IdString, pool<IdString>> stop_db; - log_header("Executing TORDER pass (print cells in topological order).\n"); + log_header(design, "Executing TORDER pass (print cells in topological order).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { diff --git a/passes/equiv/equiv_induct.cc b/passes/equiv/equiv_induct.cc index cdb951ec..c958c3de 100644 --- a/passes/equiv/equiv_induct.cc +++ b/passes/equiv/equiv_induct.cc @@ -198,7 +198,7 @@ struct EquivInductPass : public Pass { bool model_undef = false; int max_seq = 4; - log_header("Executing EQUIV_INDUCT pass.\n"); + log_header(design, "Executing EQUIV_INDUCT pass.\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { diff --git a/passes/equiv/equiv_make.cc b/passes/equiv/equiv_make.cc index 8b063c54..40ca4262 100644 --- a/passes/equiv/equiv_make.cc +++ b/passes/equiv/equiv_make.cc @@ -464,7 +464,7 @@ struct EquivMakePass : public Pass { worker.read_blacklists(); worker.read_encfiles(); - log_header("Executing EQUIV_MAKE pass (creating equiv checking module).\n"); + log_header(design, "Executing EQUIV_MAKE pass (creating equiv checking module).\n"); worker.equiv_mod = design->addModule(RTLIL::escape_id(args[argidx+2])); worker.run(); diff --git a/passes/equiv/equiv_mark.cc b/passes/equiv/equiv_mark.cc index 3e9819d1..22c50176 100644 --- a/passes/equiv/equiv_mark.cc +++ b/passes/equiv/equiv_mark.cc @@ -218,7 +218,7 @@ struct EquivMarkPass : public Pass { } virtual void execute(std::vector<std::string> args, Design *design) { - log_header("Executing EQUIV_MARK pass.\n"); + log_header(design, "Executing EQUIV_MARK pass.\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { diff --git a/passes/equiv/equiv_miter.cc b/passes/equiv/equiv_miter.cc index 982176c4..eb2e5a17 100644 --- a/passes/equiv/equiv_miter.cc +++ b/passes/equiv/equiv_miter.cc @@ -333,7 +333,7 @@ struct EquivMiterPass : public Pass { found_two_modules: log_cmd_error("Exactly one module must be selected for 'equiv_miter'!\n"); - log_header("Executing EQUIV_MITER pass.\n"); + log_header(design, "Executing EQUIV_MITER pass.\n"); worker.miter_module = design->addModule(worker.miter_name); worker.run(); diff --git a/passes/equiv/equiv_purge.cc b/passes/equiv/equiv_purge.cc index f4141ad4..163b1009 100644 --- a/passes/equiv/equiv_purge.cc +++ b/passes/equiv/equiv_purge.cc @@ -189,7 +189,7 @@ struct EquivPurgePass : public Pass { } virtual void execute(std::vector<std::string> args, Design *design) { - log_header("Executing EQUIV_PURGE pass.\n"); + log_header(design, "Executing EQUIV_PURGE pass.\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { diff --git a/passes/equiv/equiv_remove.cc b/passes/equiv/equiv_remove.cc index b5c383b6..770497a5 100644 --- a/passes/equiv/equiv_remove.cc +++ b/passes/equiv/equiv_remove.cc @@ -46,7 +46,7 @@ struct EquivRemovePass : public Pass { bool mode_gate = false; int remove_count = 0; - log_header("Executing EQUIV_REMOVE pass.\n"); + log_header(design, "Executing EQUIV_REMOVE pass.\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { diff --git a/passes/equiv/equiv_simple.cc b/passes/equiv/equiv_simple.cc index fa22dc62..49963ed6 100644 --- a/passes/equiv/equiv_simple.cc +++ b/passes/equiv/equiv_simple.cc @@ -277,7 +277,7 @@ struct EquivSimplePass : public Pass { int success_counter = 0; int max_seq = 1; - log_header("Executing EQUIV_SIMPLE pass.\n"); + log_header(design, "Executing EQUIV_SIMPLE pass.\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { diff --git a/passes/equiv/equiv_status.cc b/passes/equiv/equiv_status.cc index 8a2f5e05..7b9230b3 100644 --- a/passes/equiv/equiv_status.cc +++ b/passes/equiv/equiv_status.cc @@ -41,7 +41,7 @@ struct EquivStatusPass : public Pass { bool assert_mode = false; int unproven_count = 0; - log_header("Executing EQUIV_STATUS pass.\n"); + log_header(design, "Executing EQUIV_STATUS pass.\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { diff --git a/passes/equiv/equiv_struct.cc b/passes/equiv/equiv_struct.cc index 2c85d2d3..c4ced6a7 100644 --- a/passes/equiv/equiv_struct.cc +++ b/passes/equiv/equiv_struct.cc @@ -321,7 +321,7 @@ struct EquivStructPass : public Pass { bool mode_fwd = false; int max_iter = -1; - log_header("Executing EQUIV_STRUCT pass.\n"); + log_header(design, "Executing EQUIV_STRUCT pass.\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { diff --git a/passes/fsm/fsm.cc b/passes/fsm/fsm.cc index 3f5564fc..3b537ecd 100644 --- a/passes/fsm/fsm.cc +++ b/passes/fsm/fsm.cc @@ -76,7 +76,7 @@ struct FsmPass : public Pass { std::string encfile_opt; std::string encoding_opt; - log_header("Executing FSM pass (extract and optimize FSM).\n"); + log_header(design, "Executing FSM pass (extract and optimize FSM).\n"); log_push(); size_t argidx; diff --git a/passes/fsm/fsm_detect.cc b/passes/fsm/fsm_detect.cc index 740113e3..6a560f16 100644 --- a/passes/fsm/fsm_detect.cc +++ b/passes/fsm/fsm_detect.cc @@ -36,18 +36,21 @@ static SigPool sig_at_port; static bool check_state_mux_tree(RTLIL::SigSpec old_sig, RTLIL::SigSpec sig, pool<Cell*> &recursion_monitor) { - if (sig_at_port.check_any(assign_map(sig))) - return false; - - if (sig.is_fully_const() || old_sig == sig) + if (sig.is_fully_const() || old_sig == sig) { return true; + } + + if (sig_at_port.check_any(assign_map(sig))) { + return false; + } std::set<sig2driver_entry_t> cellport_list; sig2driver.find(sig, cellport_list); for (auto &cellport : cellport_list) { - if ((cellport.first->type != "$mux" && cellport.first->type != "$pmux") || cellport.second != "\\Y") + if ((cellport.first->type != "$mux" && cellport.first->type != "$pmux") || cellport.second != "\\Y") { return false; + } if (recursion_monitor.count(cellport.first)) { log_warning("logic loop in mux tree at signal %s in module %s.\n", @@ -110,28 +113,134 @@ static bool check_state_users(RTLIL::SigSpec sig) static void detect_fsm(RTLIL::Wire *wire) { - if (wire->attributes.count("\\init") > 0) - return; - if (wire->attributes.count("\\fsm_encoding") > 0 || wire->width <= 1) + bool has_fsm_encoding_attr = wire->attributes.count("\\fsm_encoding") > 0 && wire->attributes.at("\\fsm_encoding").decode_string() != "none"; + bool has_fsm_encoding_none = wire->attributes.count("\\fsm_encoding") > 0 && wire->attributes.at("\\fsm_encoding").decode_string() == "none"; + bool has_init_attr = wire->attributes.count("\\init") > 0; + bool is_module_port = sig_at_port.check_any(assign_map(RTLIL::SigSpec(wire))); + bool looks_like_state_reg = false, looks_like_good_state_reg = false; + bool is_self_resetting = false; + + if (has_fsm_encoding_none) return; - if (sig_at_port.check_any(assign_map(RTLIL::SigSpec(wire)))) + + if (wire->width <= 1) { + if (has_fsm_encoding_attr) { + log_warning("Removing fsm_encoding attribute from 1-bit net: %s.%s\n", log_id(wire->module), log_id(wire)); + wire->attributes.erase("\\fsm_encoding"); + } return; + } std::set<sig2driver_entry_t> cellport_list; sig2driver.find(RTLIL::SigSpec(wire), cellport_list); - for (auto &cellport : cellport_list) { + + for (auto &cellport : cellport_list) + { if ((cellport.first->type != "$dff" && cellport.first->type != "$adff") || cellport.second != "\\Q") continue; + muxtree_cells.clear(); pool<Cell*> recursion_monitor; RTLIL::SigSpec sig_q = assign_map(cellport.first->getPort("\\Q")); RTLIL::SigSpec sig_d = assign_map(cellport.first->getPort("\\D")); - if (sig_q == RTLIL::SigSpec(wire) && check_state_mux_tree(sig_q, sig_d, recursion_monitor) && check_state_users(sig_q)) { - log("Found FSM state register %s in module %s.\n", wire->name.c_str(), module->name.c_str()); - wire->attributes["\\fsm_encoding"] = RTLIL::Const("auto"); - return; + + if (sig_q != assign_map(wire)) + continue; + + looks_like_state_reg = check_state_mux_tree(sig_q, sig_d, recursion_monitor); + looks_like_good_state_reg = check_state_users(sig_q); + + if (!looks_like_state_reg) + break; + + ConstEval ce(wire->module); + + std::set<sig2driver_entry_t> cellport_list; + sig2user.find(sig_q, cellport_list); + + for (auto &cellport : cellport_list) + { + RTLIL::Cell *cell = cellport.first; + bool set_output = false, clr_output = false; + + if (cell->type == "$ne") + set_output = true; + + if (cell->type == "$eq") + clr_output = true; + + if (!set_output && !clr_output) { + clr_output = true; + for (auto &port_it : cell->connections()) + if (port_it.first != "\\A" || port_it.first != "\\Y") + clr_output = false; + } + + if (set_output || clr_output) { + for (auto &port_it : cell->connections()) + if (cell->output(port_it.first)) { + SigSpec sig = assign_map(port_it.second); + Const val(set_output ? State::S1 : State::S0, GetSize(sig)); + ce.set(sig, val); + } + } + } + + SigSpec sig_y = sig_d, sig_undef; + if (ce.eval(sig_y, sig_undef)) + is_self_resetting = true; + } + + if (has_fsm_encoding_attr) + { + vector<string> warnings; + + if (is_module_port) + warnings.push_back("Forcing fsm recoding on module port might result in larger circuit.\n"); + + if (!looks_like_good_state_reg) + warnings.push_back("Users of state reg look like fsm recoding might result in larger circuit.\n"); + + if (has_init_attr) + warnings.push_back("Init value on fsm state registers are ignored. Possible simulation-synthesis mismatch!"); + + if (!looks_like_state_reg) + warnings.push_back("Doesn't look like a proper FSM. Possible simulation-synthesis mismatch!\n"); + + if (is_self_resetting) + warnings.push_back("FSM seems to be self-resetting. Possible simulation-synthesis mismatch!\n"); + + if (!warnings.empty()) { + string warnmsg = stringf("Regarding the user-specified fsm_encoding attribute on %s.%s:\n", log_id(wire->module), log_id(wire)); + for (auto w : warnings) warnmsg += " " + w; + log_warning("%s", warnmsg.c_str()); + } else { + log("FSM state register %s.%s already has fsm_encoding attribute.\n", log_id(wire->module), log_id(wire)); } } + else + if (looks_like_state_reg && looks_like_good_state_reg && !has_init_attr && !is_module_port && !is_self_resetting) + { + log("Found FSM state register %s.%s.\n", log_id(wire->module), log_id(wire)); + wire->attributes["\\fsm_encoding"] = RTLIL::Const("auto"); + } + else + if (looks_like_state_reg) + { + log("Not marking %s.%s as FSM state register:\n", log_id(wire->module), log_id(wire)); + + if (is_module_port) + log(" Register is connected to module port.\n"); + + if (!looks_like_good_state_reg) + log(" Users of register don't seem to benefit from recoding.\n"); + + if (has_init_attr) + log(" Register has an initialization value."); + + if (is_self_resetting) + log(" Circuit seems to be self-resetting.\n"); + } } struct FsmDetectPass : public Pass { @@ -154,7 +263,7 @@ struct FsmDetectPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing FSM_DETECT pass (finding FSMs in design).\n"); + log_header(design, "Executing FSM_DETECT pass (finding FSMs in design).\n"); extra_args(args, 1, design); CellTypes ct; diff --git a/passes/fsm/fsm_expand.cc b/passes/fsm/fsm_expand.cc index 43c9a792..3ded3f37 100644 --- a/passes/fsm/fsm_expand.cc +++ b/passes/fsm/fsm_expand.cc @@ -258,7 +258,7 @@ struct FsmExpandPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing FSM_EXPAND pass (merging auxiliary logic into FSMs).\n"); + log_header(design, "Executing FSM_EXPAND pass (merging auxiliary logic into FSMs).\n"); extra_args(args, 1, design); for (auto &mod_it : design->modules_) { diff --git a/passes/fsm/fsm_export.cc b/passes/fsm/fsm_export.cc index 0eff2884..1cbfcfae 100644 --- a/passes/fsm/fsm_export.cc +++ b/passes/fsm/fsm_export.cc @@ -152,7 +152,7 @@ struct FsmExportPass : public Pass { bool flag_origenc = false; size_t argidx; - log_header("Executing FSM_EXPORT pass (exporting FSMs in KISS2 file format).\n"); + log_header(design, "Executing FSM_EXPORT pass (exporting FSMs in KISS2 file format).\n"); for (argidx = 1; argidx < args.size(); argidx++) { arg = args[argidx]; diff --git a/passes/fsm/fsm_extract.cc b/passes/fsm/fsm_extract.cc index d61ac568..8a4ee3f2 100644 --- a/passes/fsm/fsm_extract.cc +++ b/passes/fsm/fsm_extract.cc @@ -92,12 +92,15 @@ static bool find_states(RTLIL::SigSpec sig, const RTLIL::SigSpec &dff_out, RTLIL if (reset_state && RTLIL::SigSpec(*reset_state).is_fully_undef()) do { + SigSpec new_reset_state; if (sig_aa.is_fully_def()) - *reset_state = sig_aa.as_const(); + new_reset_state = sig_aa.as_const(); else if (sig_bb.is_fully_def()) - *reset_state = sig_bb.as_const(); + new_reset_state = sig_bb.as_const(); else break; + new_reset_state.extend_u0(GetSize(*reset_state)); + *reset_state = new_reset_state.as_const(); log(" found reset state: %s (guessed from mux tree)\n", log_signal(*reset_state)); } while (0); @@ -416,7 +419,7 @@ struct FsmExtractPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing FSM_EXTRACT pass (extracting FSM from design).\n"); + log_header(design, "Executing FSM_EXTRACT pass (extracting FSM from design).\n"); extra_args(args, 1, design); CellTypes ct; diff --git a/passes/fsm/fsm_info.cc b/passes/fsm/fsm_info.cc index 20db82c1..2cc1a7d5 100644 --- a/passes/fsm/fsm_info.cc +++ b/passes/fsm/fsm_info.cc @@ -43,7 +43,7 @@ struct FsmInfoPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing FSM_INFO pass (dumping all available information on FSM cells).\n"); + log_header(design, "Executing FSM_INFO pass (dumping all available information on FSM cells).\n"); extra_args(args, 1, design); for (auto &mod_it : design->modules_) diff --git a/passes/fsm/fsm_map.cc b/passes/fsm/fsm_map.cc index 574b9a20..5b32ed59 100644 --- a/passes/fsm/fsm_map.cc +++ b/passes/fsm/fsm_map.cc @@ -335,7 +335,7 @@ struct FsmMapPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing FSM_MAP pass (mapping FSMs to basic logic).\n"); + log_header(design, "Executing FSM_MAP pass (mapping FSMs to basic logic).\n"); extra_args(args, 1, design); for (auto &mod_it : design->modules_) { diff --git a/passes/fsm/fsm_opt.cc b/passes/fsm/fsm_opt.cc index a7cc95ff..5b1da44f 100644 --- a/passes/fsm/fsm_opt.cc +++ b/passes/fsm/fsm_opt.cc @@ -336,7 +336,7 @@ struct FsmOptPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing FSM_OPT pass (simple optimizations of FSMs).\n"); + log_header(design, "Executing FSM_OPT pass (simple optimizations of FSMs).\n"); extra_args(args, 1, design); for (auto &mod_it : design->modules_) { diff --git a/passes/fsm/fsm_recode.cc b/passes/fsm/fsm_recode.cc index a4b45295..5102d833 100644 --- a/passes/fsm/fsm_recode.cc +++ b/passes/fsm/fsm_recode.cc @@ -157,7 +157,7 @@ struct FsmRecodePass : public Pass { FILE *encfile = NULL; std::string default_encoding; - log_header("Executing FSM_RECODE pass (re-assigning FSM state encoding).\n"); + log_header(design, "Executing FSM_RECODE pass (re-assigning FSM state encoding).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index fcc30d17..4d1e3987 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -261,7 +261,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check return did_something; } -void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*> &used, RTLIL::Module *mod, int indent) +void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*, IdString::compare_ptr_by_name<Module>> &used, RTLIL::Module *mod, int indent) { if (used.count(mod) > 0) return; @@ -287,7 +287,7 @@ void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*> &used, RTL void hierarchy_clean(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib) { - std::set<RTLIL::Module*> used; + std::set<RTLIL::Module*, IdString::compare_ptr_by_name<Module>> used; hierarchy_worker(design, used, top, 0); std::vector<RTLIL::Module*> del_modules; @@ -297,8 +297,6 @@ void hierarchy_clean(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib) int del_counter = 0; for (auto mod : del_modules) { - if (mod->name.substr(0, 9) == "$abstract") - continue; if (!purge_lib && mod->get_bool_attribute("\\blackbox")) continue; log("Removing unused module `%s'.\n", mod->name.c_str()); @@ -324,10 +322,12 @@ bool set_keep_assert(std::map<RTLIL::Module*, bool> &cache, RTLIL::Module *mod) int find_top_mod_score(Design *design, Module *module, dict<Module*, int> &db) { if (db.count(module) == 0) { + int score = 0; db[module] = 0; for (auto cell : module->cells()) if (design->module(cell->type)) - db[module] = max(db[module], find_top_mod_score(design, design->module(cell->type), db) + 1); + score = max(score, find_top_mod_score(design, design->module(cell->type), db) + 1); + db[module] = score; } return db.at(module); } @@ -398,7 +398,7 @@ struct HierarchyPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing HIERARCHY pass (managing design hierarchy).\n"); + log_header(design, "Executing HIERARCHY pass (managing design hierarchy).\n"); bool flag_check = false; bool purge_lib = false; @@ -508,7 +508,7 @@ struct HierarchyPass : public Pass { top_mod = mod_it.second; if (top_mod == nullptr && auto_top_mode) { - log_header("Finding top of design hierarchy..\n"); + log_header(design, "Finding top of design hierarchy..\n"); dict<Module*, int> db; for (Module *mod : design->selected_modules()) { int score = find_top_mod_score(design, mod, db); @@ -525,9 +525,9 @@ struct HierarchyPass : public Pass { { did_something = false; - std::set<RTLIL::Module*> used_modules; + std::set<RTLIL::Module*, IdString::compare_ptr_by_name<Module>> used_modules; if (top_mod != NULL) { - log_header("Analyzing design hierarchy..\n"); + log_header(design, "Analyzing design hierarchy..\n"); hierarchy_worker(design, used_modules, top_mod, 0); } else { for (auto mod : design->modules()) @@ -541,7 +541,7 @@ struct HierarchyPass : public Pass { } if (top_mod != NULL) { - log_header("Analyzing design hierarchy..\n"); + log_header(design, "Analyzing design hierarchy..\n"); hierarchy_clean(design, top_mod, purge_lib); } diff --git a/passes/hierarchy/singleton.cc b/passes/hierarchy/singleton.cc index 5715c0eb..03c365fb 100644 --- a/passes/hierarchy/singleton.cc +++ b/passes/hierarchy/singleton.cc @@ -43,7 +43,7 @@ struct SingletonPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing SINGLETON pass (creating singleton modules).\n"); + log_header(design, "Executing SINGLETON pass (creating singleton modules).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) diff --git a/passes/hierarchy/submod.cc b/passes/hierarchy/submod.cc index d4e8c96c..9f312f82 100644 --- a/passes/hierarchy/submod.cc +++ b/passes/hierarchy/submod.cc @@ -298,7 +298,7 @@ struct SubmodPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing SUBMOD pass (moving cells to submodules as requested).\n"); + log_header(design, "Executing SUBMOD pass (moving cells to submodules as requested).\n"); log_push(); std::string opt_name; @@ -321,7 +321,7 @@ struct SubmodPass : public Pass { if (opt_name.empty()) { Pass::call(design, "opt_clean"); - log_header("Continuing SUBMOD pass.\n"); + log_header(design, "Continuing SUBMOD pass.\n"); std::set<RTLIL::IdString> handled_modules; @@ -356,7 +356,7 @@ struct SubmodPass : public Pass { log("Nothing selected -> do nothing.\n"); else { Pass::call_on_module(design, module, "opt_clean"); - log_header("Continuing SUBMOD pass.\n"); + log_header(design, "Continuing SUBMOD pass.\n"); SubmodWorker worker(design, module, copy_mode, opt_name); } } diff --git a/passes/memory/Makefile.inc b/passes/memory/Makefile.inc index aeff225d..ad359c01 100644 --- a/passes/memory/Makefile.inc +++ b/passes/memory/Makefile.inc @@ -6,4 +6,5 @@ OBJS += passes/memory/memory_collect.o OBJS += passes/memory/memory_unpack.o OBJS += passes/memory/memory_bram.o OBJS += passes/memory/memory_map.o +OBJS += passes/memory/memory_memx.o diff --git a/passes/memory/memory.cc b/passes/memory/memory.cc index 4e74d1a4..947d598b 100644 --- a/passes/memory/memory.cc +++ b/passes/memory/memory.cc @@ -31,14 +31,15 @@ struct MemoryPass : public Pass { { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" memory [-nomap] [-nordff] [-bram <bram_rules>] [selection]\n"); + log(" memory [-nomap] [-nordff] [-memx] [-bram <bram_rules>] [selection]\n"); log("\n"); log("This pass calls all the other memory_* passes in a useful order:\n"); log("\n"); - log(" memory_dff [-nordff]\n"); + log(" memory_dff [-nordff] (-memx implies -nordff)\n"); log(" opt_clean\n"); log(" memory_share\n"); log(" opt_clean\n"); + log(" memory_memx (when called with -memx)\n"); log(" memory_collect\n"); log(" memory_bram -rules <bram_rules> (when called with -bram)\n"); log(" memory_map (skipped if called with -nomap)\n"); @@ -51,9 +52,10 @@ struct MemoryPass : public Pass { { bool flag_nomap = false; bool flag_nordff = false; + bool flag_memx = false; string memory_bram_opts; - log_header("Executing MEMORY pass.\n"); + log_header(design, "Executing MEMORY pass.\n"); log_push(); size_t argidx; @@ -66,6 +68,11 @@ struct MemoryPass : public Pass { flag_nordff = true; continue; } + if (args[argidx] == "-memx") { + flag_nordff = true; + flag_memx = true; + continue; + } if (argidx+1 < args.size() && args[argidx] == "-bram") { memory_bram_opts += " -rules " + args[++argidx]; continue; @@ -77,6 +84,8 @@ struct MemoryPass : public Pass { Pass::call(design, flag_nordff ? "memory_dff -nordff" : "memory_dff"); Pass::call(design, "opt_clean"); Pass::call(design, "memory_share"); + if (flag_memx) + Pass::call(design, "memory_memx"); Pass::call(design, "opt_clean"); Pass::call(design, "memory_collect"); diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc index f2d9b584..a7f9cf38 100644 --- a/passes/memory/memory_bram.cc +++ b/passes/memory/memory_bram.cc @@ -656,6 +656,9 @@ grow_read_ports:; bool transp = rd_transp[cell_port_i] == State::S1; SigBit clksig = rd_clk[cell_port_i]; + if (wr_ports == 0) + transp = false; + pair<SigBit, bool> clkdom(clksig, clkpol); if (!clken) clkdom = pair<SigBit, bool>(State::S1, false); @@ -826,7 +829,7 @@ grow_read_ports:; State padding = State::Sx; for (int j = 0; j < bram.dbits; j++) if (init_offset+i < GetSize(initdata) && init_shift+j < GetSize(initdata[init_offset+i])) - padding = initparam[i*bram.dbits+j] = initdata[init_offset+i][init_shift+j]; + initparam[i*bram.dbits+j] = initdata[init_offset+i][init_shift+j]; else initparam[i*bram.dbits+j] = padding; } @@ -1211,7 +1214,7 @@ struct MemoryBramPass : public Pass { { rules_t rules; - log_header("Executing MEMORY_BRAM pass (mapping $mem cells to block memories).\n"); + log_header(design, "Executing MEMORY_BRAM pass (mapping $mem cells to block memories).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc index 5c0acb3e..ab66e3fb 100644 --- a/passes/memory/memory_collect.cc +++ b/passes/memory/memory_collect.cc @@ -37,8 +37,6 @@ Cell *handle_memory(Module *module, RTLIL::Memory *memory) log("Collecting $memrd, $memwr and $meminit for memory `%s' in module `%s':\n", memory->name.c_str(), module->name.c_str()); - int addr_bits = 0; - Const init_data(State::Sx, memory->size * memory->width); SigMap sigmap(module); @@ -59,16 +57,28 @@ Cell *handle_memory(Module *module, RTLIL::Memory *memory) SigSpec sig_rd_data; SigSpec sig_rd_en; + int addr_bits = 0; std::vector<Cell*> memcells; for (auto &cell_it : module->cells_) { Cell *cell = cell_it.second; if (cell->type.in("$memrd", "$memwr", "$meminit") && memory->name == cell->parameters["\\MEMID"].decode_string()) { - addr_bits = max(addr_bits, cell->getParam("\\ABITS").as_int()); + SigSpec addr = sigmap(cell->getPort("\\ADDR")); + for (int i = 0; i < GetSize(addr); i++) + if (addr[i] != State::S0) + addr_bits = std::max(addr_bits, i+1); memcells.push_back(cell); } } + if (memory->start_offset == 0 && addr_bits < 30 && (1 << addr_bits) < memory->size) + memory->size = 1 << addr_bits; + + if (memory->start_offset >= 0) + addr_bits = std::min(addr_bits, ceil_log2(memory->size + memory->start_offset)); + + addr_bits = std::max(addr_bits, 1); + if (memcells.empty()) { log(" no cells found. removing memory.\n"); return nullptr; @@ -247,7 +257,7 @@ struct MemoryCollectPass : public Pass { log("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing MEMORY_COLLECT pass (generating $mem cells).\n"); + log_header(design, "Executing MEMORY_COLLECT pass (generating $mem cells).\n"); extra_args(args, 1, design); for (auto &mod_it : design->modules_) if (design->selected(mod_it.second)) diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc index beb2016a..40691d16 100644 --- a/passes/memory/memory_dff.cc +++ b/passes/memory/memory_dff.cc @@ -283,7 +283,7 @@ struct MemoryDffPass : public Pass { { bool flag_wr_only = false; - log_header("Executing MEMORY_DFF pass (merging $dff cells to $memrd and $memwr).\n"); + log_header(design, "Executing MEMORY_DFF pass (merging $dff cells to $memrd and $memwr).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc index 0b8ccb36..bffeec85 100644 --- a/passes/memory/memory_map.cc +++ b/passes/memory/memory_map.cc @@ -363,7 +363,7 @@ struct MemoryMapPass : public Pass { log("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing MEMORY_MAP pass (converting $mem cells to logic and flip-flops).\n"); + log_header(design, "Executing MEMORY_MAP pass (converting $mem cells to logic and flip-flops).\n"); extra_args(args, 1, design); for (auto mod : design->selected_modules()) MemoryMapWorker(design, mod); diff --git a/passes/memory/memory_memx.cc b/passes/memory/memory_memx.cc new file mode 100644 index 00000000..2b02e249 --- /dev/null +++ b/passes/memory/memory_memx.cc @@ -0,0 +1,92 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/register.h" +#include "kernel/log.h" +#include <sstream> +#include <set> +#include <stdlib.h> + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct MemoryMemxPass : public Pass { + MemoryMemxPass() : Pass("memory_memx", "emulate vlog sim behavior for mem ports") { } + virtual void help() + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" memory_memx [selection]\n"); + log("\n"); + log("This pass adds additional circuitry that emulates the Verilog simulation\n"); + log("behavior for out-of-bounds memory reads and writes.\n"); + log("\n"); + } + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { + log_header(design, "Executing MEMORY_MEMX pass (converting $mem cells to logic and flip-flops).\n"); + extra_args(args, 1, design); + + for (auto module : design->selected_modules()) + { + vector<Cell*> mem_port_cells; + + for (auto cell : module->selected_cells()) + if (cell->type.in("$memrd", "$memwr")) + mem_port_cells.push_back(cell); + + for (auto cell : mem_port_cells) + { + IdString memid = cell->getParam("\\MEMID").decode_string(); + RTLIL::Memory *mem = module->memories.at(memid); + + int lowest_addr = mem->start_offset; + int highest_addr = mem->start_offset + mem->size - 1; + + SigSpec addr = cell->getPort("\\ADDR"); + addr.extend_u0(32); + + SigSpec addr_ok = module->Nex(NEW_ID, module->ReduceXor(NEW_ID, addr), module->ReduceXor(NEW_ID, {addr, State::S1})); + if (lowest_addr != 0) + addr_ok = module->LogicAnd(NEW_ID, addr_ok, module->Ge(NEW_ID, addr, lowest_addr)); + addr_ok = module->LogicAnd(NEW_ID, addr_ok, module->Le(NEW_ID, addr, highest_addr)); + + if (cell->type == "$memrd") + { + if (cell->getParam("\\CLK_ENABLE").as_bool()) + log_error("Cell %s.%s (%s) has an enabled clock. Clocked $memrd cells are not supported by memory_memx!\n", + log_id(module), log_id(cell), log_id(cell->type)); + + SigSpec rdata = cell->getPort("\\DATA"); + Wire *raw_rdata = module->addWire(NEW_ID, GetSize(rdata)); + module->addMux(NEW_ID, SigSpec(State::Sx, GetSize(rdata)), raw_rdata, addr_ok, rdata); + cell->setPort("\\DATA", raw_rdata); + } + + if (cell->type == "$memwr") + { + SigSpec en = cell->getPort("\\EN"); + en = module->And(NEW_ID, en, addr_ok.repeat(GetSize(en))); + cell->setPort("\\EN", en); + } + } + } + } +} MemoryMemxPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/memory/memory_share.cc b/passes/memory/memory_share.cc index 3a6fd0b4..ca09ac52 100644 --- a/passes/memory/memory_share.cc +++ b/passes/memory/memory_share.cc @@ -43,7 +43,7 @@ struct MemoryShareWorker CellTypes cone_ct; std::map<RTLIL::SigBit, std::pair<RTLIL::Cell*, int>> sig_to_mux; - std::map<std::set<std::map<RTLIL::SigBit, bool>>, RTLIL::SigBit> conditions_logic_cache; + std::map<pair<std::set<std::map<SigBit, bool>>, SigBit>, SigBit> conditions_logic_cache; // ----------------------------------------------------------------- @@ -109,10 +109,12 @@ struct MemoryShareWorker return false; } - RTLIL::SigBit conditions_to_logic(std::set<std::map<RTLIL::SigBit, bool>> &conditions, int &created_conditions) + RTLIL::SigBit conditions_to_logic(std::set<std::map<RTLIL::SigBit, bool>> &conditions, SigBit olden, int &created_conditions) { - if (conditions_logic_cache.count(conditions)) - return conditions_logic_cache.at(conditions); + auto key = make_pair(conditions, olden); + + if (conditions_logic_cache.count(key)) + return conditions_logic_cache.at(key); RTLIL::SigSpec terms; for (auto &cond : conditions) { @@ -125,13 +127,16 @@ struct MemoryShareWorker created_conditions++; } - if (terms.size() == 0) + if (olden.wire != nullptr || olden != State::S1) + terms.append(olden); + + if (GetSize(terms) == 0) terms = State::S1; - if (terms.size() > 1) + if (GetSize(terms) > 1) terms = module->ReduceAnd(NEW_ID, terms); - return conditions_logic_cache[conditions] = terms; + return conditions_logic_cache[key] = terms; } void translate_rd_feedback_to_en(std::string memid, std::vector<RTLIL::Cell*> &rd_ports, std::vector<RTLIL::Cell*> &wr_ports) @@ -140,15 +145,14 @@ struct MemoryShareWorker std::map<RTLIL::SigBit, std::set<RTLIL::SigBit>> muxtree_upstream_map; std::set<RTLIL::SigBit> non_feedback_nets; - for (auto wire_it : module->wires_) - if (wire_it.second->port_output) { - std::vector<RTLIL::SigBit> bits = RTLIL::SigSpec(wire_it.second); + for (auto wire : module->wires()) + if (wire->port_output) { + std::vector<RTLIL::SigBit> bits = sigmap(wire); non_feedback_nets.insert(bits.begin(), bits.end()); } - for (auto cell_it : module->cells_) + for (auto cell : module->cells()) { - RTLIL::Cell *cell = cell_it.second; bool ignore_data_port = false; if (cell->type == "$mux" || cell->type == "$pmux") @@ -173,7 +177,7 @@ struct MemoryShareWorker cell->parameters.at("\\MEMID").decode_string() == memid) ignore_data_port = true; - for (auto conn : cell_it.second->connections()) + for (auto conn : cell->connections()) { if (ignore_data_port && conn.first == "\\DATA") continue; @@ -240,13 +244,8 @@ struct MemoryShareWorker std::map<RTLIL::SigBit, bool> state; std::set<std::map<RTLIL::SigBit, bool>> conditions; - if (cell_en[i].wire != NULL) { - state[cell_en[i]] = false; - conditions.insert(state); - } - find_data_feedback(async_rd_bits.at(sig_addr).at(i), cell_data[i], state, conditions); - cell_en[i] = conditions_to_logic(conditions, created_conditions); + cell_en[i] = conditions_to_logic(conditions, cell_en[i], created_conditions); } if (created_conditions) { @@ -620,6 +619,12 @@ struct MemoryShareWorker RTLIL::SigBit this_en_active = module->ReduceOr(NEW_ID, this_en); + if (GetSize(last_addr) < GetSize(this_addr)) + last_addr.extend_u0(GetSize(this_addr)); + else + this_addr.extend_u0(GetSize(last_addr)); + + wr_ports[i]->setParam("\\ABITS", GetSize(this_addr)); wr_ports[i]->setPort("\\ADDR", module->Mux(NEW_ID, last_addr, this_addr, this_en_active)); wr_ports[i]->setPort("\\DATA", module->Mux(NEW_ID, last_data, this_data, this_en_active)); @@ -666,10 +671,8 @@ struct MemoryShareWorker std::map<std::string, std::pair<std::vector<RTLIL::Cell*>, std::vector<RTLIL::Cell*>>> memindex; sigmap_xmux = sigmap; - for (auto &it : module->cells_) + for (auto cell : module->cells()) { - RTLIL::Cell *cell = it.second; - if (cell->type == "$memrd") memindex[cell->parameters.at("\\MEMID").decode_string()].first.push_back(cell); @@ -746,11 +749,11 @@ struct MemorySharePass : public Pass { log("\n"); log("Note that in addition to the algorithms implemented in this pass, the $memrd\n"); log("and $memwr cells are also subject to generic resource sharing passes (and other\n"); - log("optimizations) such as opt_share.\n"); + log("optimizations) such as \"share\" and \"opt_merge\".\n"); log("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing MEMORY_SHARE pass (consolidating $memrc/$memwr cells).\n"); + log_header(design, "Executing MEMORY_SHARE pass (consolidating $memrd/$memwr cells).\n"); extra_args(args, 1, design); for (auto module : design->selected_modules()) MemoryShareWorker(design, module); diff --git a/passes/memory/memory_unpack.cc b/passes/memory/memory_unpack.cc index 60724da7..a0fc31b5 100644 --- a/passes/memory/memory_unpack.cc +++ b/passes/memory/memory_unpack.cc @@ -138,7 +138,7 @@ struct MemoryUnpackPass : public Pass { log("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing MEMORY_UNPACK pass (generating $memrd/$memwr cells form $mem cells).\n"); + log_header(design, "Executing MEMORY_UNPACK pass (generating $memrd/$memwr cells form $mem cells).\n"); extra_args(args, 1, design); for (auto &mod_it : design->modules_) if (design->selected(mod_it.second)) diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc index 43defb78..a8b1537b 100644 --- a/passes/opt/Makefile.inc +++ b/passes/opt/Makefile.inc @@ -1,11 +1,11 @@ OBJS += passes/opt/opt.o -OBJS += passes/opt/opt_share.o +OBJS += passes/opt/opt_merge.o OBJS += passes/opt/opt_muxtree.o OBJS += passes/opt/opt_reduce.o OBJS += passes/opt/opt_rmdff.o OBJS += passes/opt/opt_clean.o -OBJS += passes/opt/opt_const.o +OBJS += passes/opt/opt_expr.o ifneq ($(SMALL),1) OBJS += passes/opt/share.o diff --git a/passes/opt/opt.cc b/passes/opt/opt.cc index f5389d8e..13ea5469 100644 --- a/passes/opt/opt.cc +++ b/passes/opt/opt.cc @@ -37,23 +37,23 @@ struct OptPass : public Pass { log("a series of trivial optimizations and cleanups. This pass executes the other\n"); log("passes in the following order:\n"); log("\n"); - log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n"); - log(" opt_share [-share_all] -nomux\n"); + log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n"); + log(" opt_merge [-share_all] -nomux\n"); log("\n"); log(" do\n"); log(" opt_muxtree\n"); log(" opt_reduce [-fine] [-full]\n"); - log(" opt_share [-share_all]\n"); + log(" opt_merge [-share_all]\n"); log(" opt_rmdff\n"); log(" opt_clean [-purge]\n"); - log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n"); + log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n"); log(" while <changed design>\n"); log("\n"); log("When called with -fast the following script is used instead:\n"); log("\n"); log(" do\n"); - log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n"); - log(" opt_share [-share_all]\n"); + log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n"); + log(" opt_merge [-share_all]\n"); log(" opt_rmdff\n"); log(" opt_clean [-purge]\n"); log(" while <changed design in opt_rmdff>\n"); @@ -66,12 +66,12 @@ struct OptPass : public Pass { virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { std::string opt_clean_args; - std::string opt_const_args; + std::string opt_expr_args; std::string opt_reduce_args; - std::string opt_share_args; + std::string opt_merge_args; bool fast_mode = false; - log_header("Executing OPT pass (performing simple optimizations).\n"); + log_header(design, "Executing OPT pass (performing simple optimizations).\n"); log_push(); size_t argidx; @@ -81,37 +81,37 @@ struct OptPass : public Pass { continue; } if (args[argidx] == "-mux_undef") { - opt_const_args += " -mux_undef"; + opt_expr_args += " -mux_undef"; continue; } if (args[argidx] == "-mux_bool") { - opt_const_args += " -mux_bool"; + opt_expr_args += " -mux_bool"; continue; } if (args[argidx] == "-undriven") { - opt_const_args += " -undriven"; + opt_expr_args += " -undriven"; continue; } if (args[argidx] == "-clkinv") { - opt_const_args += " -clkinv"; + opt_expr_args += " -clkinv"; continue; } if (args[argidx] == "-fine") { - opt_const_args += " -fine"; + opt_expr_args += " -fine"; opt_reduce_args += " -fine"; continue; } if (args[argidx] == "-full") { - opt_const_args += " -full"; + opt_expr_args += " -full"; opt_reduce_args += " -full"; continue; } if (args[argidx] == "-keepdc") { - opt_const_args += " -keepdc"; + opt_expr_args += " -keepdc"; continue; } if (args[argidx] == "-share_all") { - opt_share_args += " -share_all"; + opt_merge_args += " -share_all"; continue; } if (args[argidx] == "-fast") { @@ -125,32 +125,32 @@ struct OptPass : public Pass { if (fast_mode) { while (1) { - Pass::call(design, "opt_const" + opt_const_args); - Pass::call(design, "opt_share" + opt_share_args); + Pass::call(design, "opt_expr" + opt_expr_args); + Pass::call(design, "opt_merge" + opt_merge_args); design->scratchpad_unset("opt.did_something"); Pass::call(design, "opt_rmdff"); if (design->scratchpad_get_bool("opt.did_something") == false) break; Pass::call(design, "opt_clean" + opt_clean_args); - log_header("Rerunning OPT passes. (Removed registers in this run.)\n"); + log_header(design, "Rerunning OPT passes. (Removed registers in this run.)\n"); } Pass::call(design, "opt_clean" + opt_clean_args); } else { - Pass::call(design, "opt_const" + opt_const_args); - Pass::call(design, "opt_share -nomux" + opt_share_args); + Pass::call(design, "opt_expr" + opt_expr_args); + Pass::call(design, "opt_merge -nomux" + opt_merge_args); while (1) { design->scratchpad_unset("opt.did_something"); Pass::call(design, "opt_muxtree"); Pass::call(design, "opt_reduce" + opt_reduce_args); - Pass::call(design, "opt_share" + opt_share_args); + Pass::call(design, "opt_merge" + opt_merge_args); Pass::call(design, "opt_rmdff"); Pass::call(design, "opt_clean" + opt_clean_args); - Pass::call(design, "opt_const" + opt_const_args); + Pass::call(design, "opt_expr" + opt_expr_args); if (design->scratchpad_get_bool("opt.did_something") == false) break; - log_header("Rerunning OPT passes. (Maybe there is more to do..)\n"); + log_header(design, "Rerunning OPT passes. (Maybe there is more to do..)\n"); } } @@ -158,7 +158,7 @@ struct OptPass : public Pass { design->sort(); design->check(); - log_header(fast_mode ? "Finished fast OPT passes.\n" : "Finished OPT passes. (There is nothing left to do.)\n"); + log_header(design, fast_mode ? "Finished fast OPT passes.\n" : "Finished OPT passes. (There is nothing left to do.)\n"); log_pop(); } } OptPass; diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc index 175e8e11..6600ffa2 100644 --- a/passes/opt/opt_clean.cc +++ b/passes/opt/opt_clean.cc @@ -156,6 +156,9 @@ bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool ®s, SigPoo if (w1->port_input != w2->port_input) return w2->port_input; + if ((w1->port_input && w1->port_output) != (w2->port_input && w2->port_output)) + return !(w2->port_input && w2->port_output); + if (w1->name[0] == '\\' && w2->name[0] == '\\') { if (regs.check_any(s1) != regs.check_any(s2)) return regs.check_any(s2); @@ -380,7 +383,7 @@ struct OptCleanPass : public Pass { { bool purge_mode = false; - log_header("Executing OPT_CLEAN pass (remove unused cells and wires).\n"); + log_header(design, "Executing OPT_CLEAN pass (remove unused cells and wires).\n"); log_push(); size_t argidx; diff --git a/passes/opt/opt_const.cc b/passes/opt/opt_expr.cc index 0fcacf0a..b62eae28 100644 --- a/passes/opt/opt_const.cc +++ b/passes/opt/opt_expr.cc @@ -179,7 +179,7 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ log("\n"); } - cover_list("opt.opt_const.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell->type.str()); + cover_list("opt.opt_expr.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell->type.str()); module->remove(cell); did_something = true; @@ -304,7 +304,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons for (auto cell : cells.sorted) { -#define ACTION_DO(_p_, _s_) do { cover("opt.opt_const.action_" S__LINE__); replace_cell(assign_map, module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0) +#define ACTION_DO(_p_, _s_) do { cover("opt.opt_expr.action_" S__LINE__); replace_cell(assign_map, module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0) #define ACTION_DO_Y(_v_) ACTION_DO("\\Y", RTLIL::SigSpec(RTLIL::State::S ## _v_)) if (clkinv) @@ -342,6 +342,68 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons handle_clkpol_celltype_swap(cell, "$_DLATCHSR_??N_", "$_DLATCHSR_??P_", "\\R", assign_map, invert_map); } + bool detect_const_and = false; + bool detect_const_or = false; + + if (cell->type.in("$reduce_and", "$_AND_")) + detect_const_and = true; + + if (cell->type.in("$and", "$logic_and") && GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\B")) == 1) + detect_const_and = true; + + if (cell->type.in("$reduce_or", "$reduce_bool", "$_OR_")) + detect_const_or = true; + + if (cell->type.in("$or", "$logic_or") && GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\B")) == 1) + detect_const_or = true; + + if (detect_const_and || detect_const_or) + { + pool<SigBit> input_bits = assign_map(cell->getPort("\\A")).to_sigbit_pool(); + bool found_zero = false, found_one = false, found_inv = false; + + if (cell->hasPort("\\B")) { + vector<SigBit> more_bits = assign_map(cell->getPort("\\B")).to_sigbit_vector(); + input_bits.insert(more_bits.begin(), more_bits.end()); + } + + for (auto bit : input_bits) { + if (bit == State::S0) + found_zero = true; + if (bit == State::S1) + found_one = true; + if (invert_map.count(bit) && input_bits.count(invert_map.at(bit))) + found_inv = true; + } + + if (detect_const_and && (found_zero || found_inv)) { + cover("opt.opt_expr.const_and"); + replace_cell(assign_map, module, cell, "const_and", "\\Y", RTLIL::State::S0); + goto next_cell; + } + + if (detect_const_or && (found_one || found_inv)) { + cover("opt.opt_expr.const_or"); + replace_cell(assign_map, module, cell, "const_or", "\\Y", RTLIL::State::S1); + goto next_cell; + } + } + + if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_bool", "$reduce_xor", "$reduce_xnor", "$neg") && + GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\Y")) == 1) + { + if (cell->type == "$reduce_xnor") { + cover("opt.opt_expr.reduce_xnor_not"); + log("Replacing %s cell `%s' in module `%s' with $not cell.\n", + log_id(cell->type), log_id(cell->name), log_id(module)); + cell->type = "$not"; + } else { + cover("opt.opt_expr.unary_buffer"); + replace_cell(assign_map, module, cell, "unary_buffer", "\\Y", cell->getPort("\\A")); + } + goto next_cell; + } + if (do_fine) { if (cell->type == "$not" || cell->type == "$pos" || @@ -366,7 +428,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) { - cover("opt.opt_const.fine.$reduce_and"); + cover("opt.opt_expr.fine.$reduce_and"); log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a)); cell->setPort("\\A", sig_a = new_a); @@ -392,7 +454,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) { - cover_list("opt.opt_const.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell->type.str()); + cover_list("opt.opt_expr.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell->type.str()); log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a)); cell->setPort("\\A", sig_a = new_a); @@ -418,7 +480,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } if (new_b != RTLIL::State::Sm && RTLIL::SigSpec(new_b) != sig_b) { - cover_list("opt.opt_const.fine.B", "$logic_and", "$logic_or", cell->type.str()); + cover_list("opt.opt_expr.fine.B", "$logic_and", "$logic_or", cell->type.str()); log("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_b)); cell->setPort("\\B", sig_b = new_b); @@ -428,18 +490,6 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } } - if (cell->type == "$logic_or" && (assign_map(cell->getPort("\\A")) == RTLIL::State::S1 || assign_map(cell->getPort("\\B")) == RTLIL::State::S1)) { - cover("opt.opt_const.one_high"); - replace_cell(assign_map, module, cell, "one high", "\\Y", RTLIL::State::S1); - goto next_cell; - } - - if (cell->type == "$logic_and" && (assign_map(cell->getPort("\\A")) == RTLIL::State::S0 || assign_map(cell->getPort("\\B")) == RTLIL::State::S0)) { - cover("opt.opt_const.one_low"); - replace_cell(assign_map, module, cell, "one low", "\\Y", RTLIL::State::S0); - goto next_cell; - } - if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor" || cell->type == "$shift" || cell->type == "$shiftx" || cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" || cell->type == "$lt" || cell->type == "$le" || cell->type == "$ge" || cell->type == "$gt" || @@ -462,7 +512,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (0) { found_the_x_bit: - cover_list("opt.opt_const.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", + cover_list("opt.opt_expr.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$pow", cell->type.str()); if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor" || cell->type == "$lt" || cell->type == "$le" || cell->type == "$ge" || cell->type == "$gt") @@ -475,13 +525,13 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if ((cell->type == "$_NOT_" || cell->type == "$not" || cell->type == "$logic_not") && cell->getPort("\\Y").size() == 1 && invert_map.count(assign_map(cell->getPort("\\A"))) != 0) { - cover_list("opt.opt_const.invert.double", "$_NOT_", "$not", "$logic_not", cell->type.str()); + cover_list("opt.opt_expr.invert.double", "$_NOT_", "$not", "$logic_not", cell->type.str()); replace_cell(assign_map, module, cell, "double_invert", "\\Y", invert_map.at(assign_map(cell->getPort("\\A")))); goto next_cell; } if ((cell->type == "$_MUX_" || cell->type == "$mux") && invert_map.count(assign_map(cell->getPort("\\S"))) != 0) { - cover_list("opt.opt_const.invert.muxsel", "$_MUX_", "$mux", cell->type.str()); + cover_list("opt.opt_expr.invert.muxsel", "$_MUX_", "$mux", cell->type.str()); log("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell->type), log_id(cell), log_id(module)); RTLIL::SigSpec tmp = cell->getPort("\\A"); cell->setPort("\\A", cell->getPort("\\B")); @@ -564,7 +614,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (input.match(" 1")) ACTION_DO("\\Y", input.extract(1, 1)); if (input.match("01 ")) ACTION_DO("\\Y", input.extract(0, 1)); if (input.match("10 ")) { - cover("opt.opt_const.mux_to_inv"); + cover("opt.opt_expr.mux_to_inv"); cell->type = "$_NOT_"; cell->setPort("\\A", input.extract(0, 1)); cell->unsetPort("\\B"); @@ -599,7 +649,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons log_assert(GetSize(a) == GetSize(b)); for (int i = 0; i < GetSize(a); i++) { if (a[i].wire == NULL && b[i].wire == NULL && a[i] != b[i] && a[i].data <= RTLIL::State::S1 && b[i].data <= RTLIL::State::S1) { - cover_list("opt.opt_const.eqneq.isneq", "$eq", "$ne", "$eqx", "$nex", cell->type.str()); + cover_list("opt.opt_expr.eqneq.isneq", "$eq", "$ne", "$eqx", "$nex", cell->type.str()); RTLIL::SigSpec new_y = RTLIL::SigSpec((cell->type == "$eq" || cell->type == "$eqx") ? RTLIL::State::S0 : RTLIL::State::S1); new_y.extend_u0(cell->parameters["\\Y_WIDTH"].as_int(), false); replace_cell(assign_map, module, cell, "isneq", "\\Y", new_y); @@ -612,7 +662,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } if (new_a.size() == 0) { - cover_list("opt.opt_const.eqneq.empty", "$eq", "$ne", "$eqx", "$nex", cell->type.str()); + cover_list("opt.opt_expr.eqneq.empty", "$eq", "$ne", "$eqx", "$nex", cell->type.str()); RTLIL::SigSpec new_y = RTLIL::SigSpec((cell->type == "$eq" || cell->type == "$eqx") ? RTLIL::State::S1 : RTLIL::State::S0); new_y.extend_u0(cell->parameters["\\Y_WIDTH"].as_int(), false); replace_cell(assign_map, module, cell, "empty", "\\Y", new_y); @@ -620,7 +670,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } if (new_a.size() < a.size() || new_b.size() < b.size()) { - cover_list("opt.opt_const.eqneq.resize", "$eq", "$ne", "$eqx", "$nex", cell->type.str()); + cover_list("opt.opt_expr.eqneq.resize", "$eq", "$ne", "$eqx", "$nex", cell->type.str()); cell->setPort("\\A", new_a); cell->setPort("\\B", new_b); cell->parameters["\\A_WIDTH"] = new_a.size(); @@ -635,7 +685,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons RTLIL::SigSpec b = assign_map(cell->getPort("\\B")); if (a.is_fully_const() && !b.is_fully_const()) { - cover_list("opt.opt_const.eqneq.swapconst", "$eq", "$ne", cell->type.str()); + cover_list("opt.opt_expr.eqneq.swapconst", "$eq", "$ne", cell->type.str()); cell->setPort("\\A", b); cell->setPort("\\B", a); std::swap(a, b); @@ -646,7 +696,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons RTLIL::SigSpec input = b; ACTION_DO("\\Y", cell->getPort("\\A")); } else { - cover_list("opt.opt_const.eqneq.isnot", "$eq", "$ne", cell->type.str()); + cover_list("opt.opt_expr.eqneq.isnot", "$eq", "$ne", cell->type.str()); log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module)); cell->type = "$not"; cell->parameters.erase("\\B_WIDTH"); @@ -661,7 +711,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if ((cell->type == "$eq" || cell->type == "$ne") && (assign_map(cell->getPort("\\A")).is_fully_zero() || assign_map(cell->getPort("\\B")).is_fully_zero())) { - cover_list("opt.opt_const.eqneq.cmpzero", "$eq", "$ne", cell->type.str()); + cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell->type.str()); log("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell), log_id(module), "$eq" ? "$logic_not" : "$reduce_bool"); cell->type = cell->type == "$eq" ? "$logic_not" : "$reduce_bool"; @@ -699,7 +749,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons sig_y[i] = sig_a[GetSize(sig_a)-1]; } - cover_list("opt.opt_const.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str()); + cover_list("opt.opt_expr.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str()); log("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n", log_id(cell->type), log_id(cell), log_signal(assign_map(cell->getPort("\\B"))), shift_bits, log_id(module), log_signal(sig_y)); @@ -760,9 +810,9 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (identity_wrt_a || identity_wrt_b) { if (identity_wrt_a) - cover_list("opt.opt_const.identwrt.a", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str()); + cover_list("opt.opt_expr.identwrt.a", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str()); if (identity_wrt_b) - cover_list("opt.opt_const.identwrt.b", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str()); + cover_list("opt.opt_expr.identwrt.b", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str()); log("Replacing %s cell `%s' in module `%s' with identity for port %c.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), identity_wrt_a ? 'A' : 'B'); @@ -786,14 +836,14 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == RTLIL::SigSpec(0, 1) && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) { - cover_list("opt.opt_const.mux_bool", "$mux", "$_MUX_", cell->type.str()); + cover_list("opt.opt_expr.mux_bool", "$mux", "$_MUX_", cell->type.str()); replace_cell(assign_map, module, cell, "mux_bool", "\\Y", cell->getPort("\\S")); goto next_cell; } if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == RTLIL::SigSpec(1, 1) && cell->getPort("\\B") == RTLIL::SigSpec(0, 1)) { - cover_list("opt.opt_const.mux_invert", "$mux", "$_MUX_", cell->type.str()); + cover_list("opt.opt_expr.mux_invert", "$mux", "$_MUX_", cell->type.str()); log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module)); cell->setPort("\\A", cell->getPort("\\S")); cell->unsetPort("\\B"); @@ -812,7 +862,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == RTLIL::SigSpec(0, 1)) { - cover_list("opt.opt_const.mux_and", "$mux", "$_MUX_", cell->type.str()); + cover_list("opt.opt_expr.mux_and", "$mux", "$_MUX_", cell->type.str()); log("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); cell->setPort("\\A", cell->getPort("\\S")); cell->unsetPort("\\S"); @@ -832,7 +882,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) { - cover_list("opt.opt_const.mux_or", "$mux", "$_MUX_", cell->type.str()); + cover_list("opt.opt_expr.mux_or", "$mux", "$_MUX_", cell->type.str()); log("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); cell->setPort("\\B", cell->getPort("\\S")); cell->unsetPort("\\S"); @@ -856,7 +906,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons int width = cell->getPort("\\A").size(); if ((cell->getPort("\\A").is_fully_undef() && cell->getPort("\\B").is_fully_undef()) || cell->getPort("\\S").is_fully_undef()) { - cover_list("opt.opt_const.mux_undef", "$mux", "$pmux", cell->type.str()); + cover_list("opt.opt_expr.mux_undef", "$mux", "$pmux", cell->type.str()); replace_cell(assign_map, module, cell, "mux_undef", "\\Y", cell->getPort("\\A")); goto next_cell; } @@ -875,17 +925,17 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons new_s = new_s.extract(0, new_s.size()-1); } if (new_s.size() == 0) { - cover_list("opt.opt_const.mux_empty", "$mux", "$pmux", cell->type.str()); + cover_list("opt.opt_expr.mux_empty", "$mux", "$pmux", cell->type.str()); replace_cell(assign_map, module, cell, "mux_empty", "\\Y", new_a); goto next_cell; } if (new_a == RTLIL::SigSpec(RTLIL::State::S0) && new_b == RTLIL::SigSpec(RTLIL::State::S1)) { - cover_list("opt.opt_const.mux_sel01", "$mux", "$pmux", cell->type.str()); + cover_list("opt.opt_expr.mux_sel01", "$mux", "$pmux", cell->type.str()); replace_cell(assign_map, module, cell, "mux_sel01", "\\Y", new_s); goto next_cell; } if (cell->getPort("\\S").size() != new_s.size()) { - cover_list("opt.opt_const.mux_reduce", "$mux", "$pmux", cell->type.str()); + cover_list("opt.opt_expr.mux_reduce", "$mux", "$pmux", cell->type.str()); log("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n", GetSize(cell->getPort("\\S")) - GetSize(new_s), log_id(cell->type), log_id(cell), log_id(module)); cell->setPort("\\A", new_a); @@ -911,7 +961,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), dummy_arg, \ cell->parameters["\\A_SIGNED"].as_bool(), false, \ cell->parameters["\\Y_WIDTH"].as_int())); \ - cover("opt.opt_const.const.$" #_t); \ + cover("opt.opt_expr.const.$" #_t); \ replace_cell(assign_map, module, cell, stringf("%s", log_signal(a)), "\\Y", y); \ goto next_cell; \ } \ @@ -926,7 +976,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons cell->parameters["\\A_SIGNED"].as_bool(), \ cell->parameters["\\B_SIGNED"].as_bool(), \ cell->parameters["\\Y_WIDTH"].as_int())); \ - cover("opt.opt_const.const.$" #_t); \ + cover("opt.opt_expr.const.$" #_t); \ replace_cell(assign_map, module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), "\\Y", y); \ goto next_cell; \ } \ @@ -1002,7 +1052,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (a_val == 0) { - cover("opt.opt_const.mul_shift.zero"); + cover("opt.opt_expr.mul_shift.zero"); log("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n", cell->name.c_str(), module->name.c_str()); @@ -1018,9 +1068,9 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (a_val == (1 << i)) { if (swapped_ab) - cover("opt.opt_const.mul_shift.swapped"); + cover("opt.opt_expr.mul_shift.swapped"); else - cover("opt.opt_const.mul_shift.unswapped"); + cover("opt.opt_expr.mul_shift.unswapped"); log("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n", a_val, cell->name.c_str(), module->name.c_str(), i); @@ -1048,6 +1098,75 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } } + if (!keepdc && cell->type.in("$div", "$mod")) + { + bool b_signed = cell->parameters["\\B_SIGNED"].as_bool(); + SigSpec sig_b = assign_map(cell->getPort("\\B")); + SigSpec sig_y = assign_map(cell->getPort("\\Y")); + + if (sig_b.is_fully_def() && sig_b.size() <= 32) + { + int b_val = sig_b.as_int(); + + if (b_val == 0) + { + cover("opt.opt_expr.divmod_zero"); + + log("Replacing divide-by-zero cell `%s' in module `%s' with undef-driver.\n", + cell->name.c_str(), module->name.c_str()); + + module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(State::Sx, sig_y.size()))); + module->remove(cell); + + did_something = true; + goto next_cell; + } + + for (int i = 1; i < (b_signed ? sig_b.size()-1 : sig_b.size()); i++) + if (b_val == (1 << i)) + { + if (cell->type == "$div") + { + cover("opt.opt_expr.div_shift"); + + log("Replacing divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n", + b_val, cell->name.c_str(), module->name.c_str(), i); + + std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(i, 6); + + while (GetSize(new_b) > 1 && new_b.back() == RTLIL::State::S0) + new_b.pop_back(); + + cell->type = "$shr"; + cell->parameters["\\B_WIDTH"] = GetSize(new_b); + cell->parameters["\\B_SIGNED"] = false; + cell->setPort("\\B", new_b); + cell->check(); + } + else + { + cover("opt.opt_expr.mod_mask"); + + log("Replacing modulo-by-%d cell `%s' in module `%s' with bitmask.\n", + b_val, cell->name.c_str(), module->name.c_str()); + + std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(State::S1, i); + + if (b_signed) + new_b.push_back(State::S0); + + cell->type = "$and"; + cell->parameters["\\B_WIDTH"] = GetSize(new_b); + cell->setPort("\\B", new_b); + cell->check(); + } + + did_something = true; + goto next_cell; + } + } + } + next_cell:; #undef ACTION_DO #undef ACTION_DO_Y @@ -1056,15 +1175,16 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } } -struct OptConstPass : public Pass { - OptConstPass() : Pass("opt_const", "perform const folding") { } +struct OptExprPass : public Pass { + OptExprPass() : Pass("opt_expr", "perform const folding and simple expression rewriting") { } virtual void help() { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" opt_const [options] [selection]\n"); + log(" opt_expr [options] [selection]\n"); log("\n"); log("This pass performs const folding on internal cell types with constant inputs.\n"); + log("It also performs some simple expression rewritring.\n"); log("\n"); log(" -mux_undef\n"); log(" remove 'undef' inputs from $mux, $pmux and $_MUX_ cells\n"); @@ -1100,7 +1220,7 @@ struct OptConstPass : public Pass { bool do_fine = false; bool keepdc = false; - log_header("Executing OPT_CONST pass (perform const folding).\n"); + log_header(design, "Executing OPT_EXPR pass (perform const folding).\n"); log_push(); size_t argidx; @@ -1158,6 +1278,6 @@ struct OptConstPass : public Pass { log_pop(); } -} OptConstPass; +} OptExprPass; PRIVATE_NAMESPACE_END diff --git a/passes/opt/opt_share.cc b/passes/opt/opt_merge.cc index 46752e43..97989d27 100644 --- a/passes/opt/opt_share.cc +++ b/passes/opt/opt_merge.cc @@ -31,7 +31,7 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -struct OptShareWorker +struct OptMergeWorker { RTLIL::Design *design; RTLIL::Module *module; @@ -45,6 +45,29 @@ struct OptShareWorker dict<const RTLIL::Cell*, std::string> cell_hash_cache; #endif + static void sort_pmux_conn(dict<RTLIL::IdString, RTLIL::SigSpec> &conn) + { + SigSpec sig_s = conn.at("\\S"); + SigSpec sig_b = conn.at("\\B"); + + int s_width = GetSize(sig_s); + int width = GetSize(sig_b) / s_width; + + vector<pair<SigBit, SigSpec>> sb_pairs; + for (int i = 0; i < s_width; i++) + sb_pairs.push_back(pair<SigBit, SigSpec>(sig_s[i], sig_b.extract(i*width, width))); + + std::sort(sb_pairs.begin(), sb_pairs.end()); + + conn["\\S"] = SigSpec(); + conn["\\B"] = SigSpec(); + + for (auto &it : sb_pairs) { + conn["\\S"].append(it.first); + conn["\\B"].append(it.second); + } + } + #ifdef USE_CELL_HASH_CACHE std::string int_to_hash_string(unsigned int v) { @@ -91,25 +114,40 @@ struct OptShareWorker assign_map.apply(alt_conn.at("\\A")); alt_conn.at("\\A").sort_and_unify(); conn = &alt_conn; + } else + if (cell->type == "$pmux") { + alt_conn = *conn; + assign_map.apply(alt_conn.at("\\A")); + assign_map.apply(alt_conn.at("\\B")); + assign_map.apply(alt_conn.at("\\S")); + sort_pmux_conn(alt_conn); + conn = &alt_conn; } + vector<string> hash_conn_strings; + for (auto &it : *conn) { if (cell->output(it.first)) continue; RTLIL::SigSpec sig = it.second; assign_map.apply(sig); - hash_string += "C " + it.first.str() + "="; + string s = "C " + it.first.str() + "="; for (auto &chunk : sig.chunks()) { if (chunk.wire) - hash_string += "{" + chunk.wire->name.str() + " " + + s += "{" + chunk.wire->name.str() + " " + int_to_hash_string(chunk.offset) + " " + int_to_hash_string(chunk.width) + "}"; else - hash_string += RTLIL::Const(chunk.data).as_string(); + s += RTLIL::Const(chunk.data).as_string(); } - hash_string += "\n"; + hash_conn_strings.push_back(s + "\n"); } + std::sort(hash_conn_strings.begin(), hash_conn_strings.end()); + + for (auto it : hash_conn_strings) + hash_string += it; + cell_hash_cache[cell] = sha1(hash_string); return cell_hash_cache[cell]; } @@ -171,6 +209,10 @@ struct OptShareWorker if (cell1->type == "$reduce_and" || cell1->type == "$reduce_or" || cell1->type == "$reduce_bool") { conn1["\\A"].sort_and_unify(); conn2["\\A"].sort_and_unify(); + } else + if (cell1->type == "$pmux") { + sort_pmux_conn(conn1); + sort_pmux_conn(conn2); } if (conn1 != conn2) { @@ -212,14 +254,14 @@ struct OptShareWorker } struct CompareCells { - OptShareWorker *that; - CompareCells(OptShareWorker *that) : that(that) {} + OptMergeWorker *that; + CompareCells(OptMergeWorker *that) : that(that) {} bool operator()(const RTLIL::Cell *cell1, const RTLIL::Cell *cell2) const { return that->compare_cells(cell1, cell2); } }; - OptShareWorker(RTLIL::Design *design, RTLIL::Module *module, bool mode_nomux, bool mode_share_all) : + OptMergeWorker(RTLIL::Design *design, RTLIL::Module *module, bool mode_nomux, bool mode_share_all) : design(design), module(module), assign_map(module), mode_share_all(mode_share_all) { total_count = 0; @@ -286,13 +328,13 @@ struct OptShareWorker } }; -struct OptSharePass : public Pass { - OptSharePass() : Pass("opt_share", "consolidate identical cells") { } +struct OptMergePass : public Pass { + OptMergePass() : Pass("opt_merge", "consolidate identical cells") { } virtual void help() { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" opt_share [options] [selection]\n"); + log(" opt_merge [options] [selection]\n"); log("\n"); log("This pass identifies cells with identical type and input signals. Such cells\n"); log("are then merged to one cell.\n"); @@ -306,7 +348,7 @@ struct OptSharePass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing OPT_SHARE pass (detect identical cells).\n"); + log_header(design, "Executing OPT_MERGE pass (detect identical cells).\n"); bool mode_nomux = false; bool mode_share_all = false; @@ -328,7 +370,7 @@ struct OptSharePass : public Pass { int total_count = 0; for (auto module : design->selected_modules()) { - OptShareWorker worker(design, module, mode_nomux, mode_share_all); + OptMergeWorker worker(design, module, mode_nomux, mode_share_all); total_count += worker.total_count; } @@ -336,6 +378,6 @@ struct OptSharePass : public Pass { design->scratchpad_set_bool("opt.did_something", true); log("Removed a total of %d cells.\n", total_count); } -} OptSharePass; +} OptMergePass; PRIVATE_NAMESPACE_END diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc index 905a0162..f5ddc2af 100644 --- a/passes/opt/opt_muxtree.cc +++ b/passes/opt/opt_muxtree.cc @@ -68,7 +68,7 @@ struct OptMuxtreeWorker OptMuxtreeWorker(RTLIL::Design *design, RTLIL::Module *module) : design(design), module(module), assign_map(module), removed_count(0) { - log("Running muxtree optimizier on module %s..\n", module->name.c_str()); + log("Running muxtree optimizer on module %s..\n", module->name.c_str()); log(" Creating internal representation of mux trees.\n"); @@ -464,7 +464,7 @@ struct OptMuxtreePass : public Pass { } virtual void execute(vector<std::string> args, RTLIL::Design *design) { - log_header("Executing OPT_MUXTREE pass (detect dead branches in mux trees).\n"); + log_header(design, "Executing OPT_MUXTREE pass (detect dead branches in mux trees).\n"); extra_args(args, 1, design); int total_count = 0; diff --git a/passes/opt/opt_reduce.cc b/passes/opt/opt_reduce.cc index 98b7b2e1..eb9d02ad 100644 --- a/passes/opt/opt_reduce.cc +++ b/passes/opt/opt_reduce.cc @@ -354,7 +354,7 @@ struct OptReducePass : public Pass { { bool do_fine = false; - log_header("Executing OPT_REDUCE pass (consolidate $*mux and $reduce_* inputs).\n"); + log_header(design, "Executing OPT_REDUCE pass (consolidate $*mux and $reduce_* inputs).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc index e1b184af..fa954afa 100644 --- a/passes/opt/opt_rmdff.cc +++ b/passes/opt/opt_rmdff.cc @@ -60,7 +60,7 @@ bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch) return false; delete_dlatch: - log("Removing %s (%s) from module %s.\n", dlatch->name.c_str(), dlatch->type.c_str(), mod->name.c_str()); + log("Removing %s (%s) from module %s.\n", log_id(dlatch), log_id(dlatch->type), log_id(mod)); remove_init_attr(dlatch->getPort("\\Q")); mod->remove(dlatch); return true; @@ -170,7 +170,7 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff) return false; delete_dff: - log("Removing %s (%s) from module %s.\n", dff->name.c_str(), dff->type.c_str(), mod->name.c_str()); + log("Removing %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod)); remove_init_attr(dff->getPort("\\Q")); mod->remove(dff); return true; @@ -190,73 +190,116 @@ struct OptRmdffPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - int total_count = 0; - log_header("Executing OPT_RMDFF pass (remove dff with constant values).\n"); + int total_count = 0, total_initdrv = 0; + log_header(design, "Executing OPT_RMDFF pass (remove dff with constant values).\n"); extra_args(args, 1, design); - for (auto &mod_it : design->modules_) + for (auto module : design->selected_modules()) { - if (!design->selected(mod_it.second)) - continue; - - assign_map.set(mod_it.second); - dff_init_map.set(mod_it.second); - for (auto &it : mod_it.second->wires_) - if (it.second->attributes.count("\\init") != 0) { - dff_init_map.add(it.second, it.second->attributes.at("\\init")); - for (int i = 0; i < GetSize(it.second); i++) { - SigBit wire_bit(it.second, i), mapped_bit = assign_map(wire_bit); - if (mapped_bit.wire) + pool<SigBit> driven_bits; + dict<SigBit, State> init_bits; + + assign_map.set(module); + dff_init_map.set(module); + + for (auto wire : module->wires()) + { + if (wire->attributes.count("\\init") != 0) { + Const initval = wire->attributes.at("\\init"); + dff_init_map.add(wire, initval); + for (int i = 0; i < GetSize(wire); i++) { + SigBit wire_bit(wire, i), mapped_bit = assign_map(wire_bit); + if (mapped_bit.wire) { init_attributes[mapped_bit].insert(wire_bit); + if (i < GetSize(initval)) + init_bits[mapped_bit] = initval[i]; + } } } + + if (wire->port_input) { + for (auto bit : assign_map(wire)) + driven_bits.insert(bit); + } + } mux_drivers.clear(); std::vector<RTLIL::IdString> dff_list; std::vector<RTLIL::IdString> dlatch_list; - for (auto &it : mod_it.second->cells_) { - if (it.second->type == "$mux" || it.second->type == "$pmux") { - if (it.second->getPort("\\A").size() == it.second->getPort("\\B").size()) - mux_drivers.insert(assign_map(it.second->getPort("\\Y")), it.second); + for (auto cell : module->cells()) + { + for (auto &conn : cell->connections()) + if (cell->output(conn.first) || !cell->known()) + for (auto bit : assign_map(conn.second)) + driven_bits.insert(bit); + + if (cell->type == "$mux" || cell->type == "$pmux") { + if (cell->getPort("\\A").size() == cell->getPort("\\B").size()) + mux_drivers.insert(assign_map(cell->getPort("\\Y")), cell); continue; } - if (!design->selected(mod_it.second, it.second)) + + if (!design->selected(module, cell)) continue; - if (it.second->type == "$_DFF_N_") dff_list.push_back(it.first); - if (it.second->type == "$_DFF_P_") dff_list.push_back(it.first); - if (it.second->type == "$_DFF_NN0_") dff_list.push_back(it.first); - if (it.second->type == "$_DFF_NN1_") dff_list.push_back(it.first); - if (it.second->type == "$_DFF_NP0_") dff_list.push_back(it.first); - if (it.second->type == "$_DFF_NP1_") dff_list.push_back(it.first); - if (it.second->type == "$_DFF_PN0_") dff_list.push_back(it.first); - if (it.second->type == "$_DFF_PN1_") dff_list.push_back(it.first); - if (it.second->type == "$_DFF_PP0_") dff_list.push_back(it.first); - if (it.second->type == "$_DFF_PP1_") dff_list.push_back(it.first); - if (it.second->type == "$dff") dff_list.push_back(it.first); - if (it.second->type == "$adff") dff_list.push_back(it.first); - if (it.second->type == "$dlatch") dlatch_list.push_back(it.first); + + if (cell->type.in("$_DFF_N_", "$_DFF_P_", + "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", + "$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_", + "$dff", "$adff")) + dff_list.push_back(cell->name); + + if (cell->type == "$dlatch") + dlatch_list.push_back(cell->name); } for (auto &id : dff_list) { - if (mod_it.second->cells_.count(id) > 0 && - handle_dff(mod_it.second, mod_it.second->cells_[id])) + if (module->cell(id) != nullptr && + handle_dff(module, module->cells_[id])) total_count++; } for (auto &id : dlatch_list) { - if (mod_it.second->cells_.count(id) > 0 && - handle_dlatch(mod_it.second, mod_it.second->cells_[id])) + if (module->cell(id) != nullptr && + handle_dlatch(module, module->cells_[id])) total_count++; } + + SigSpec const_init_sigs; + + for (auto bit : init_bits) + if (!driven_bits.count(bit.first)) + const_init_sigs.append(bit.first); + + const_init_sigs.sort_and_unify(); + + for (SigSpec sig : const_init_sigs.chunks()) + { + Const val; + + for (auto bit : sig) + val.bits.push_back(init_bits.at(bit)); + + log("Promoting init spec %s = %s to constant driver in module %s.\n", + log_signal(sig), log_signal(val), log_id(module)); + + module->connect(sig, val); + remove_init_attr(sig); + total_initdrv++; + } } assign_map.clear(); mux_drivers.clear(); - if (total_count) + if (total_count || total_initdrv) design->scratchpad_set_bool("opt.did_something", true); - log("Replaced %d DFF cells.\n", total_count); + + if (total_initdrv) + log("Promoted %d init specs to constant drivers.\n", total_initdrv); + + if (total_count) + log("Replaced %d DFF cells.\n", total_count); } } OptRmdffPass; diff --git a/passes/opt/share.cc b/passes/opt/share.cc index 1d9b1006..22914eaa 100644 --- a/passes/opt/share.cc +++ b/passes/opt/share.cc @@ -793,10 +793,59 @@ struct ShareWorker return true; } - void optimize_activation_patterns(pool<ssc_pair_t> & /* patterns */) + void optimize_activation_patterns(pool<ssc_pair_t> &patterns) { // TODO: Remove patterns that are contained in other patterns - // TODO: Consolidate pairs of patterns that only differ in the value for one signal bit + + dict<SigSpec, pool<Const>> db; + bool did_something = false; + + for (auto const &p : patterns) + { + auto &sig = p.first; + auto &val = p.second; + int len = GetSize(sig); + + for (int i = 0; i < len; i++) + { + auto otherval = val; + + if (otherval.bits[i] == State::S0) + otherval.bits[i] = State::S1; + else if (otherval.bits[i] == State::S1) + otherval.bits[i] = State::S0; + else + continue; + + if (db[sig].count(otherval)) + { + auto newsig = sig; + newsig.remove(i); + + auto newval = val; + newval.bits.erase(newval.bits.begin() + i); + + db[newsig].insert(newval); + db[sig].erase(otherval); + + did_something = true; + goto next_pattern; + } + } + + db[sig].insert(val); + next_pattern:; + } + + if (!did_something) + return; + + patterns.clear(); + for (auto &it : db) + for (auto &val : it.second) + patterns.insert(make_pair(it.first, val)); + + optimize_activation_patterns(patterns); } const pool<ssc_pair_t> &find_cell_activation_patterns(RTLIL::Cell *cell, const char *indent) @@ -1451,7 +1500,7 @@ struct SharePass : public Pass { config.generic_other_ops.insert("$alu"); config.generic_other_ops.insert("$macc"); - log_header("Executing SHARE pass (SAT-based resource sharing).\n"); + log_header(design, "Executing SHARE pass (SAT-based resource sharing).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index 4f08da67..07503fbb 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -366,15 +366,26 @@ struct WreducePass : public Pass { log(" assign y = a + b + c + 1;\n"); log(" endmodule\n"); log("\n"); + log("Options:\n"); + log("\n"); + log(" -memx\n"); + log(" Do not change the width of memory address ports. Use this options in\n"); + log(" flows that use the 'memory_memx' pass.\n"); + log("\n"); } virtual void execute(std::vector<std::string> args, Design *design) { WreduceConfig config; + bool opt_memx = false; - log_header("Executing WREDUCE pass (reducing word size of cells).\n"); + log_header(design, "Executing WREDUCE pass (reducing word size of cells).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-memx") { + opt_memx = true; + continue; + } break; } extra_args(args, argidx, design); @@ -385,6 +396,7 @@ struct WreducePass : public Pass { continue; for (auto c : module->selected_cells()) + { if (c->type.in("$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool", "$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt", "$logic_not", "$logic_and", "$logic_or") && GetSize(c->getPort("\\Y")) > 1) { @@ -396,6 +408,23 @@ struct WreducePass : public Pass { module->connect(sig, Const(0, GetSize(sig))); } } + if (!opt_memx && c->type.in("$memrd", "$memwr", "$meminit")) { + IdString memid = c->getParam("\\MEMID").decode_string(); + RTLIL::Memory *mem = module->memories.at(memid); + if (mem->start_offset >= 0) { + int cur_addrbits = c->getParam("\\ABITS").as_int(); + int max_addrbits = ceil_log2(mem->start_offset + mem->size); + if (cur_addrbits > max_addrbits) { + log("Removed top %d address bits (of %d) from memory %s port %s.%s (%s).\n", + cur_addrbits-max_addrbits, cur_addrbits, + c->type == "$memrd" ? "read" : c->type == "$memwr" ? "write" : "init", + log_id(module), log_id(c), log_id(memid)); + c->setParam("\\ABITS", max_addrbits); + c->setPort("\\ADDR", c->getPort("\\ADDR").extract(0, max_addrbits)); + } + } + } + } WreduceWorker worker(&config, module); worker.run(); diff --git a/passes/proc/proc.cc b/passes/proc/proc.cc index 577ff6bf..d5366f26 100644 --- a/passes/proc/proc.cc +++ b/passes/proc/proc.cc @@ -52,12 +52,17 @@ struct ProcPass : public Pass { log(" -global_arst [!]<netname>\n"); log(" This option is passed through to proc_arst.\n"); log("\n"); + log(" -ifx\n"); + log(" This option is passed through to proc_mux. proc_rmdead is not\n"); + log(" executed in -ifx mode.\n"); + log("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { std::string global_arst; + bool ifxmode = false; - log_header("Executing PROC pass (convert processes to netlists).\n"); + log_header(design, "Executing PROC pass (convert processes to netlists).\n"); log_push(); size_t argidx; @@ -67,18 +72,23 @@ struct ProcPass : public Pass { global_arst = args[++argidx]; continue; } + if (args[argidx] == "-ifx") { + ifxmode = true; + continue; + } break; } extra_args(args, argidx, design); Pass::call(design, "proc_clean"); - Pass::call(design, "proc_rmdead"); + if (!ifxmode) + Pass::call(design, "proc_rmdead"); Pass::call(design, "proc_init"); if (global_arst.empty()) Pass::call(design, "proc_arst"); else Pass::call(design, "proc_arst -global_arst " + global_arst); - Pass::call(design, "proc_mux"); + Pass::call(design, ifxmode ? "proc_mux -ifx" : "proc_mux"); Pass::call(design, "proc_dlatch"); Pass::call(design, "proc_dff"); Pass::call(design, "proc_clean"); diff --git a/passes/proc/proc_arst.cc b/passes/proc/proc_arst.cc index 1da23728..216b00dd 100644 --- a/passes/proc/proc_arst.cc +++ b/passes/proc/proc_arst.cc @@ -226,7 +226,7 @@ struct ProcArstPass : public Pass { std::string global_arst; bool global_arst_neg = false; - log_header("Executing PROC_ARST pass (detect async resets in processes).\n"); + log_header(design, "Executing PROC_ARST pass (detect async resets in processes).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) diff --git a/passes/proc/proc_clean.cc b/passes/proc/proc_clean.cc index 35801951..7dbabc21 100644 --- a/passes/proc/proc_clean.cc +++ b/passes/proc/proc_clean.cc @@ -156,7 +156,7 @@ struct ProcCleanPass : public Pass { virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { int total_count = 0; - log_header("Executing PROC_CLEAN pass (remove empty switches from decision trees).\n"); + log_header(design, "Executing PROC_CLEAN pass (remove empty switches from decision trees).\n"); extra_args(args, 1, design); diff --git a/passes/proc/proc_dff.cc b/passes/proc/proc_dff.cc index 63713139..f532990c 100644 --- a/passes/proc/proc_dff.cc +++ b/passes/proc/proc_dff.cc @@ -369,7 +369,7 @@ struct ProcDffPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing PROC_DFF pass (convert process syncs to FFs).\n"); + log_header(design, "Executing PROC_DFF pass (convert process syncs to FFs).\n"); extra_args(args, 1, design); diff --git a/passes/proc/proc_dlatch.cc b/passes/proc/proc_dlatch.cc index e37d81dd..6621afd3 100644 --- a/passes/proc/proc_dlatch.cc +++ b/passes/proc/proc_dlatch.cc @@ -33,6 +33,8 @@ struct proc_dlatch_db_t Module *module; SigMap sigmap; + pool<Cell*> generated_dlatches; + dict<Cell*, vector<SigBit>> mux_srcbits; dict<SigBit, pair<Cell*, int>> mux_drivers; dict<SigBit, int> sigusers; @@ -40,10 +42,24 @@ struct proc_dlatch_db_t { for (auto cell : module->cells()) { - if (cell->type.in("$mux", "$pmux")) { + if (cell->type.in("$mux", "$pmux")) + { auto sig_y = sigmap(cell->getPort("\\Y")); for (int i = 0; i < GetSize(sig_y); i++) mux_drivers[sig_y[i]] = pair<Cell*, int>(cell, i); + + pool<SigBit> mux_srcbits_pool; + for (auto bit : sigmap(cell->getPort("\\A"))) + mux_srcbits_pool.insert(bit); + for (auto bit : sigmap(cell->getPort("\\B"))) + mux_srcbits_pool.insert(bit); + + vector<SigBit> mux_srcbits_vec; + for (auto bit : mux_srcbits_pool) + if (bit.wire != nullptr) + mux_srcbits_vec.push_back(bit); + + mux_srcbits[cell].swap(mux_srcbits_vec); } for (auto &conn : cell->connections()) @@ -58,6 +74,42 @@ struct proc_dlatch_db_t sigusers[bit]++; } + bool quickcheck(const SigSpec &haystack, const SigSpec &needle) + { + pool<SigBit> haystack_bits = sigmap(haystack).to_sigbit_pool(); + pool<SigBit> needle_bits = sigmap(needle).to_sigbit_pool(); + + pool<Cell*> cells_queue, cells_visited; + pool<SigBit> bits_queue, bits_visited; + + bits_queue = haystack_bits; + while (!bits_queue.empty()) + { + for (auto &bit : bits_queue) { + auto it = mux_drivers.find(bit); + if (it != mux_drivers.end()) + if (!cells_visited.count(it->second.first)) + cells_queue.insert(it->second.first); + bits_visited.insert(bit); + } + + bits_queue.clear(); + + for (auto c : cells_queue) { + for (auto bit : mux_srcbits[c]) { + if (needle_bits.count(bit)) + return true; + if (!bits_visited.count(bit)) + bits_queue.insert(bit); + } + } + + cells_queue.clear(); + } + + return false; + } + struct rule_node_t { // a node is true if "signal" equals "match" and [any @@ -202,6 +254,84 @@ struct proc_dlatch_db_t rules_sig[n] = and_bits[0]; return and_bits[0]; } + + void fixup_mux(Cell *cell) + { + SigSpec sig_a = cell->getPort("\\A"); + SigSpec sig_b = cell->getPort("\\B"); + SigSpec sig_s = cell->getPort("\\S"); + SigSpec sig_any_valid_b; + + SigSpec sig_new_b, sig_new_s; + for (int i = 0; i < GetSize(sig_s); i++) { + SigSpec b = sig_b.extract(i*GetSize(sig_a), GetSize(sig_a)); + if (!b.is_fully_undef()) { + sig_any_valid_b = b; + sig_new_b.append(b); + sig_new_s.append(sig_s[i]); + } + } + + if (sig_new_s.empty()) { + sig_new_b = sig_a; + sig_new_s = State::S0; + } + + if (sig_a.is_fully_undef() && !sig_any_valid_b.empty()) + cell->setPort("\\A", sig_any_valid_b); + + if (GetSize(sig_new_s) == 1) { + cell->type = "$mux"; + cell->unsetParam("\\S_WIDTH"); + } else { + cell->type = "$pmux"; + cell->setParam("\\S_WIDTH", GetSize(sig_new_s)); + } + + cell->setPort("\\B", sig_new_b); + cell->setPort("\\S", sig_new_s); + } + + void fixup_muxes() + { + pool<Cell*> visited, queue; + dict<Cell*, pool<SigBit>> upstream_cell2net; + dict<SigBit, pool<Cell*>> upstream_net2cell; + + CellTypes ct; + ct.setup_internals(); + + for (auto cell : module->cells()) + for (auto conn : cell->connections()) { + if (cell->input(conn.first)) + for (auto bit : sigmap(conn.second)) + upstream_cell2net[cell].insert(bit); + if (cell->output(conn.first)) + for (auto bit : sigmap(conn.second)) + upstream_net2cell[bit].insert(cell); + } + + queue = generated_dlatches; + while (!queue.empty()) + { + pool<Cell*> next_queue; + + for (auto cell : queue) { + if (cell->type.in("$mux", "$pmux")) + fixup_mux(cell); + for (auto bit : upstream_cell2net[cell]) + for (auto cell : upstream_net2cell[bit]) + next_queue.insert(cell); + visited.insert(cell); + } + + queue.clear(); + for (auto cell : next_queue) { + if (!visited.count(cell) && ct.cell_known(cell->type)) + queue.insert(cell); + } + } + } }; void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc) @@ -218,9 +348,17 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc) continue; } - for (auto ss : sr->actions) { + for (auto ss : sr->actions) + { db.sigmap.apply(ss.first); db.sigmap.apply(ss.second); + + if (!db.quickcheck(ss.second, ss.first)) { + nolatches_bits.first.append(ss.first); + nolatches_bits.second.append(ss.second); + continue; + } + for (int i = 0; i < GetSize(ss.first); i++) latches_out_in[ss.first[i]] = ss.second[i]; } @@ -268,6 +406,8 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc) SigSpec rhs = latches_bits.second.extract(offset, width); Cell *cell = db.module->addDlatch(NEW_ID, db.module->Not(NEW_ID, db.make_hold(n)), rhs, lhs); + db.generated_dlatches.insert(cell); + log("Latch inferred for signal `%s.%s' from process `%s.%s': %s\n", db.module->name.c_str(), log_signal(lhs), db.module->name.c_str(), proc->name.c_str(), log_id(cell)); } @@ -292,7 +432,7 @@ struct ProcDlatchPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing PROC_DLATCH pass (convert process syncs to latches).\n"); + log_header(design, "Executing PROC_DLATCH pass (convert process syncs to latches).\n"); extra_args(args, 1, design); @@ -301,6 +441,7 @@ struct ProcDlatchPass : public Pass { for (auto &proc_it : module->processes) if (design->selected(module, proc_it.second)) proc_dlatch(db, proc_it.second); + db.fixup_muxes(); } } } ProcDlatchPass; diff --git a/passes/proc/proc_init.cc b/passes/proc/proc_init.cc index 633d4e58..0c8fb83d 100644 --- a/passes/proc/proc_init.cc +++ b/passes/proc/proc_init.cc @@ -61,13 +61,28 @@ void proc_init(RTLIL::Module *mod, RTLIL::Process *proc) log_cmd_error("Failed to get a constant init value for %s: %s\n", log_signal(lhs), log_signal(rhs)); int offset = 0; - for (auto &lhs_c : lhs.chunks()) { - if (lhs_c.wire != NULL) { - RTLIL::SigSpec value = rhs.extract(offset, lhs_c.width); - if (value.size() != lhs_c.wire->width) - log_cmd_error("Init value is not for the entire wire: %s = %s\n", log_signal(lhs_c), log_signal(value)); - log(" Setting init value: %s = %s\n", log_signal(lhs_c.wire), log_signal(value)); - lhs_c.wire->attributes["\\init"] = value.as_const(); + for (auto &lhs_c : lhs.chunks()) + { + if (lhs_c.wire != nullptr) + { + SigSpec valuesig = rhs.extract(offset, lhs_c.width); + if (!valuesig.is_fully_const()) + log_cmd_error("Non-const initialization value: %s = %s\n", log_signal(lhs_c), log_signal(valuesig)); + + Const value = valuesig.as_const(); + Const &wireinit = lhs_c.wire->attributes["\\init"]; + + while (GetSize(wireinit.bits) < lhs_c.wire->width) + wireinit.bits.push_back(State::Sx); + + for (int i = 0; i < lhs_c.width; i++) { + auto &initbit = wireinit.bits[i + lhs_c.offset]; + if (initbit != State::Sx && initbit != value[i]) + log_cmd_error("Conflicting initialization values for %s.\n", log_signal(lhs_c)); + initbit = value[i]; + } + + log(" Set init value: %s = %s\n", log_signal(lhs_c.wire), log_signal(wireinit)); } offset += lhs_c.width; } @@ -100,7 +115,7 @@ struct ProcInitPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing PROC_INIT pass (extract init attributes).\n"); + log_header(design, "Executing PROC_INIT pass (extract init attributes).\n"); extra_args(args, 1, design); diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc index 943e8c56..57e131ca 100644 --- a/passes/proc/proc_mux.cc +++ b/passes/proc/proc_mux.cc @@ -143,7 +143,7 @@ struct SnippetSwCache } }; -RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SwitchRule *sw) +RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SwitchRule *sw, bool ifxmode) { std::stringstream sstr; sstr << "$procmux$" << (autoidx++); @@ -164,14 +164,14 @@ RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s if (comp.size() == 0) return RTLIL::SigSpec(); - if (sig.size() == 1 && comp == RTLIL::SigSpec(1,1)) + if (sig.size() == 1 && comp == RTLIL::SigSpec(1,1) && !ifxmode) { mod->connect(RTLIL::SigSig(RTLIL::SigSpec(cmp_wire, cmp_wire->width++), sig)); } else { // create compare cell - RTLIL::Cell *eq_cell = mod->addCell(stringf("%s_CMP%d", sstr.str().c_str(), cmp_wire->width), "$eq"); + RTLIL::Cell *eq_cell = mod->addCell(stringf("%s_CMP%d", sstr.str().c_str(), cmp_wire->width), ifxmode ? "$eqx" : "$eq"); eq_cell->attributes = sw->attributes; eq_cell->parameters["\\A_SIGNED"] = RTLIL::Const(0); @@ -211,7 +211,7 @@ RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s return RTLIL::SigSpec(ctrl_wire); } -RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::SigSpec else_signal, RTLIL::Cell *&last_mux_cell, RTLIL::SwitchRule *sw) +RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::SigSpec else_signal, RTLIL::Cell *&last_mux_cell, RTLIL::SwitchRule *sw, bool ifxmode) { log_assert(when_signal.size() == else_signal.size()); @@ -223,7 +223,7 @@ RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s return when_signal; // compare results - RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw); + RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw, ifxmode); if (ctrl_sig.size() == 0) return when_signal; log_assert(ctrl_sig.size() == 1); @@ -245,12 +245,15 @@ RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s return RTLIL::SigSpec(result_wire); } -void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::Cell *last_mux_cell, RTLIL::SwitchRule *sw) +void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::Cell *last_mux_cell, RTLIL::SwitchRule *sw, bool ifxmode) { log_assert(last_mux_cell != NULL); log_assert(when_signal.size() == last_mux_cell->getPort("\\A").size()); - RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw); + if (when_signal == last_mux_cell->getPort("\\A")) + return; + + RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw, ifxmode); log_assert(ctrl_sig.size() == 1); last_mux_cell->type = "$pmux"; @@ -266,7 +269,7 @@ void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::ve } RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, dict<RTLIL::SwitchRule*, bool, hash_ptr_ops> &swpara, - RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval) + RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval, bool ifxmode) { RTLIL::SigSpec result = defval; @@ -329,7 +332,7 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d for (auto pat : cs2->compare) if (!pat.is_fully_const()) extra_group_for_next_case = true; - else + else if (!ifxmode) pool.take(pat); } } @@ -340,18 +343,18 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d for (size_t i = 0; i < sw->cases.size(); i++) { int case_idx = sw->cases.size() - i - 1; RTLIL::CaseRule *cs2 = sw->cases[case_idx]; - RTLIL::SigSpec value = signal_to_mux_tree(mod, swcache, swpara, cs2, sig, initial_val); + RTLIL::SigSpec value = signal_to_mux_tree(mod, swcache, swpara, cs2, sig, initial_val, ifxmode); if (last_mux_cell && pgroups[case_idx] == pgroups[case_idx+1]) - append_pmux(mod, sw->signal, cs2->compare, value, last_mux_cell, sw); + append_pmux(mod, sw->signal, cs2->compare, value, last_mux_cell, sw, ifxmode); else - result = gen_mux(mod, sw->signal, cs2->compare, value, result, last_mux_cell, sw); + result = gen_mux(mod, sw->signal, cs2->compare, value, result, last_mux_cell, sw, ifxmode); } } return result; } -void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc) +void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc, bool ifxmode) { log("Creating decoders for process `%s.%s'.\n", mod->name.c_str(), proc->name.c_str()); @@ -372,7 +375,7 @@ void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc) log("%6d/%d: %s\n", ++cnt, GetSize(sigsnip.snippets), log_signal(sig)); - RTLIL::SigSpec value = signal_to_mux_tree(mod, swcache, swpara, &proc->root_case, sig, RTLIL::SigSpec(RTLIL::State::Sx, sig.size())); + RTLIL::SigSpec value = signal_to_mux_tree(mod, swcache, swpara, &proc->root_case, sig, RTLIL::SigSpec(RTLIL::State::Sx, sig.size()), ifxmode); mod->connect(RTLIL::SigSig(sig, value)); } } @@ -383,23 +386,37 @@ struct ProcMuxPass : public Pass { { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" proc_mux [selection]\n"); + log(" proc_mux [options] [selection]\n"); log("\n"); log("This pass converts the decision trees in processes (originating from if-else\n"); log("and case statements) to trees of multiplexer cells.\n"); log("\n"); + log(" -ifx\n"); + log(" Use Verilog simulation behavior with respect to undef values in\n"); + log(" 'case' expressions and 'if' conditions.\n"); + log("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing PROC_MUX pass (convert decision trees to multiplexers).\n"); + bool ifxmode = false; + log_header(design, "Executing PROC_MUX pass (convert decision trees to multiplexers).\n"); - extra_args(args, 1, design); + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-ifx") { + ifxmode = true; + continue; + } + break; + } + extra_args(args, argidx, design); for (auto mod : design->modules()) if (design->selected(mod)) for (auto &proc_it : mod->processes) if (design->selected(mod, proc_it.second)) - proc_mux(mod, proc_it.second); + proc_mux(mod, proc_it.second, ifxmode); } } ProcMuxPass; diff --git a/passes/proc/proc_rmdead.cc b/passes/proc/proc_rmdead.cc index f60d4b30..5672fb47 100644 --- a/passes/proc/proc_rmdead.cc +++ b/passes/proc/proc_rmdead.cc @@ -51,8 +51,8 @@ void proc_rmdead(RTLIL::SwitchRule *sw, int &counter) counter++; continue; } - if (pool.empty()) - sw->cases[i]->compare.clear(); + // if (pool.empty()) + // sw->cases[i]->compare.clear(); } for (auto switch_it : sw->cases[i]->switches) @@ -76,7 +76,7 @@ struct ProcRmdeadPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing PROC_RMDEAD pass (remove dead branches from decision trees).\n"); + log_header(design, "Executing PROC_RMDEAD pass (remove dead branches from decision trees).\n"); extra_args(args, 1, design); diff --git a/passes/sat/Makefile.inc b/passes/sat/Makefile.inc index 4fa6bf0d..0c5f6fc6 100644 --- a/passes/sat/Makefile.inc +++ b/passes/sat/Makefile.inc @@ -4,4 +4,5 @@ OBJS += passes/sat/freduce.o OBJS += passes/sat/eval.o OBJS += passes/sat/miter.o OBJS += passes/sat/expose.o +OBJS += passes/sat/assertpmux.o diff --git a/passes/sat/assertpmux.cc b/passes/sat/assertpmux.cc new file mode 100644 index 00000000..63a90767 --- /dev/null +++ b/passes/sat/assertpmux.cc @@ -0,0 +1,240 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct AssertpmuxWorker +{ + Module *module; + SigMap sigmap; + + bool flag_noinit; + bool flag_always; + + // get<0> ... mux cell + // get<1> ... mux port index + // get<2> ... mux bit index + dict<SigBit, pool<tuple<Cell*, int, int>>> sigbit_muxusers; + + dict<SigBit, SigBit> sigbit_actsignals; + dict<SigSpec, SigBit> sigspec_actsignals; + dict<tuple<Cell*, int>, SigBit> muxport_actsignal; + + AssertpmuxWorker(Module *module, bool flag_noinit, bool flag_always) : + module(module), sigmap(module), flag_noinit(flag_noinit), flag_always(flag_always) + { + for (auto wire : module->wires()) + { + if (wire->port_output) + for (auto bit : sigmap(wire)) + sigbit_actsignals[bit] = State::S1; + } + + for (auto cell : module->cells()) + { + if (cell->type.in("$mux", "$pmux")) + { + int width = cell->getParam("\\WIDTH").as_int(); + int numports = cell->type == "$mux" ? 2 : cell->getParam("\\S_WIDTH").as_int() + 1; + + SigSpec sig_a = sigmap(cell->getPort("\\A")); + SigSpec sig_b = sigmap(cell->getPort("\\B")); + SigSpec sig_s = sigmap(cell->getPort("\\S")); + + for (int i = 0; i < numports; i++) { + SigSpec bits = i == 0 ? sig_a : sig_b.extract(width*(i-1), width); + for (int k = 0; k < width; k++) { + tuple<Cell*, int, int> muxuser(cell, i, k); + sigbit_muxusers[bits[k]].insert(muxuser); + } + } + } + else + { + for (auto &conn : cell->connections()) { + if (!cell->known() || cell->input(conn.first)) + for (auto bit : sigmap(conn.second)) + sigbit_actsignals[bit] = State::S1; + } + } + } + } + + SigBit get_bit_activation(SigBit bit) + { + sigmap.apply(bit); + + if (sigbit_actsignals.count(bit) == 0) + { + SigSpec output; + + for (auto muxuser : sigbit_muxusers.at(bit)) + { + Cell *cell = std::get<0>(muxuser); + int portidx = std::get<1>(muxuser); + int bitidx = std::get<2>(muxuser); + + tuple<Cell*, int> muxport(cell, portidx); + + if (muxport_actsignal.count(muxport) == 0) { + if (portidx == 0) + muxport_actsignal[muxport] = module->LogicNot(NEW_ID, cell->getPort("\\S")); + else + muxport_actsignal[muxport] = cell->getPort("\\S")[portidx-1]; + } + + output.append(module->LogicAnd(NEW_ID, muxport_actsignal.at(muxport), get_bit_activation(cell->getPort("\\Y")[bitidx]))); + } + + output.sort_and_unify(); + + if (GetSize(output) == 0) + output = State::S0; + else if (GetSize(output) > 1) + output = module->ReduceOr(NEW_ID, output); + + sigbit_actsignals[bit] = output.as_bit(); + } + + return sigbit_actsignals.at(bit); + } + + SigBit get_activation(SigSpec sig) + { + sigmap.apply(sig); + sig.sort_and_unify(); + + if (sigspec_actsignals.count(sig) == 0) + { + SigSpec output; + + for (auto bit : sig) + output.append(get_bit_activation(bit)); + + output.sort_and_unify(); + + if (GetSize(output) == 0) + output = State::S0; + else if (GetSize(output) > 1) + output = module->ReduceOr(NEW_ID, output); + + sigspec_actsignals[sig] = output.as_bit(); + } + + return sigspec_actsignals.at(sig); + } + + void run(Cell *pmux) + { + log("Adding assert for $pmux cell %s.%s.\n", log_id(module), log_id(pmux)); + + int swidth = pmux->getParam("\\S_WIDTH").as_int(); + int cntbits = ceil_log2(swidth+1); + + SigSpec sel = pmux->getPort("\\S"); + SigSpec cnt(State::S0, cntbits); + + for (int i = 0; i < swidth; i++) + cnt = module->Add(NEW_ID, cnt, sel[i]); + + SigSpec assert_a = module->Le(NEW_ID, cnt, SigSpec(1, cntbits)); + SigSpec assert_en; + + if (flag_noinit) + assert_en.append(module->LogicNot(NEW_ID, module->Initstate(NEW_ID))); + + if (!flag_always) + assert_en.append(get_activation(pmux->getPort("\\Y"))); + + if (GetSize(assert_en) == 0) + assert_en = State::S1; + + if (GetSize(assert_en) == 2) + assert_en = module->LogicAnd(NEW_ID, assert_en[0], assert_en[1]); + + Cell *assert_cell = module->addAssert(NEW_ID, assert_a, assert_en); + + if (pmux->attributes.count("\\src") != 0) + assert_cell->attributes["\\src"] = pmux->attributes.at("\\src"); + } +}; + +struct AssertpmuxPass : public Pass { + AssertpmuxPass() : Pass("assertpmux", "convert internal signals to module ports") { } + virtual void help() + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" assertpmux [options] [selection]\n"); + log("\n"); + log("This command adds asserts to the design that assert that all parallel muxes\n"); + log("($pmux cells) have a maximum of one of their inputs enable at any time.\n"); + log("\n"); + log(" -noinit\n"); + log(" do not enforce the pmux condition during the init state\n"); + log("\n"); + log(" -always\n"); + log(" usually the $pmux condition is only checked when the $pmux output\n"); + log(" is used be the mux tree it drives. this option will deactivate this\n"); + log(" additional constrained and check the $pmux condition always.\n"); + log("\n"); + } + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + { + bool flag_noinit = false; + bool flag_always = false; + + log_header(design, "Executing ASSERTPMUX pass (add asserts for $pmux cells).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-noinit") { + flag_noinit = true; + continue; + } + if (args[argidx] == "-always") { + flag_always = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + { + AssertpmuxWorker worker(module, flag_noinit, flag_always); + vector<Cell*> pmux_cells; + + for (auto cell : module->selected_cells()) + if (cell->type == "$pmux") + pmux_cells.push_back(cell); + + for (auto cell : pmux_cells) + worker.run(cell); + } + + } +} AssertpmuxPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/sat/eval.cc b/passes/sat/eval.cc index 614a1bd3..09f69cc5 100644 --- a/passes/sat/eval.cc +++ b/passes/sat/eval.cc @@ -389,7 +389,7 @@ struct EvalPass : public Pass { std::vector<std::string> shows, tables; bool set_undef = false; - log_header("Executing EVAL pass (evaluate the circuit given an input).\n"); + log_header(design, "Executing EVAL pass (evaluate the circuit given an input).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { diff --git a/passes/sat/expose.cc b/passes/sat/expose.cc index ebdf2ed5..9427547f 100644 --- a/passes/sat/expose.cc +++ b/passes/sat/expose.cc @@ -262,7 +262,7 @@ struct ExposePass : public Pass { bool flag_evert_dff = false; std::string sep = "."; - log_header("Executing EXPOSE pass (exposing internal signals as outputs).\n"); + log_header(design, "Executing EXPOSE pass (exposing internal signals as outputs).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) diff --git a/passes/sat/freduce.cc b/passes/sat/freduce.cc index 373b8048..77263f6a 100644 --- a/passes/sat/freduce.cc +++ b/passes/sat/freduce.cc @@ -798,7 +798,7 @@ struct FreducePass : public Pass { inv_mode = false; dump_prefix = std::string(); - log_header("Executing FREDUCE pass (perform functional reduction).\n"); + log_header(design, "Executing FREDUCE pass (perform functional reduction).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { diff --git a/passes/sat/miter.cc b/passes/sat/miter.cc index 682299ef..4854e19b 100644 --- a/passes/sat/miter.cc +++ b/passes/sat/miter.cc @@ -32,7 +32,7 @@ void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL: bool flag_make_assert = false; bool flag_flatten = false; - log_header("Executing MITER pass (creating miter circuit).\n"); + log_header(design, "Executing MITER pass (creating miter circuit).\n"); size_t argidx; for (argidx = 2; argidx < args.size(); argidx++) @@ -254,7 +254,7 @@ void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL: if (flag_flatten) { log_push(); - Pass::call_on_module(design, miter_module, "flatten; opt_const -keepdc -undriven;;"); + Pass::call_on_module(design, miter_module, "flatten; opt_expr -keepdc -undriven;;"); log_pop(); } } @@ -264,7 +264,7 @@ void create_miter_assert(struct Pass *that, std::vector<std::string> args, RTLIL bool flag_make_outputs = false; bool flag_flatten = false; - log_header("Executing MITER pass (creating miter circuit).\n"); + log_header(design, "Executing MITER pass (creating miter circuit).\n"); size_t argidx; for (argidx = 2; argidx < args.size(); argidx++) @@ -327,7 +327,7 @@ void create_miter_assert(struct Pass *that, std::vector<std::string> args, RTLIL if (flag_flatten) { log_push(); - Pass::call_on_module(design, module, "opt_const -keepdc -undriven;;"); + Pass::call_on_module(design, module, "opt_expr -keepdc -undriven;;"); log_pop(); } } @@ -361,7 +361,7 @@ struct MiterPass : public Pass { log(" also create an 'assert' cell that checks if trigger is always low.\n"); log("\n"); log(" -flatten\n"); - log(" call 'flatten; opt_const -keepdc -undriven;;' on the miter circuit.\n"); + log(" call 'flatten; opt_expr -keepdc -undriven;;' on the miter circuit.\n"); log("\n"); log("\n"); log(" miter -assert [options] module [miter_name]\n"); @@ -375,7 +375,7 @@ struct MiterPass : public Pass { log(" keep module output ports.\n"); log("\n"); log(" -flatten\n"); - log(" call 'flatten; opt_const -keepdc -undriven;;' on the miter circuit.\n"); + log(" call 'flatten; opt_expr -keepdc -undriven;;' on the miter circuit.\n"); log("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc index 2e9c6d2f..a6ac7afd 100644 --- a/passes/sat/sat.cc +++ b/passes/sat/sat.cc @@ -90,106 +90,16 @@ struct SatHelper log_cmd_error("Bit %d of %s is undef but option -enable_undef is missing!\n", int(i), log_signal(sig)); } - void setup_init() - { - log ("\nSetting up initial state:\n"); - - RTLIL::SigSpec big_lhs, big_rhs; - - for (auto &it : module->wires_) - { - if (it.second->attributes.count("\\init") == 0) - continue; - - RTLIL::SigSpec lhs = sigmap(it.second); - RTLIL::SigSpec rhs = it.second->attributes.at("\\init"); - log_assert(lhs.size() == rhs.size()); - - RTLIL::SigSpec removed_bits; - for (int i = 0; i < lhs.size(); i++) { - RTLIL::SigSpec bit = lhs.extract(i, 1); - if (!satgen.initial_state.check_all(bit)) { - removed_bits.append(bit); - lhs.remove(i, 1); - rhs.remove(i, 1); - i--; - } - } - - if (removed_bits.size()) - log_warning("ignoring initial value on non-register: %s\n", log_signal(removed_bits)); - - if (lhs.size()) { - log("Import set-constraint from init attribute: %s = %s\n", log_signal(lhs), log_signal(rhs)); - big_lhs.remove2(lhs, &big_rhs); - big_lhs.append(lhs); - big_rhs.append(rhs); - } - } - - for (auto &s : sets_init) - { - RTLIL::SigSpec lhs, rhs; - - if (!RTLIL::SigSpec::parse_sel(lhs, design, module, s.first)) - log_cmd_error("Failed to parse lhs set expression `%s'.\n", s.first.c_str()); - if (!RTLIL::SigSpec::parse_rhs(lhs, rhs, module, s.second)) - log_cmd_error("Failed to parse rhs set expression `%s'.\n", s.second.c_str()); - show_signal_pool.add(sigmap(lhs)); - show_signal_pool.add(sigmap(rhs)); - - if (lhs.size() != rhs.size()) - log_cmd_error("Set expression with different lhs and rhs sizes: %s (%s, %d bits) vs. %s (%s, %d bits)\n", - s.first.c_str(), log_signal(lhs), lhs.size(), s.second.c_str(), log_signal(rhs), rhs.size()); - - log("Import set-constraint: %s = %s\n", log_signal(lhs), log_signal(rhs)); - big_lhs.remove2(lhs, &big_rhs); - big_lhs.append(lhs); - big_rhs.append(rhs); - } - - if (!satgen.initial_state.check_all(big_lhs)) { - RTLIL::SigSpec rem = satgen.initial_state.remove(big_lhs); - log_cmd_error("Found -set-init bits that are not part of the initial_state: %s\n", log_signal(rem)); - } - - if (set_init_def) { - RTLIL::SigSpec rem = satgen.initial_state.export_all(); - std::vector<int> undef_rem = satgen.importUndefSigSpec(rem, 1); - ez->assume(ez->NOT(ez->expression(ezSAT::OpOr, undef_rem))); - } - - if (set_init_undef) { - RTLIL::SigSpec rem = satgen.initial_state.export_all(); - rem.remove(big_lhs); - big_lhs.append(rem); - big_rhs.append(RTLIL::SigSpec(RTLIL::State::Sx, rem.size())); - } - - if (set_init_zero) { - RTLIL::SigSpec rem = satgen.initial_state.export_all(); - rem.remove(big_lhs); - big_lhs.append(rem); - big_rhs.append(RTLIL::SigSpec(RTLIL::State::S0, rem.size())); - } - - if (big_lhs.size() == 0) { - log("No constraints for initial state found.\n\n"); - return; - } - - log("Final constraint equation: %s = %s\n\n", log_signal(big_lhs), log_signal(big_rhs)); - check_undef_enabled(big_lhs), check_undef_enabled(big_rhs); - ez->assume(satgen.signals_eq(big_lhs, big_rhs, 1)); - } - - void setup(int timestep = -1) + void setup(int timestep = -1, bool initstate = false) { if (timestep > 0) log ("\nSetting up time step %d:\n", timestep); else log ("\nSetting up SAT problem:\n"); + if (initstate) + satgen.setInitState(timestep); + if (timestep > max_timestep) max_timestep = timestep; @@ -341,6 +251,97 @@ struct SatHelper log("Import constraint from assume cell: %s when %s.\n", log_signal(assumes_a[i]), log_signal(assumes_en[i])); ez->assume(satgen.importAssumes(timestep)); } + + if (initstate) + { + RTLIL::SigSpec big_lhs, big_rhs; + + for (auto &it : module->wires_) + { + if (it.second->attributes.count("\\init") == 0) + continue; + + RTLIL::SigSpec lhs = sigmap(it.second); + RTLIL::SigSpec rhs = it.second->attributes.at("\\init"); + log_assert(lhs.size() == rhs.size()); + + RTLIL::SigSpec removed_bits; + for (int i = 0; i < lhs.size(); i++) { + RTLIL::SigSpec bit = lhs.extract(i, 1); + if (!satgen.initial_state.check_all(bit)) { + removed_bits.append(bit); + lhs.remove(i, 1); + rhs.remove(i, 1); + i--; + } + } + + if (removed_bits.size()) + log_warning("ignoring initial value on non-register: %s\n", log_signal(removed_bits)); + + if (lhs.size()) { + log("Import set-constraint from init attribute: %s = %s\n", log_signal(lhs), log_signal(rhs)); + big_lhs.remove2(lhs, &big_rhs); + big_lhs.append(lhs); + big_rhs.append(rhs); + } + } + + for (auto &s : sets_init) + { + RTLIL::SigSpec lhs, rhs; + + if (!RTLIL::SigSpec::parse_sel(lhs, design, module, s.first)) + log_cmd_error("Failed to parse lhs set expression `%s'.\n", s.first.c_str()); + if (!RTLIL::SigSpec::parse_rhs(lhs, rhs, module, s.second)) + log_cmd_error("Failed to parse rhs set expression `%s'.\n", s.second.c_str()); + show_signal_pool.add(sigmap(lhs)); + show_signal_pool.add(sigmap(rhs)); + + if (lhs.size() != rhs.size()) + log_cmd_error("Set expression with different lhs and rhs sizes: %s (%s, %d bits) vs. %s (%s, %d bits)\n", + s.first.c_str(), log_signal(lhs), lhs.size(), s.second.c_str(), log_signal(rhs), rhs.size()); + + log("Import init set-constraint: %s = %s\n", log_signal(lhs), log_signal(rhs)); + big_lhs.remove2(lhs, &big_rhs); + big_lhs.append(lhs); + big_rhs.append(rhs); + } + + if (!satgen.initial_state.check_all(big_lhs)) { + RTLIL::SigSpec rem = satgen.initial_state.remove(big_lhs); + log_cmd_error("Found -set-init bits that are not part of the initial_state: %s\n", log_signal(rem)); + } + + if (set_init_def) { + RTLIL::SigSpec rem = satgen.initial_state.export_all(); + std::vector<int> undef_rem = satgen.importUndefSigSpec(rem, 1); + ez->assume(ez->NOT(ez->expression(ezSAT::OpOr, undef_rem))); + } + + if (set_init_undef) { + RTLIL::SigSpec rem = satgen.initial_state.export_all(); + rem.remove(big_lhs); + big_lhs.append(rem); + big_rhs.append(RTLIL::SigSpec(RTLIL::State::Sx, rem.size())); + } + + if (set_init_zero) { + RTLIL::SigSpec rem = satgen.initial_state.export_all(); + rem.remove(big_lhs); + big_lhs.append(rem); + big_rhs.append(RTLIL::SigSpec(RTLIL::State::S0, rem.size())); + } + + if (big_lhs.size() == 0) { + log("No constraints for initial state found.\n\n"); + return; + } + + log("Final init constraint equation: %s = %s\n", log_signal(big_lhs), log_signal(big_rhs)); + check_undef_enabled(big_lhs), check_undef_enabled(big_rhs); + ez->assume(satgen.signals_eq(big_lhs, big_rhs, timestep)); + } } int setup_proof(int timestep = -1) @@ -630,11 +631,11 @@ struct SatHelper "---------------------------------------------------------------------------------------------------"; if (last_timestep == -2) { log(max_timestep > 0 ? " Time " : " "); - log("%-*s %10s %10s %*s\n", maxModelName+10, "Signal Name", "Dec", "Hex", maxModelWidth+5, "Bin"); + log("%-*s %11s %9s %*s\n", maxModelName+5, "Signal Name", "Dec", "Hex", maxModelWidth+3, "Bin"); } log(max_timestep > 0 ? " ---- " : " "); - log("%*.*s %10.10s %10.10s %*.*s\n", maxModelName+10, maxModelName+10, - hline, hline, hline, maxModelWidth+5, maxModelWidth+5, hline); + log("%*.*s %11.11s %9.9s %*.*s\n", maxModelName+5, maxModelName+5, + hline, hline, hline, maxModelWidth+3, maxModelWidth+3, hline); last_timestep = info.timestep; } @@ -647,9 +648,9 @@ struct SatHelper log(" "); if (info.width <= 32 && !found_undef) - log("%-*s %10d %10x %*s\n", maxModelName+10, info.description.c_str(), value.as_int(), value.as_int(), maxModelWidth+5, value.as_string().c_str()); + log("%-*s %11d %9x %*s\n", maxModelName+5, info.description.c_str(), value.as_int(), value.as_int(), maxModelWidth+3, value.as_string().c_str()); else - log("%-*s %10s %10s %*s\n", maxModelName+10, info.description.c_str(), "--", "--", maxModelWidth+5, value.as_string().c_str()); + log("%-*s %11s %9s %*s\n", maxModelName+5, info.description.c_str(), "--", "--", maxModelWidth+3, value.as_string().c_str()); } if (last_timestep == -2) @@ -1073,7 +1074,7 @@ struct SatPass : public Pass { int tempinduct_skip = 0, stepsize = 1; std::string vcd_file_name, json_file_name, cnf_file_name; - log_header("Executing SAT pass (solving SAT problems in the circuit).\n"); + log_header(design, "Executing SAT pass (solving SAT problems in the circuit).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { @@ -1377,7 +1378,6 @@ struct SatPass : public Pass { SatHelper basecase(design, module, enable_undef); SatHelper inductstep(design, module, enable_undef); - bool basecase_setup_init = true; basecase.sets = sets; basecase.set_assumes = set_assumes; @@ -1403,7 +1403,7 @@ struct SatPass : public Pass { for (int timestep = 1; timestep <= seq_len; timestep++) if (!tempinduct_inductonly) - basecase.setup(timestep); + basecase.setup(timestep, timestep == 1); inductstep.sets = sets; inductstep.set_assumes = set_assumes; @@ -1436,15 +1436,10 @@ struct SatPass : public Pass { if (!tempinduct_inductonly) { - basecase.setup(seq_len + inductlen); + basecase.setup(seq_len + inductlen, seq_len + inductlen == 1); int property = basecase.setup_proof(seq_len + inductlen); basecase.generate_model(); - if (basecase_setup_init) { - basecase.setup_init(); - basecase_setup_init = false; - } - if (inductlen > 1) basecase.force_unique_state(seq_len + 1, seq_len + inductlen); @@ -1452,6 +1447,7 @@ struct SatPass : public Pass { { log("\n[base case %d] Solving problem with %d variables and %d clauses..\n", inductlen, basecase.ez->numCnfVariables(), basecase.ez->numCnfClauses()); + log_flush(); if (basecase.solve(basecase.ez->NOT(property))) { log("SAT temporal induction proof finished - model found for base case: FAIL!\n"); @@ -1522,6 +1518,7 @@ struct SatPass : public Pass { log("\n[induction step %d] Solving problem with %d variables and %d clauses..\n", inductlen, inductstep.ez->numCnfVariables(), inductstep.ez->numCnfClauses()); + log_flush(); if (!inductstep.solve(inductstep.ez->NOT(property))) { if (inductstep.gotTimeout) @@ -1599,14 +1596,13 @@ struct SatPass : public Pass { } else { std::vector<int> prove_bits; for (int timestep = 1; timestep <= seq_len; timestep++) { - sathelper.setup(timestep); + sathelper.setup(timestep, timestep == 1); if (sathelper.prove.size() || sathelper.prove_x.size() || sathelper.prove_asserts) if (timestep > prove_skip) prove_bits.push_back(sathelper.setup_proof(timestep)); } if (sathelper.prove.size() || sathelper.prove_x.size() || sathelper.prove_asserts) sathelper.ez->assume(sathelper.ez->NOT(sathelper.ez->expression(ezSAT::OpAnd, prove_bits))); - sathelper.setup_init(); } sathelper.generate_model(); @@ -1628,6 +1624,7 @@ struct SatPass : public Pass { rerun_solver: log("\nSolving problem with %d variables and %d clauses..\n", sathelper.ez->numCnfVariables(), sathelper.ez->numCnfClauses()); + log_flush(); if (sathelper.solve()) { diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index 8112516c..b5024fa9 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -7,6 +7,9 @@ OBJS += passes/techmap/libparse.o ifeq ($(ENABLE_ABC),1) OBJS += passes/techmap/abc.o +ifneq ($(ABCEXTERNAL),) +passes/techmap/abc.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' +endif endif ifneq ($(SMALL),1) @@ -23,6 +26,11 @@ OBJS += passes/techmap/tribuf.o OBJS += passes/techmap/lut2mux.o OBJS += passes/techmap/nlutmap.o OBJS += passes/techmap/dffsr2dff.o +OBJS += passes/techmap/shregmap.o +OBJS += passes/techmap/deminout.o +OBJS += passes/techmap/insbuf.o +OBJS += passes/techmap/attrmvcp.o +OBJS += passes/techmap/attrmap.o endif GENFILES += passes/techmap/techmap.inc diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 7da26602..cc79296c 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -29,15 +29,17 @@ // Kahn, Arthur B. (1962), "Topological sorting of large networks", Communications of the ACM 5 (11): 558-562, doi:10.1145/368996.369025 // http://en.wikipedia.org/wiki/Topological_sorting -#define ABC_COMMAND_LIB "strash; scorr; ifraig; retime {D}; strash; dch -f; map {D}" -#define ABC_COMMAND_CTR "strash; scorr; ifraig; retime {D}; strash; dch -f; map {D}; buffer; upsize {D}; dnsize {D}; stime -p" -#define ABC_COMMAND_LUT "strash; scorr; ifraig; retime; strash; dch -f; if" -#define ABC_COMMAND_DFL "strash; scorr; ifraig; retime; strash; dch -f; map" - -#define ABC_FAST_COMMAND_LIB "retime {D}; map {D}" -#define ABC_FAST_COMMAND_CTR "retime {D}; map {D}; buffer; upsize {D}; dnsize {D}; stime -p" -#define ABC_FAST_COMMAND_LUT "retime; if" -#define ABC_FAST_COMMAND_DFL "retime; map" +#define ABC_COMMAND_LIB "strash; dc2; scorr; ifraig; retime -o {D}; strash; dch -f; map {D}" +#define ABC_COMMAND_CTR "strash; dc2; scorr; ifraig; retime -o {D}; strash; dch -f; map {D}; buffer; upsize {D}; dnsize {D}; stime -p" +#define ABC_COMMAND_LUT "strash; dc2; scorr; ifraig; retime -o; strash; dch -f; if; mfs" +#define ABC_COMMAND_SOP "strash; dc2; scorr; ifraig; retime -o; strash; dch -f; cover {I} {P}" +#define ABC_COMMAND_DFL "strash; dc2; scorr; ifraig; retime -o; strash; dch -f; map" + +#define ABC_FAST_COMMAND_LIB "retime -o {D}; map {D}" +#define ABC_FAST_COMMAND_CTR "retime -o {D}; map {D}; buffer; upsize {D}; dnsize {D}; stime -p" +#define ABC_FAST_COMMAND_LUT "retime -o; if" +#define ABC_FAST_COMMAND_SOP "retime -o; cover -I {I} -P {P}" +#define ABC_FAST_COMMAND_DFL "retime -o; map" #include "kernel/register.h" #include "kernel/sigtools.h" @@ -593,7 +595,8 @@ struct abc_output_filter void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, std::string liberty_file, std::string constr_file, bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str, - bool keepff, std::string delay_target, bool fast_mode, const std::vector<RTLIL::Cell*> &cells, bool show_tempdir) + bool keepff, std::string delay_target, std::string sop_inputs, std::string sop_products, bool fast_mode, + const std::vector<RTLIL::Cell*> &cells, bool show_tempdir, bool sop_mode) { module = current_module; map_autoidx = autoidx++; @@ -616,7 +619,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin if (!cleanup) tempdir_name[0] = tempdir_name[4] = '_'; tempdir_name = make_temp_dir(tempdir_name); - log_header("Extracting gate netlist of module `%s' to `%s/input.blif'..\n", + log_header(design, "Extracting gate netlist of module `%s' to `%s/input.blif'..\n", module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str()); std::string abc_script = stringf("read_blif %s/input.blif; ", tempdir_name.c_str()); @@ -642,16 +645,30 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin abc_script += script_file[i]; } else abc_script += stringf("source %s", script_file.c_str()); - } else if (!lut_costs.empty()) + } else if (!lut_costs.empty()) { + bool all_luts_cost_same = true; + for (int this_cost : lut_costs) + if (this_cost != lut_costs.front()) + all_luts_cost_same = false; abc_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT; - else if (!liberty_file.empty()) + if (all_luts_cost_same && !fast_mode) + abc_script += "; lutpack"; + } else if (!liberty_file.empty()) abc_script += constr_file.empty() ? (fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR); + else if (sop_mode) + abc_script += fast_mode ? ABC_FAST_COMMAND_SOP : ABC_COMMAND_SOP; else abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL; for (size_t pos = abc_script.find("{D}"); pos != std::string::npos; pos = abc_script.find("{D}", pos)) abc_script = abc_script.substr(0, pos) + delay_target + abc_script.substr(pos+3); + for (size_t pos = abc_script.find("{I}"); pos != std::string::npos; pos = abc_script.find("{D}", pos)) + abc_script = abc_script.substr(0, pos) + sop_inputs + abc_script.substr(pos+3); + + for (size_t pos = abc_script.find("{P}"); pos != std::string::npos; pos = abc_script.find("{D}", pos)) + abc_script = abc_script.substr(0, pos) + sop_products + abc_script.substr(pos+3); + abc_script += stringf("; write_blif %s/output.blif", tempdir_name.c_str()); abc_script = add_echos_to_abc_cmd(abc_script); @@ -828,7 +845,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin if (count_output > 0) { - log_header("Executing ABC.\n"); + log_header(design, "Executing ABC.\n"); buffer = stringf("%s/stdcells.genlib", tempdir_name.c_str()); f = fopen(buffer.c_str(), "wt"); @@ -892,13 +909,13 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin if (ifs.fail()) log_error("Can't open ABC output file `%s'.\n", buffer.c_str()); - bool builtin_lib = liberty_file.empty() && script_file.empty() && lut_costs.empty(); + bool builtin_lib = liberty_file.empty(); RTLIL::Design *mapped_design = new RTLIL::Design; - parse_blif(mapped_design, ifs, builtin_lib ? "\\DFF" : "\\_dff_"); + parse_blif(mapped_design, ifs, builtin_lib ? "\\DFF" : "\\_dff_", false, sop_mode); ifs.close(); - log_header("Re-integrating ABC results.\n"); + log_header(design, "Re-integrating ABC results.\n"); RTLIL::Module *mapped_mod = mapped_design->modules_["\\netlist"]; if (mapped_mod == NULL) log_error("ABC output file does not contain a module `netlist'.\n"); @@ -910,10 +927,10 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin } std::map<std::string, int> cell_stats; - if (builtin_lib) + for (auto c : mapped_mod->cells()) { - for (auto &it : mapped_mod->cells_) { - RTLIL::Cell *c = it.second; + if (builtin_lib) + { cell_stats[RTLIL::unescape_id(c->type)]++; if (c->type == "\\ZERO" || c->type == "\\ONE") { RTLIL::SigSig conn; @@ -1052,60 +1069,57 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin design->select(module, cell); continue; } - log_abort(); } - } - else - { - for (auto &it : mapped_mod->cells_) - { - RTLIL::Cell *c = it.second; - cell_stats[RTLIL::unescape_id(c->type)]++; - if (c->type == "\\_const0_" || c->type == "\\_const1_") { - RTLIL::SigSig conn; - conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->connections().begin()->second.as_wire()->name)]); - conn.second = RTLIL::SigSpec(c->type == "\\_const0_" ? 0 : 1, 1); - module->connect(conn); - continue; - } - if (c->type == "\\_dff_") { - log_assert(clk_sig.size() == 1); - RTLIL::Cell *cell; - if (en_sig.size() == 0) { - cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_"); - } else { - log_assert(en_sig.size() == 1); - cell = module->addCell(remap_name(c->name), stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N')); - cell->setPort("\\E", en_sig); - } - if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx; - cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)])); - cell->setPort("\\Q", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Q").as_wire()->name)])); - cell->setPort("\\C", clk_sig); - design->select(module, cell); - continue; - } - if (c->type == "$lut" && GetSize(c->getPort("\\A")) == 1 && c->getParam("\\LUT").as_int() == 2) { - SigSpec my_a = module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]; - SigSpec my_y = module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]; - module->connect(my_y, my_a); - continue; + + cell_stats[RTLIL::unescape_id(c->type)]++; + + if (c->type == "\\_const0_" || c->type == "\\_const1_") { + RTLIL::SigSig conn; + conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->connections().begin()->second.as_wire()->name)]); + conn.second = RTLIL::SigSpec(c->type == "\\_const0_" ? 0 : 1, 1); + module->connect(conn); + continue; + } + + if (c->type == "\\_dff_") { + log_assert(clk_sig.size() == 1); + RTLIL::Cell *cell; + if (en_sig.size() == 0) { + cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_"); + } else { + log_assert(en_sig.size() == 1); + cell = module->addCell(remap_name(c->name), stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N')); + cell->setPort("\\E", en_sig); } - RTLIL::Cell *cell = module->addCell(remap_name(c->name), c->type); if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx; - cell->parameters = c->parameters; - for (auto &conn : c->connections()) { - RTLIL::SigSpec newsig; - for (auto &c : conn.second.chunks()) { - if (c.width == 0) - continue; - log_assert(c.width == 1); - newsig.append(module->wires_[remap_name(c.wire->name)]); - } - cell->setPort(conn.first, newsig); - } + cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)])); + cell->setPort("\\Q", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Q").as_wire()->name)])); + cell->setPort("\\C", clk_sig); design->select(module, cell); + continue; + } + + if (c->type == "$lut" && GetSize(c->getPort("\\A")) == 1 && c->getParam("\\LUT").as_int() == 2) { + SigSpec my_a = module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]; + SigSpec my_y = module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]; + module->connect(my_y, my_a); + continue; + } + + RTLIL::Cell *cell = module->addCell(remap_name(c->name), c->type); + if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx; + cell->parameters = c->parameters; + for (auto &conn : c->connections()) { + RTLIL::SigSpec newsig; + for (auto &c : conn.second.chunks()) { + if (c.width == 0) + continue; + log_assert(c.width == 1); + newsig.append(module->wires_[remap_name(c.wire->name)]); + } + cell->setPort(conn.first, newsig); } + design->select(module, cell); } for (auto conn : mapped_mod->connections()) { @@ -1167,7 +1181,11 @@ struct AbcPass : public Pass { log("library to a target architecture.\n"); log("\n"); log(" -exe <command>\n"); - log(" use the specified command name instead of \"yosys-abc\" to execute ABC.\n"); +#ifdef ABCEXTERNAL + log(" use the specified command instead of \"" ABCEXTERNAL "\" to execute ABC.\n"); +#else + log(" use the specified command instead of \"<yosys-bindir>/yosys-abc\" to execute ABC.\n"); +#endif log(" This can e.g. be used to call a specific version of ABC or a wrapper.\n"); log("\n"); log(" -script <file>\n"); @@ -1186,9 +1204,15 @@ struct AbcPass : public Pass { log(" for -liberty with -constr:\n"); log("%s\n", fold_abc_cmd(ABC_COMMAND_CTR).c_str()); log("\n"); - log(" for -lut:\n"); + log(" for -lut/-luts (only one LUT size):\n"); + log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT "; lutpack").c_str()); + log("\n"); + log(" for -lut/-luts (different LUT sizes):\n"); log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT).c_str()); log("\n"); + log(" for -sop:\n"); + log("%s\n", fold_abc_cmd(ABC_COMMAND_SOP).c_str()); + log("\n"); log(" otherwise:\n"); log("%s\n", fold_abc_cmd(ABC_COMMAND_DFL).c_str()); log("\n"); @@ -1202,9 +1226,12 @@ struct AbcPass : public Pass { log(" for -liberty with -constr:\n"); log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_CTR).c_str()); log("\n"); - log(" for -lut:\n"); + log(" for -lut/-luts:\n"); log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_LUT).c_str()); log("\n"); + log(" for -sop:\n"); + log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_SOP).c_str()); + log("\n"); log(" otherwise:\n"); log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_DFL).c_str()); log("\n"); @@ -1227,6 +1254,14 @@ struct AbcPass : public Pass { log(" set delay target. the string {D} in the default scripts above is\n"); log(" replaced by this option when used, and an empty string otherwise.\n"); log("\n"); + log(" -I <num>\n"); + log(" maximum number of SOP inputs.\n"); + log(" (replaces {I} in the default scripts above)\n"); + log("\n"); + log(" -P <num>\n"); + log(" maximum number of SOP products.\n"); + log(" (replaces {P} in the default scripts above)\n"); + log("\n"); log(" -lut <width>\n"); log(" generate netlist using luts of (max) the specified width.\n"); log("\n"); @@ -1240,6 +1275,9 @@ struct AbcPass : public Pass { log(" generate netlist using luts. Use the specified costs for luts with 1,\n"); log(" 2, 3, .. inputs.\n"); log("\n"); + log(" -sop\n"); + log(" map to sum-of-product cells and inverters\n"); + log("\n"); // log(" -mux4, -mux8, -mux16\n"); // log(" try to extract 4-input, 8-input, and/or 16-input muxes\n"); // log(" (ignored when used with -liberty or -lut)\n"); @@ -1286,13 +1324,18 @@ struct AbcPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing ABC pass (technology mapping using ABC).\n"); + log_header(design, "Executing ABC pass (technology mapping using ABC).\n"); log_push(); +#ifdef ABCEXTERNAL + std::string exe_file = ABCEXTERNAL; +#else std::string exe_file = proc_self_dirname() + "yosys-abc"; - std::string script_file, liberty_file, constr_file, clk_str, delay_target; +#endif + std::string script_file, liberty_file, constr_file, clk_str; + std::string delay_target, sop_inputs, sop_products; bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true; - bool show_tempdir = false; + bool show_tempdir = false, sop_mode = false; vector<int> lut_costs; markgroups = false; @@ -1302,9 +1345,11 @@ struct AbcPass : public Pass { enabled_gates.clear(); #ifdef _WIN32 +#ifndef ABCEXTERNAL if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\yosys-abc.exe")) exe_file = proc_self_dirname() + "..\\yosys-abc"; #endif +#endif size_t argidx; char pwd [PATH_MAX]; @@ -1340,6 +1385,14 @@ struct AbcPass : public Pass { delay_target = "-D " + args[++argidx]; continue; } + if (arg == "-I" && argidx+1 < args.size()) { + sop_inputs = "-I " + args[++argidx]; + continue; + } + if (arg == "-P" && argidx+1 < args.size()) { + sop_products = "-P " + args[++argidx]; + continue; + } if (arg == "-lut" && argidx+1 < args.size()) { string arg = args[++argidx]; size_t pos = arg.find_first_of(':'); @@ -1374,6 +1427,10 @@ struct AbcPass : public Pass { } continue; } + if (arg == "-sop") { + sop_mode = true; + continue; + } if (arg == "-mux4") { map_mux4 = true; continue; @@ -1447,7 +1504,8 @@ struct AbcPass : public Pass { if (mod->processes.size() > 0) log("Skipping module %s as it contains processes.\n", log_id(mod)); else if (!dff_mode || !clk_str.empty()) - abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff, delay_target, fast_mode, mod->selected_cells(), show_tempdir); + abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff, + delay_target, sop_inputs, sop_products, fast_mode, mod->selected_cells(), show_tempdir, sop_mode); else { assign_map.set(mod); @@ -1580,7 +1638,7 @@ struct AbcPass : public Pass { assigned_cells_reverse[cell] = key; } - log_header("Summary of detected clock domains:\n"); + log_header(design, "Summary of detected clock domains:\n"); for (auto &it : assigned_cells) log(" %d cells in clk=%s%s, en=%s%s\n", GetSize(it.second), std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)), @@ -1591,8 +1649,8 @@ struct AbcPass : public Pass { clk_sig = assign_map(std::get<1>(it.first)); en_polarity = std::get<2>(it.first); en_sig = assign_map(std::get<3>(it.first)); - abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, - !clk_sig.empty(), "$", keepff, delay_target, fast_mode, it.second, show_tempdir); + abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$", + keepff, delay_target, sop_inputs, sop_products, fast_mode, it.second, show_tempdir, sop_mode); assign_map.set(mod); } } diff --git a/passes/techmap/aigmap.cc b/passes/techmap/aigmap.cc index db1c731e..b9ac7ade 100644 --- a/passes/techmap/aigmap.cc +++ b/passes/techmap/aigmap.cc @@ -41,7 +41,7 @@ struct AigmapPass : public Pass { { bool nand_mode = false; - log_header("Executing AIGMAP pass (map logic to AIG).\n"); + log_header(design, "Executing AIGMAP pass (map logic to AIG).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc index 3c7ff4b9..9f6dd02d 100644 --- a/passes/techmap/alumacc.cc +++ b/passes/techmap/alumacc.cc @@ -544,7 +544,7 @@ struct AlumaccPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing ALUMACC pass (create $alu and $macc cells).\n"); + log_header(design, "Executing ALUMACC pass (create $alu and $macc cells).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { diff --git a/passes/techmap/attrmap.cc b/passes/techmap/attrmap.cc new file mode 100644 index 00000000..f715b63e --- /dev/null +++ b/passes/techmap/attrmap.cc @@ -0,0 +1,250 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +Const make_value(string &value) +{ + if (GetSize(value) >= 2 && value.front() == '"' && value.back() == '"') + return Const(value.substr(1, GetSize(value)-2)); + + SigSpec sig; + SigSpec::parse(sig, nullptr, value); + return sig.as_const(); +} + +bool match_name(string &name, IdString &id, bool ignore_case=false) +{ + string str1 = RTLIL::escape_id(name); + string str2 = id.str(); + + if (ignore_case) + return !strcasecmp(str1.c_str(), str2.c_str()); + + return str1 == str2; +} + +bool match_value(string &value, Const &val, bool ignore_case=false) +{ + if (ignore_case && ((val.flags & RTLIL::CONST_FLAG_STRING) != 0) && GetSize(value) && value.front() == '"' && value.back() == '"') { + string str1 = value.substr(1, GetSize(value)-2); + string str2 = val.decode_string(); + return !strcasecmp(str1.c_str(), str2.c_str()); + } + + return make_value(value) == val; +} + +struct AttrmapAction { + virtual ~AttrmapAction() { } + virtual bool apply(IdString &id, Const &val) = 0; +}; + +struct AttrmapTocase : AttrmapAction { + string name; + virtual bool apply(IdString &id, Const&) { + if (match_name(name, id, true)) + id = RTLIL::escape_id(name); + return true; + } +}; + +struct AttrmapRename : AttrmapAction { + string old_name, new_name; + virtual bool apply(IdString &id, Const&) { + if (match_name(old_name, id)) + id = RTLIL::escape_id(new_name); + return true; + } +}; + +struct AttrmapMap : AttrmapAction { + bool imap; + string old_name, new_name; + string old_value, new_value; + virtual bool apply(IdString &id, Const &val) { + if (match_name(old_name, id) && match_value(old_value, val, true)) { + id = RTLIL::escape_id(new_name); + val = make_value(new_value); + } + return true; + } +}; + +struct AttrmapRemove : AttrmapAction { + string name, value; + virtual bool apply(IdString &id, Const &val) { + return !(match_name(name, id) && match_value(value, val)); + } +}; + +void attrmap_apply(string objname, vector<std::unique_ptr<AttrmapAction>> &actions, dict<RTLIL::IdString, RTLIL::Const> &attributes) +{ + dict<RTLIL::IdString, RTLIL::Const> new_attributes; + + for (auto attr : attributes) + { + auto new_attr = attr; + for (auto &action : actions) + if (!action->apply(new_attr.first, new_attr.second)) + goto delete_this_attr; + + if (new_attr != attr) + log("Changed attribute on %s: %s=%s -> %s=%s\n", objname.c_str(), + log_id(attr.first), log_const(attr.second), log_id(new_attr.first), log_const(new_attr.second)); + + new_attributes[new_attr.first] = new_attr.second; + + if (0) + delete_this_attr: + log("Removed attribute on %s: %s=%s\n", objname.c_str(), log_id(attr.first), log_const(attr.second)); + } + + attributes.swap(new_attributes); +} + +struct AttrmapPass : public Pass { + AttrmapPass() : Pass("attrmap", "renaming attributes") { } + virtual void help() + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" attrmap [options] [selection]\n"); + log("\n"); + log("This command renames attributes and/or mapps key/value pairs to\n"); + log("other key/value pairs.\n"); + log("\n"); + log(" -tocase <name>\n"); + log(" Match attribute names case-insensitively and set it to the specified\n"); + log(" name.\n"); + log("\n"); + log(" -rename <old_name> <new_name>\n"); + log(" Rename attributes as specified\n"); + log("\n"); + log(" -map <old_name>=<old_value> <new_name>=<new_value>\n"); + log(" Map key/value pairs as indicated.\n"); + log("\n"); + log(" -imap <old_name>=<old_value> <new_name>=<new_value>\n"); + log(" Like -map, but use case-insensitive match for <old_value> when\n"); + log(" it is a string value.\n"); + log("\n"); + log(" -remove <name>=<value>\n"); + log(" Remove attributes matching this pattern.\n"); + log("\n"); + log(" -modattr\n"); + log(" Operate on module attributes instead of attributes on wires and cells.\n"); + log("\n"); + log("For example, mapping Xilinx-style \"keep\" attributes to Yosys-style:\n"); + log("\n"); + log(" attrmap -tocase keep -imap keep=\"true\" keep=1 \\\n"); + log(" -imap keep=\"false\" keep=0 -remove keep=0\n"); + log("\n"); + } + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + { + log_header(design, "Executing ATTRMAP pass (move or copy attributes).\n"); + + bool modattr_mode = false; + vector<std::unique_ptr<AttrmapAction>> actions; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + std::string arg = args[argidx]; + if (arg == "-tocase" && argidx+1 < args.size()) { + auto action = new AttrmapTocase; + action->name = args[++argidx]; + actions.push_back(std::unique_ptr<AttrmapAction>(action)); + continue; + } + if (arg == "-rename" && argidx+2 < args.size()) { + auto action = new AttrmapRename; + action->old_name = args[++argidx]; + action->new_name = args[++argidx]; + actions.push_back(std::unique_ptr<AttrmapAction>(action)); + continue; + } + if ((arg == "-map" || arg == "-imap") && argidx+2 < args.size()) { + string arg1 = args[++argidx]; + string arg2 = args[++argidx]; + string val1, val2; + size_t p = arg1.find("="); + if (p != string::npos) { + val1 = arg1.substr(p+1); + arg1 = arg1.substr(0, p); + } + p = arg2.find("="); + if (p != string::npos) { + val2 = arg2.substr(p+1); + arg2 = arg2.substr(0, p); + } + auto action = new AttrmapMap; + action->imap = (arg == "-map"); + action->old_name = arg1; + action->new_name = arg2; + action->old_value = val1; + action->new_value = val2; + actions.push_back(std::unique_ptr<AttrmapAction>(action)); + continue; + } + if (arg == "-remove" && argidx+1 < args.size()) { + string arg1 = args[++argidx], val1; + size_t p = arg1.find("="); + if (p != string::npos) { + val1 = arg1.substr(p+1); + arg1 = arg1.substr(0, p); + } + auto action = new AttrmapRemove; + action->name = arg1; + action->value = val1; + actions.push_back(std::unique_ptr<AttrmapAction>(action)); + continue; + } + if (arg == "-modattr") { + modattr_mode = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + if (modattr_mode) + { + for (auto module : design->selected_whole_modules()) + attrmap_apply(stringf("%s", log_id(module)), actions, module->attributes); + } + else + { + for (auto module : design->selected_modules()) + { + for (auto wire : module->selected_wires()) + attrmap_apply(stringf("%s.%s", log_id(module), log_id(wire)), actions, wire->attributes); + + for (auto cell : module->selected_cells()) + attrmap_apply(stringf("%s.%s", log_id(module), log_id(cell)), actions, cell->attributes); + } + } + } +} AttrmapPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/attrmvcp.cc b/passes/techmap/attrmvcp.cc new file mode 100644 index 00000000..50eaf61d --- /dev/null +++ b/passes/techmap/attrmvcp.cc @@ -0,0 +1,139 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct AttrmvcpPass : public Pass { + AttrmvcpPass() : Pass("attrmvcp", "move or copy attributes from wires to driving cells") { } + virtual void help() + { + log("\n"); + log(" attrmvcp [options] [selection]\n"); + log("\n"); + log("Move or copy attributes on wires to the cells driving them.\n"); + log("\n"); + log(" -copy\n"); + log(" By default, attributes are moved. This will only add\n"); + log(" the attribute to the cell, without removing it from\n"); + log(" the wire.\n"); + log("\n"); + log(" -purge\n"); + log(" If no selected cell consumes the attribute, then it is\n"); + log(" left on the wire by default. This option will cause the\n"); + log(" attribute to be removed from the wire, even if no selected\n"); + log(" cell takes it.\n"); + log("\n"); + log(" -driven\n"); + log(" By default, attriburtes are moved to the cell driving the\n"); + log(" wire. With this option set it will be moved to the cell\n"); + log(" driven by the wire instead.\n"); + log("\n"); + log(" -attr <attrname>\n"); + log(" Move or copy this attribute. This option can be used\n"); + log(" multiple times.\n"); + log("\n"); + } + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + { + log_header(design, "Executing ATTRMVCP pass (move or copy attributes).\n"); + + bool copy_mode = false; + bool driven_mode = false; + bool purge_mode = false; + pool<IdString> attrnames; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + std::string arg = args[argidx]; + if (arg == "-copy") { + copy_mode = true; + continue; + } + if (arg == "-driven") { + driven_mode = true; + continue; + } + if (arg == "-purge") { + purge_mode = true; + continue; + } + if (arg == "-attr" && argidx+1 < args.size()) { + attrnames.insert(RTLIL::escape_id(args[++argidx])); + continue; + } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + { + dict<SigBit, pool<Cell*>> net2cells; + SigMap sigmap(module); + + for (auto cell : module->selected_cells()) + for (auto &conn : cell->connections()) + if (driven_mode) { + if (cell->input(conn.first)) + for (auto bit : sigmap(conn.second)) + net2cells[bit].insert(cell); + } else { + if (cell->output(conn.first)) + for (auto bit : sigmap(conn.second)) + net2cells[bit].insert(cell); + } + + for (auto wire : module->selected_wires()) + { + dict<IdString, Const> new_attributes; + + for (auto attr : wire->attributes) + { + bool did_something = false; + + if (!attrnames.count(attr.first)) { + new_attributes[attr.first] = attr.second; + continue; + } + + for (auto bit : sigmap(wire)) + if (net2cells.count(bit)) + for (auto cell : net2cells.at(bit)) { + log("Moving attribute %s=%s from %s.%s to %s.%s.\n", log_id(attr.first), log_const(attr.second), + log_id(module), log_id(wire), log_id(module), log_id(cell)); + cell->attributes[attr.first] = attr.second; + did_something = true; + } + + if (!purge_mode && !did_something) + new_attributes[attr.first] = attr.second; + } + + if (!copy_mode) + wire->attributes.swap(new_attributes); + } + } + } +} AttrmvcpPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/deminout.cc b/passes/techmap/deminout.cc new file mode 100644 index 00000000..ed4e4576 --- /dev/null +++ b/passes/techmap/deminout.cc @@ -0,0 +1,116 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct DeminoutPass : public Pass { + DeminoutPass() : Pass("deminout", "demote inout ports to input or output") { } + virtual void help() + { + log("\n"); + log(" deminout [options] [selection]\n"); + log("\n"); + log("\"Demote\" inout ports to input or output ports, if possible.\n"); + log("\n"); + } + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + { + log_header(design, "Executing DEMINOUT pass (demote inout ports to input or output).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-bits") { + // flag_bits = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + bool keep_running = true; + + while (keep_running) + { + keep_running = false; + + for (auto module : design->selected_modules()) + { + SigMap sigmap(module); + pool<SigBit> bits_written, bits_used, bits_inout; + dict<SigBit, int> bits_numports; + + for (auto wire : module->wires()) + if (wire->port_id) + for (auto bit : sigmap(wire)) + bits_numports[bit]++; + + for (auto cell : module->cells()) + for (auto &conn : cell->connections()) + { + bool cellport_out = cell->output(conn.first) || !cell->known(); + bool cellport_in = cell->input(conn.first) || !cell->known(); + + if (cellport_out && cellport_in) + for (auto bit : sigmap(conn.second)) + bits_inout.insert(bit); + + if (cellport_out) + for (auto bit : sigmap(conn.second)) + bits_written.insert(bit); + + if (cellport_in) + for (auto bit : sigmap(conn.second)) + bits_used.insert(bit); + } + + for (auto wire : module->selected_wires()) + if (wire->port_input && wire->port_output) + { + bool new_input = false; + bool new_output = false; + + for (auto bit : sigmap(wire)) + { + if (bits_numports[bit] > 1 || bits_inout.count(bit)) + new_input = true, new_output = true; + + if (bits_written.count(bit)) + new_output = true; + else if (bits_used.count(bit)) + new_input = true; + } + + if (new_input != new_output) { + log("Demoting inout port %s.%s to %s.\n", log_id(module), log_id(wire), new_input ? "input" : "output"); + wire->port_input = new_input; + wire->port_output = new_output; + keep_running = true; + } + } + } + } + } +} DeminoutPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/dff2dffe.cc b/passes/techmap/dff2dffe.cc index 51bfaade..1b8920bb 100644 --- a/passes/techmap/dff2dffe.cc +++ b/passes/techmap/dff2dffe.cc @@ -285,7 +285,7 @@ struct Dff2dffePass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing DFF2DFFE pass (transform $dff to $dffe where applicable).\n"); + log_header(design, "Executing DFF2DFFE pass (transform $dff to $dffe where applicable).\n"); bool unmap_mode = false; dict<IdString, IdString> direct_dict; diff --git a/passes/techmap/dffinit.cc b/passes/techmap/dffinit.cc index e0273f43..d737b342 100644 --- a/passes/techmap/dffinit.cc +++ b/passes/techmap/dffinit.cc @@ -41,7 +41,7 @@ struct DffinitPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing DFFINIT pass (set INIT param on FF cells).\n"); + log_header(design, "Executing DFFINIT pass (set INIT param on FF cells).\n"); dict<IdString, dict<IdString, IdString>> ff_types; diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc index 4d7a1a70..c8104fb7 100644 --- a/passes/techmap/dfflibmap.cc +++ b/passes/techmap/dfflibmap.cc @@ -108,6 +108,7 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool LibertyAst *best_cell = NULL; std::map<std::string, char> best_cell_ports; int best_cell_pins = 0; + bool best_cell_noninv = false; double best_cell_area = 0; if (ast->id != "library") @@ -155,6 +156,7 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool int num_pins = 0; bool found_output = false; + bool found_noninv_output = false; for (auto pin : cell->children) { if (pin->id != "pin" || pin->args.size() != 1) @@ -175,10 +177,14 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool value.erase(pos, 1); if (value == ff->args[0]) { this_cell_ports[pin->args[0]] = cell_next_pol ? 'Q' : 'q'; + if (cell_next_pol) + found_noninv_output = true; found_output = true; } else if (value == ff->args[1]) { this_cell_ports[pin->args[0]] = cell_next_pol ? 'q' : 'Q'; + if (!cell_next_pol) + found_noninv_output = true; found_output = true; } } @@ -187,7 +193,7 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool this_cell_ports[pin->args[0]] = 0; } - if (!found_output || (best_cell != NULL && num_pins > best_cell_pins)) + if (!found_output || (best_cell != NULL && (num_pins > best_cell_pins || (best_cell_noninv && !found_noninv_output)))) continue; if (best_cell != NULL && num_pins == best_cell_pins && area > best_cell_area) @@ -196,12 +202,14 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool best_cell = cell; best_cell_pins = num_pins; best_cell_area = area; + best_cell_noninv = found_noninv_output; best_cell_ports.swap(this_cell_ports); continue_cell_loop:; } if (best_cell != NULL) { - log(" cell %s (pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell->args[0].c_str(), best_cell_pins, best_cell_area, cell_type.c_str()); + log(" cell %s (%sinv, pins=%d, area=%.2f) is a direct match for cell type %s.\n", + best_cell->args[0].c_str(), best_cell_noninv ? "non" : "", best_cell_pins, best_cell_area, cell_type.c_str()); if (prepare_mode) { cell_mappings[cell_type].cell_name = cell_type; cell_mappings[cell_type].ports["C"] = 'C'; @@ -221,6 +229,7 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo LibertyAst *best_cell = NULL; std::map<std::string, char> best_cell_ports; int best_cell_pins = 0; + bool best_cell_noninv = false; double best_cell_area = 0; if (ast->id != "library") @@ -260,6 +269,7 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo int num_pins = 0; bool found_output = false; + bool found_noninv_output = false; for (auto pin : cell->children) { if (pin->id != "pin" || pin->args.size() != 1) @@ -280,10 +290,14 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo value.erase(pos, 1); if (value == ff->args[0]) { this_cell_ports[pin->args[0]] = cell_next_pol ? 'Q' : 'q'; + if (cell_next_pol) + found_noninv_output = true; found_output = true; } else if (value == ff->args[1]) { this_cell_ports[pin->args[0]] = cell_next_pol ? 'q' : 'Q'; + if (!cell_next_pol) + found_noninv_output = true; found_output = true; } } @@ -292,7 +306,7 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo this_cell_ports[pin->args[0]] = 0; } - if (!found_output || (best_cell != NULL && num_pins > best_cell_pins)) + if (!found_output || (best_cell != NULL && (num_pins > best_cell_pins || (best_cell_noninv && !found_noninv_output)))) continue; if (best_cell != NULL && num_pins == best_cell_pins && area > best_cell_area) @@ -301,12 +315,14 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo best_cell = cell; best_cell_pins = num_pins; best_cell_area = area; + best_cell_noninv = found_noninv_output; best_cell_ports.swap(this_cell_ports); continue_cell_loop:; } if (best_cell != NULL) { - log(" cell %s (pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell->args[0].c_str(), best_cell_pins, best_cell_area, cell_type.c_str()); + log(" cell %s (%sinv, pins=%d, area=%.2f) is a direct match for cell type %s.\n", + best_cell->args[0].c_str(), best_cell_noninv ? "non" : "", best_cell_pins, best_cell_area, cell_type.c_str()); if (prepare_mode) { cell_mappings[cell_type].cell_name = cell_type; cell_mappings[cell_type].ports["C"] = 'C'; @@ -531,7 +547,7 @@ struct DfflibmapPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n"); + log_header(design, "Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n"); std::string liberty_file; bool prepare_mode = false; diff --git a/passes/techmap/dffsr2dff.cc b/passes/techmap/dffsr2dff.cc index 8dcbb4ed..0d4d5362 100644 --- a/passes/techmap/dffsr2dff.cc +++ b/passes/techmap/dffsr2dff.cc @@ -188,7 +188,7 @@ struct Dffsr2dffPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing DFFSR2DFF pass (mapping DFFSR cells to simpler FFs).\n"); + log_header(design, "Executing DFFSR2DFF pass (mapping DFFSR cells to simpler FFs).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) diff --git a/passes/techmap/extract.cc b/passes/techmap/extract.cc index fc73177c..71e29c60 100644 --- a/passes/techmap/extract.cc +++ b/passes/techmap/extract.cc @@ -442,7 +442,7 @@ struct ExtractPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing EXTRACT pass (map subcircuits to cells).\n"); + log_header(design, "Executing EXTRACT pass (map subcircuits to cells).\n"); log_push(); SubCircuitSolver solver; @@ -627,7 +627,7 @@ struct ExtractPass : public Pass { std::map<std::string, RTLIL::Module*> needle_map, haystack_map; std::vector<RTLIL::Module*> needle_list; - log_header("Creating graphs for SubCircuit library.\n"); + log_header(design, "Creating graphs for SubCircuit library.\n"); if (!mine_mode) for (auto &mod_it : map->modules_) { @@ -654,7 +654,7 @@ struct ExtractPass : public Pass { if (!mine_mode) { std::vector<SubCircuit::Solver::Result> results; - log_header("Running solver from SubCircuit library.\n"); + log_header(design, "Running solver from SubCircuit library.\n"); std::sort(needle_list.begin(), needle_list.end(), compareSortNeedleList); @@ -667,7 +667,7 @@ struct ExtractPass : public Pass { if (results.size() > 0) { - log_header("Substitute SubCircuits with cells.\n"); + log_header(design, "Substitute SubCircuits with cells.\n"); for (int i = 0; i < int(results.size()); i++) { auto &result = results[i]; @@ -688,7 +688,7 @@ struct ExtractPass : public Pass { { std::vector<SubCircuit::Solver::MineResult> results; - log_header("Running miner from SubCircuit library.\n"); + log_header(design, "Running miner from SubCircuit library.\n"); solver.mine(results, mine_cells_min, mine_cells_max, mine_min_freq, mine_limit_mod); map = new RTLIL::Design; diff --git a/passes/techmap/hilomap.cc b/passes/techmap/hilomap.cc index a0bd2f9a..82cecac2 100644 --- a/passes/techmap/hilomap.cc +++ b/passes/techmap/hilomap.cc @@ -76,7 +76,7 @@ struct HilomapPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing HILOMAP pass (mapping to constant drivers).\n"); + log_header(design, "Executing HILOMAP pass (mapping to constant drivers).\n"); hicell_celltype = std::string(); hicell_portname = std::string(); diff --git a/passes/techmap/insbuf.cc b/passes/techmap/insbuf.cc new file mode 100644 index 00000000..aa81468d --- /dev/null +++ b/passes/techmap/insbuf.cc @@ -0,0 +1,94 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct InsbufPass : public Pass { + InsbufPass() : Pass("insbuf", "insert buffer cells for connected wires") { } + virtual void help() + { + log("\n"); + log(" insbuf [options] [selection]\n"); + log("\n"); + log("Insert buffer cells into the design for directly connected wires.\n"); + log("\n"); + log(" -buf <celltype> <in-portname> <out-portname>\n"); + log(" Use the given cell type instead of $_BUF_. (Notice that the next\n"); + log(" call to \"clean\" will remove all $_BUF_ in the design.)\n"); + log("\n"); + } + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + { + log_header(design, "Executing INSBUF pass (insert buffer cells for connected wires).\n"); + + std::string celltype = "$_BUF_", in_portname = "\\A", out_portname = "\\Y"; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + std::string arg = args[argidx]; + if (arg == "-buf" && argidx+3 < args.size()) { + celltype = args[++argidx]; + in_portname = args[++argidx]; + out_portname = args[++argidx]; + continue; + } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + { + std::vector<RTLIL::SigSig> new_connections; + + for (auto &conn : module->connections()) + { + RTLIL::SigSig new_conn; + + for (int i = 0; i < GetSize(conn.first); i++) + { + SigBit lhs = conn.first[i]; + SigBit rhs = conn.second[i]; + + if (lhs.wire && !design->selected(module, lhs.wire)) { + new_conn.first.append(lhs); + new_conn.second.append(rhs); + continue; + } + + Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(celltype)); + cell->setPort(RTLIL::escape_id(in_portname), rhs); + cell->setPort(RTLIL::escape_id(out_portname), lhs); + log("Added %s.%s: %s -> %s\n", log_id(module), log_id(cell), log_signal(rhs), log_signal(lhs)); + } + + if (GetSize(new_conn.first)) + new_connections.push_back(new_conn); + } + + module->new_connections(new_connections); + } + } +} InsbufPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc index 9dab40ca..4acbf7c0 100644 --- a/passes/techmap/iopadmap.cc +++ b/passes/techmap/iopadmap.cc @@ -17,9 +17,8 @@ * */ -#include "kernel/register.h" -#include "kernel/rtlil.h" -#include "kernel/log.h" +#include "kernel/yosys.h" +#include "kernel/sigtools.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -48,12 +47,23 @@ struct IopadmapPass : public Pass { log(" Map module input ports to the given cell type with the\n"); log(" given output port name. if a 2nd portname is given, the\n"); log(" signal is passed through the pad call, using the 2nd\n"); - log(" portname as input.\n"); + log(" portname as the port facing the module port.\n"); log("\n"); log(" -outpad <celltype> <portname>[:<portname>]\n"); log(" -inoutpad <celltype> <portname>[:<portname>]\n"); log(" Similar to -inpad, but for output and inout ports.\n"); log("\n"); + log(" -toutpad <celltype> <portname>:<portname>[:<portname>]\n"); + log(" Merges $_TBUF_ cells into the output pad cell. This takes precedence\n"); + log(" over the other -outpad cell. The first portname is the enable input\n"); + log(" of the tristate driver.\n"); + log("\n"); + log(" -tinoutpad <celltype> <portname>:<portname>:<portname>[:<portname>]\n"); + log(" Merges $_TBUF_ cells into the inout pad cell. This takes precedence\n"); + log(" over the other -inoutpad cell. The first portname is the enable input\n"); + log(" of the tristate driver and the 2nd portname is the internal output\n"); + log(" buffering the external signal.\n"); + log("\n"); log(" -widthparam <param_name>\n"); log(" Use the specified parameter name to set the port width.\n"); log("\n"); @@ -65,14 +75,18 @@ struct IopadmapPass : public Pass { log(" are wider. (the default behavior is to create word-wide\n"); log(" buffers using -widthparam to set the word size on the cell.)\n"); log("\n"); + log("Tristate PADS (-toutpad, -tinoutpad) always operate in -bits mode.\n"); + log("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing IOPADMAP pass (mapping inputs/outputs to IO-PAD cells).\n"); + log_header(design, "Executing IOPADMAP pass (mapping inputs/outputs to IO-PAD cells).\n"); std::string inpad_celltype, inpad_portname, inpad_portname2; std::string outpad_celltype, outpad_portname, outpad_portname2; std::string inoutpad_celltype, inoutpad_portname, inoutpad_portname2; + std::string toutpad_celltype, toutpad_portname, toutpad_portname2, toutpad_portname3; + std::string tinoutpad_celltype, tinoutpad_portname, tinoutpad_portname2, tinoutpad_portname3, tinoutpad_portname4; std::string widthparam, nameparam; bool flag_bits = false; @@ -98,6 +112,21 @@ struct IopadmapPass : public Pass { split_portname_pair(inoutpad_portname, inoutpad_portname2); continue; } + if (arg == "-toutpad" && argidx+2 < args.size()) { + toutpad_celltype = args[++argidx]; + toutpad_portname = args[++argidx]; + split_portname_pair(toutpad_portname, toutpad_portname2); + split_portname_pair(toutpad_portname2, toutpad_portname3); + continue; + } + if (arg == "-tinoutpad" && argidx+2 < args.size()) { + tinoutpad_celltype = args[++argidx]; + tinoutpad_portname = args[++argidx]; + split_portname_pair(tinoutpad_portname, tinoutpad_portname2); + split_portname_pair(tinoutpad_portname2, tinoutpad_portname3); + split_portname_pair(tinoutpad_portname3, tinoutpad_portname4); + continue; + } if (arg == "-widthparam" && argidx+1 < args.size()) { widthparam = args[++argidx]; continue; @@ -116,12 +145,132 @@ struct IopadmapPass : public Pass { for (auto module : design->selected_modules()) { + dict<IdString, pool<int>> skip_wires; + + if (!toutpad_celltype.empty() || !tinoutpad_celltype.empty()) + { + SigMap sigmap(module); + dict<SigBit, pair<IdString, pool<IdString>>> tbuf_bits; + + for (auto cell : module->cells()) + if (cell->type == "$_TBUF_") { + SigBit bit = sigmap(cell->getPort("\\Y").as_bit()); + tbuf_bits[bit].first = cell->name; + } + + for (auto cell : module->cells()) + for (auto port : cell->connections()) + for (auto bit : sigmap(port.second)) + if (tbuf_bits.count(bit)) + tbuf_bits.at(bit).second.insert(cell->name); + + for (auto wire : module->selected_wires()) + { + if (!wire->port_output) + continue; + + for (int i = 0; i < GetSize(wire); i++) + { + SigBit wire_bit(wire, i); + SigBit mapped_wire_bit = sigmap(wire_bit); + + if (tbuf_bits.count(mapped_wire_bit) == 0) + continue; + + auto &tbuf_cache = tbuf_bits.at(mapped_wire_bit); + Cell *tbuf_cell = module->cell(tbuf_cache.first); + + if (tbuf_cell == nullptr) + continue; + + SigBit en_sig = tbuf_cell->getPort("\\E").as_bit(); + SigBit data_sig = tbuf_cell->getPort("\\A").as_bit(); + + if (wire->port_input && !tinoutpad_celltype.empty()) + { + log("Mapping port %s.%s[%d] using %s.\n", log_id(module), log_id(wire), i, tinoutpad_celltype.c_str()); + + Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(tinoutpad_celltype)); + Wire *owire = module->addWire(NEW_ID); + + cell->setPort(RTLIL::escape_id(tinoutpad_portname), en_sig); + cell->setPort(RTLIL::escape_id(tinoutpad_portname2), owire); + cell->setPort(RTLIL::escape_id(tinoutpad_portname3), data_sig); + cell->setPort(RTLIL::escape_id(tinoutpad_portname4), wire_bit); + cell->attributes["\\keep"] = RTLIL::Const(1); + + for (auto cn : tbuf_cache.second) { + auto c = module->cell(cn); + if (c == nullptr) + continue; + for (auto port : c->connections()) { + SigSpec sig = port.second; + bool newsig = false; + for (auto &bit : sig) + if (sigmap(bit) == mapped_wire_bit) { + bit = owire; + newsig = true; + } + if (newsig) + c->setPort(port.first, sig); + } + } + + + module->remove(tbuf_cell); + skip_wires[wire->name].insert(i); + continue; + } + + if (!wire->port_input && !toutpad_celltype.empty()) + { + log("Mapping port %s.%s[%d] using %s.\n", log_id(module), log_id(wire), i, toutpad_celltype.c_str()); + + Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(toutpad_celltype)); + + cell->setPort(RTLIL::escape_id(toutpad_portname), en_sig); + cell->setPort(RTLIL::escape_id(toutpad_portname2), data_sig); + cell->setPort(RTLIL::escape_id(toutpad_portname3), wire_bit); + cell->attributes["\\keep"] = RTLIL::Const(1); + + for (auto cn : tbuf_cache.second) { + auto c = module->cell(cn); + if (c == nullptr) + continue; + for (auto port : c->connections()) { + SigSpec sig = port.second; + bool newsig = false; + for (auto &bit : sig) + if (sigmap(bit) == mapped_wire_bit) { + bit = data_sig; + newsig = true; + } + if (newsig) + c->setPort(port.first, sig); + } + } + + module->remove(tbuf_cell); + skip_wires[wire->name].insert(i); + continue; + } + } + } + } + for (auto wire : module->selected_wires()) { if (!wire->port_id) continue; std::string celltype, portname, portname2; + pool<int> skip_bit_indices; + + if (skip_wires.count(wire->name)) { + if (!flag_bits) + continue; + skip_bit_indices = skip_wires.at(wire->name); + } if (wire->port_input && !wire->port_output) { if (inpad_celltype.empty()) { @@ -163,12 +312,21 @@ struct IopadmapPass : public Pass { if (!portname2.empty()) { new_wire = module->addWire(NEW_ID, wire); module->swap_names(new_wire, wire); + wire->attributes.clear(); } if (flag_bits) { for (int i = 0; i < wire->width; i++) { + if (skip_bit_indices.count(i)) { + if (wire->port_output) + module->connect(SigSpec(new_wire, i), SigSpec(wire, i)); + else + module->connect(SigSpec(wire, i), SigSpec(new_wire, i)); + continue; + } + RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(celltype)); cell->setPort(RTLIL::escape_id(portname), RTLIL::SigSpec(wire, i)); if (!portname2.empty()) diff --git a/passes/techmap/lut2mux.cc b/passes/techmap/lut2mux.cc index fe55e499..2bb0bd8b 100644 --- a/passes/techmap/lut2mux.cc +++ b/passes/techmap/lut2mux.cc @@ -67,7 +67,7 @@ struct Lut2muxPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing LUT2MUX pass (mapping to constant drivers).\n"); + log_header(design, "Executing LUT2MUX pass (convert $lut to $_MUX_).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) diff --git a/passes/techmap/maccmap.cc b/passes/techmap/maccmap.cc index d5b8fe80..32569d07 100644 --- a/passes/techmap/maccmap.cc +++ b/passes/techmap/maccmap.cc @@ -379,7 +379,7 @@ struct MaccmapPass : public Pass { { bool unmap_mode = false; - log_header("Executing MACCMAP pass (map $macc cells).\n"); + log_header(design, "Executing MACCMAP pass (map $macc cells).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { diff --git a/passes/techmap/muxcover.cc b/passes/techmap/muxcover.cc index 514c3365..1dc64958 100644 --- a/passes/techmap/muxcover.cc +++ b/passes/techmap/muxcover.cc @@ -581,7 +581,7 @@ struct MuxcoverPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing MUXCOVER pass (mapping to wider MUXes).\n"); + log_header(design, "Executing MUXCOVER pass (mapping to wider MUXes).\n"); bool use_mux4 = false; bool use_mux8 = false; diff --git a/passes/techmap/nlutmap.cc b/passes/techmap/nlutmap.cc index 7ece4005..6fcdf82b 100644 --- a/passes/techmap/nlutmap.cc +++ b/passes/techmap/nlutmap.cc @@ -26,6 +26,7 @@ PRIVATE_NAMESPACE_BEGIN struct NlutmapConfig { vector<int> luts; + bool assert_mode = false; }; struct NlutmapWorker @@ -64,7 +65,7 @@ struct NlutmapWorker { vector<int> available_luts = config.luts; - while (!available_luts.empty()) + while (GetSize(available_luts) > 1) { int n_luts = available_luts.back(); int lut_size = GetSize(available_luts); @@ -84,7 +85,7 @@ struct NlutmapWorker if (cell->type != "$lut" || mapped_cells.count(cell)) continue; - if (GetSize(cell->getPort("\\A")) == lut_size) + if (GetSize(cell->getPort("\\A")) == lut_size || lut_size == 2) candidate_ratings[cell] = 0; for (auto &conn : cell->connections()) @@ -116,6 +117,12 @@ struct NlutmapWorker available_luts.back() += n_luts; } + if (config.assert_mode) { + for (auto cell : module->cells()) + if (cell->type == "$lut" && !mapped_cells.count(cell)) + log_error("Insufficient number of LUTs to map all logic cells!\n"); + } + run_abc(0); } }; @@ -135,6 +142,9 @@ struct NlutmapPass : public Pass { log(" The number of LUTs with 1, 2, 3, ... inputs that are\n"); log(" available in the target architecture.\n"); log("\n"); + log(" -assert\n"); + log(" Create an error if not all logic can be mapped\n"); + log("\n"); log("Excess logic that does not fit into the specified LUTs is mapped back\n"); log("to generic logic gates ($_AND_, etc.).\n"); log("\n"); @@ -143,7 +153,7 @@ struct NlutmapPass : public Pass { { NlutmapConfig config; - log_header("Executing NLUTMAP pass (mapping to constant drivers).\n"); + log_header(design, "Executing NLUTMAP pass (mapping to constant drivers).\n"); log_push(); size_t argidx; @@ -156,6 +166,10 @@ struct NlutmapPass : public Pass { config.luts.push_back(atoi(token.c_str())); continue; } + if (args[argidx] == "-assert") { + config.assert_mode = true; + continue; + } break; } extra_args(args, argidx, design); diff --git a/passes/techmap/pmuxtree.cc b/passes/techmap/pmuxtree.cc index 3c12bfd0..c626dbcc 100644 --- a/passes/techmap/pmuxtree.cc +++ b/passes/techmap/pmuxtree.cc @@ -78,7 +78,7 @@ struct PmuxtreePass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing PMUXTREE pass.\n"); + log_header(design, "Executing PMUXTREE pass.\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc new file mode 100644 index 00000000..6936b499 --- /dev/null +++ b/passes/techmap/shregmap.cc @@ -0,0 +1,584 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct ShregmapTech +{ + virtual ~ShregmapTech() { } + virtual bool analyze(vector<int> &taps) = 0; + virtual bool fixup(Cell *cell, dict<int, SigBit> &taps) = 0; +}; + +struct ShregmapOptions +{ + int minlen, maxlen; + int keep_before, keep_after; + bool zinit, init, params, ffe; + dict<IdString, pair<IdString, IdString>> ffcells; + ShregmapTech *tech; + + ShregmapOptions() + { + minlen = 2; + maxlen = 0; + keep_before = 0; + keep_after = 0; + zinit = false; + init = false; + params = false; + ffe = false; + tech = nullptr; + } +}; + +struct ShregmapTechGreenpak4 : ShregmapTech +{ + bool analyze(vector<int> &taps) + { + if (GetSize(taps) > 2 && taps[0] == 0 && taps[2] < 17) { + taps.clear(); + return true; + } + + if (GetSize(taps) > 2) + return false; + + if (taps.back() > 16) return false; + + return true; + } + + bool fixup(Cell *cell, dict<int, SigBit> &taps) + { + auto D = cell->getPort("\\D"); + auto C = cell->getPort("\\C"); + + auto newcell = cell->module->addCell(NEW_ID, "\\GP_SHREG"); + newcell->setPort("\\nRST", State::S1); + newcell->setPort("\\CLK", C); + newcell->setPort("\\IN", D); + + int i = 0; + for (auto tap : taps) { + newcell->setPort(i ? "\\OUTB" : "\\OUTA", tap.second); + newcell->setParam(i ? "\\OUTB_TAP" : "\\OUTA_TAP", tap.first + 1); + i++; + } + + cell->setParam("\\OUTA_INVERT", 0); + return false; + } +}; + +struct ShregmapWorker +{ + Module *module; + SigMap sigmap; + + const ShregmapOptions &opts; + int dff_count, shreg_count; + + pool<Cell*> remove_cells; + pool<SigBit> remove_init; + + dict<SigBit, bool> sigbit_init; + dict<SigBit, Cell*> sigbit_chain_next; + dict<SigBit, Cell*> sigbit_chain_prev; + pool<SigBit> sigbit_with_non_chain_users; + pool<Cell*> chain_start_cells; + + void make_sigbit_chain_next_prev() + { + for (auto wire : module->wires()) + { + if (wire->port_output || wire->get_bool_attribute("\\keep")) { + for (auto bit : sigmap(wire)) + sigbit_with_non_chain_users.insert(bit); + } + + if (wire->attributes.count("\\init")) { + SigSpec initsig = sigmap(wire); + Const initval = wire->attributes.at("\\init"); + for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++) + if (initval[i] == State::S0 && !opts.zinit) + sigbit_init[initsig[i]] = false; + else if (initval[i] == State::S1) + sigbit_init[initsig[i]] = true; + } + } + + for (auto cell : module->cells()) + { + if (opts.ffcells.count(cell->type) && !cell->get_bool_attribute("\\keep")) + { + IdString d_port = opts.ffcells.at(cell->type).first; + IdString q_port = opts.ffcells.at(cell->type).second; + + SigBit d_bit = sigmap(cell->getPort(d_port).as_bit()); + SigBit q_bit = sigmap(cell->getPort(q_port).as_bit()); + + if (opts.init || sigbit_init.count(q_bit) == 0) + { + if (sigbit_chain_next.count(d_bit)) { + sigbit_with_non_chain_users.insert(d_bit); + } else + sigbit_chain_next[d_bit] = cell; + + sigbit_chain_prev[q_bit] = cell; + continue; + } + } + + for (auto conn : cell->connections()) + if (cell->input(conn.first)) + for (auto bit : sigmap(conn.second)) + sigbit_with_non_chain_users.insert(bit); + } + } + + void find_chain_start_cells() + { + for (auto it : sigbit_chain_next) + { + if (opts.tech == nullptr && sigbit_with_non_chain_users.count(it.first)) + goto start_cell; + + if (sigbit_chain_prev.count(it.first) != 0) + { + Cell *c1 = sigbit_chain_prev.at(it.first); + Cell *c2 = it.second; + + if (c1->type != c2->type) + goto start_cell; + + if (c1->parameters != c2->parameters) + goto start_cell; + + IdString d_port = opts.ffcells.at(c1->type).first; + IdString q_port = opts.ffcells.at(c1->type).second; + + auto c1_conn = c1->connections(); + auto c2_conn = c1->connections(); + + c1_conn.erase(d_port); + c1_conn.erase(q_port); + + c2_conn.erase(d_port); + c2_conn.erase(q_port); + + if (c1_conn != c2_conn) + goto start_cell; + + continue; + } + + start_cell: + chain_start_cells.insert(it.second); + } + } + + vector<Cell*> create_chain(Cell *start_cell) + { + vector<Cell*> chain; + + Cell *c = start_cell; + while (c != nullptr) + { + chain.push_back(c); + + IdString q_port = opts.ffcells.at(c->type).second; + SigBit q_bit = sigmap(c->getPort(q_port).as_bit()); + + if (sigbit_chain_next.count(q_bit) == 0) + break; + + c = sigbit_chain_next.at(q_bit); + if (chain_start_cells.count(c) != 0) + break; + } + + return chain; + } + + void process_chain(vector<Cell*> &chain) + { + if (GetSize(chain) < opts.keep_before + opts.minlen + opts.keep_after) + return; + + int cursor = opts.keep_before; + while (cursor < GetSize(chain) - opts.keep_after) + { + int depth = GetSize(chain) - opts.keep_after - cursor; + + if (opts.maxlen > 0) + depth = std::min(opts.maxlen, depth); + + Cell *first_cell = chain[cursor]; + IdString q_port = opts.ffcells.at(first_cell->type).second; + dict<int, SigBit> taps_dict; + + if (opts.tech) + { + vector<SigBit> qbits; + vector<int> taps; + + for (int i = 0; i < depth; i++) + { + Cell *cell = chain[cursor+i]; + auto qbit = sigmap(cell->getPort(q_port)); + qbits.push_back(qbit); + + if (sigbit_with_non_chain_users.count(qbit)) + taps.push_back(i); + } + + while (depth > 0) + { + if (taps.empty() || taps.back() < depth-1) + taps.push_back(depth-1); + + if (opts.tech->analyze(taps)) + break; + + taps.pop_back(); + depth--; + } + + depth = 0; + for (auto tap : taps) { + taps_dict[tap] = qbits.at(tap); + log_assert(depth < tap+1); + depth = tap+1; + } + } + + if (depth < 2) { + cursor++; + continue; + } + + Cell *last_cell = chain[cursor+depth-1]; + + log("Converting %s.%s ... %s.%s to a shift register with depth %d.\n", + log_id(module), log_id(first_cell), log_id(module), log_id(last_cell), depth); + + dff_count += depth; + shreg_count += 1; + + string shreg_cell_type_str = "$__SHREG"; + if (opts.params) { + shreg_cell_type_str += "_"; + } else { + if (first_cell->type[1] != '_') + shreg_cell_type_str += "_"; + shreg_cell_type_str += first_cell->type.substr(1); + } + + if (opts.init) { + vector<State> initval; + for (int i = depth-1; i >= 0; i--) { + SigBit bit = sigmap(chain[cursor+i]->getPort(q_port).as_bit()); + if (sigbit_init.count(bit) == 0) + initval.push_back(State::Sx); + else if (sigbit_init.at(bit)) + initval.push_back(State::S1); + else + initval.push_back(State::S0); + remove_init.insert(bit); + } + first_cell->setParam("\\INIT", initval); + } + + if (opts.zinit) + for (int i = depth-1; i >= 0; i--) { + SigBit bit = sigmap(chain[cursor+i]->getPort(q_port).as_bit()); + remove_init.insert(bit); + } + + if (opts.params) + { + int param_clkpol = -1; + int param_enpol = 2; + + if (first_cell->type == "$_DFF_N_") param_clkpol = 0; + if (first_cell->type == "$_DFF_P_") param_clkpol = 1; + + if (first_cell->type == "$_DFFE_NN_") param_clkpol = 0, param_enpol = 0; + if (first_cell->type == "$_DFFE_NP_") param_clkpol = 0, param_enpol = 1; + if (first_cell->type == "$_DFFE_PN_") param_clkpol = 1, param_enpol = 0; + if (first_cell->type == "$_DFFE_PP_") param_clkpol = 1, param_enpol = 1; + + log_assert(param_clkpol >= 0); + first_cell->setParam("\\CLKPOL", param_clkpol); + if (opts.ffe) first_cell->setParam("\\ENPOL", param_enpol); + } + + first_cell->type = shreg_cell_type_str; + first_cell->setPort(q_port, last_cell->getPort(q_port)); + first_cell->setParam("\\DEPTH", depth); + + if (opts.tech != nullptr && !opts.tech->fixup(first_cell, taps_dict)) + remove_cells.insert(first_cell); + + for (int i = 1; i < depth; i++) + remove_cells.insert(chain[cursor+i]); + cursor += depth; + } + } + + void cleanup() + { + for (auto cell : remove_cells) + module->remove(cell); + + for (auto wire : module->wires()) + { + if (wire->attributes.count("\\init") == 0) + continue; + + SigSpec initsig = sigmap(wire); + Const &initval = wire->attributes.at("\\init"); + + for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++) + if (remove_init.count(initsig[i])) + initval[i] = State::Sx; + + if (SigSpec(initval).is_fully_undef()) + wire->attributes.erase("\\init"); + } + + remove_cells.clear(); + sigbit_chain_next.clear(); + sigbit_chain_prev.clear(); + chain_start_cells.clear(); + } + + ShregmapWorker(Module *module, const ShregmapOptions &opts) : + module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0) + { + make_sigbit_chain_next_prev(); + find_chain_start_cells(); + + for (auto c : chain_start_cells) { + vector<Cell*> chain = create_chain(c); + process_chain(chain); + } + + cleanup(); + } +}; + +struct ShregmapPass : public Pass { + ShregmapPass() : Pass("shregmap", "map shift registers") { } + virtual void help() + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" shregmap [options] [selection]\n"); + log("\n"); + log("This pass converts chains of $_DFF_[NP]_ gates to target specific shift register\n"); + log("primitives. The generated shift register will be of type $__SHREG_DFF_[NP]_ and\n"); + log("will use the same interface as the original $_DFF_*_ cells. The cell parameter\n"); + log("'DEPTH' will contain the depth of the shift register. Use a target-specific\n"); + log("'techmap' map file to convert those cells to the actual target cells.\n"); + log("\n"); + log(" -minlen N\n"); + log(" minimum length of shift register (default = 2)\n"); + log(" (this is the length after -keep_before and -keep_after)\n"); + log("\n"); + log(" -maxlen N\n"); + log(" maximum length of shift register (default = no limit)\n"); + log(" larger chains will be mapped to multiple shift register instances\n"); + log("\n"); + log(" -keep_before N\n"); + log(" number of DFFs to keep before the shift register (default = 0)\n"); + log("\n"); + log(" -keep_after N\n"); + log(" number of DFFs to keep after the shift register (default = 0)\n"); + log("\n"); + log(" -clkpol pos|neg|any\n"); + log(" limit match to only positive or negative edge clocks. (default = any)\n"); + log("\n"); + log(" -enpol pos|neg|none|any_or_none|any\n"); + log(" limit match to FFs with the specified enable polarity. (default = none)\n"); + log("\n"); + log(" -match <cell_type>[:<d_port_name>:<q_port_name>]\n"); + log(" match the specified cells instead of $_DFF_N_ and $_DFF_P_. If\n"); + log(" ':<d_port_name>:<q_port_name>' is omitted then 'D' and 'Q' is used\n"); + log(" by default. E.g. the option '-clkpol pos' is just an alias for\n"); + log(" '-match $_DFF_P_', which is an alias for '-match $_DFF_P_:D:Q'.\n"); + log("\n"); + log(" -params\n"); + log(" instead of encoding the clock and enable polarity in the cell name by\n"); + log(" deriving from the original cell name, simply name all generated cells\n"); + log(" $__SHREG_ and use CLKPOL and ENPOL parameters. An ENPOL value of 2 is\n"); + log(" used to denote cells without enable input. The ENPOL parameter is\n"); + log(" omitted when '-enpol none' (or no -enpol option) is passed.\n"); + log("\n"); + log(" -zinit\n"); + log(" assume the shift register is automatically zero-initialized, so it\n"); + log(" becomes legal to merge zero initialized FFs into the shift register.\n"); + log("\n"); + log(" -init\n"); + log(" map initialized registers to the shift reg, add an INIT parameter to\n"); + log(" generated cells with the initialization value. (first bit to shift out\n"); + log(" in LSB position)\n"); + log("\n"); + log(" -tech greenpak4\n"); + log(" map to greenpak4 shift registers.\n"); + log("\n"); + } + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + { + ShregmapOptions opts; + string clkpol, enpol; + + log_header(design, "Executing SHREGMAP pass (map shift registers).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-clkpol" && argidx+1 < args.size()) { + clkpol = args[++argidx]; + continue; + } + if (args[argidx] == "-enpol" && argidx+1 < args.size()) { + enpol = args[++argidx]; + continue; + } + if (args[argidx] == "-match" && argidx+1 < args.size()) { + vector<string> match_args = split_tokens(args[++argidx], ":"); + if (GetSize(match_args) < 2) + match_args.push_back("D"); + if (GetSize(match_args) < 3) + match_args.push_back("Q"); + IdString id_cell_type(RTLIL::escape_id(match_args[0])); + IdString id_d_port_name(RTLIL::escape_id(match_args[1])); + IdString id_q_port_name(RTLIL::escape_id(match_args[2])); + opts.ffcells[id_cell_type] = make_pair(id_d_port_name, id_q_port_name); + continue; + } + if (args[argidx] == "-minlen" && argidx+1 < args.size()) { + opts.minlen = atoi(args[++argidx].c_str()); + continue; + } + if (args[argidx] == "-maxlen" && argidx+1 < args.size()) { + opts.maxlen = atoi(args[++argidx].c_str()); + continue; + } + if (args[argidx] == "-keep_before" && argidx+1 < args.size()) { + opts.keep_before = atoi(args[++argidx].c_str()); + continue; + } + if (args[argidx] == "-keep_after" && argidx+1 < args.size()) { + opts.keep_after = atoi(args[++argidx].c_str()); + continue; + } + if (args[argidx] == "-tech" && argidx+1 < args.size() && opts.tech == nullptr) { + string tech = args[++argidx]; + if (tech == "greenpak4") { + clkpol = "pos"; + opts.zinit = true; + opts.tech = new ShregmapTechGreenpak4; + } else { + argidx--; + break; + } + continue; + } + if (args[argidx] == "-zinit") { + opts.zinit = true; + continue; + } + if (args[argidx] == "-init") { + opts.init = true; + continue; + } + if (args[argidx] == "-params") { + opts.params = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + if (opts.zinit && opts.init) + log_cmd_error("Options -zinit and -init are exclusive!\n"); + + if (opts.ffcells.empty()) + { + bool clk_pos = clkpol == "" || clkpol == "pos" || clkpol == "any"; + bool clk_neg = clkpol == "" || clkpol == "neg" || clkpol == "any"; + + bool en_none = enpol == "" || enpol == "none" || enpol == "any_or_none"; + bool en_pos = enpol == "pos" || enpol == "any" || enpol == "any_or_none"; + bool en_neg = enpol == "neg" || enpol == "any" || enpol == "any_or_none"; + + if (clk_pos && en_none) + opts.ffcells["$_DFF_P_"] = make_pair(IdString("\\D"), IdString("\\Q")); + if (clk_neg && en_none) + opts.ffcells["$_DFF_N_"] = make_pair(IdString("\\D"), IdString("\\Q")); + + if (clk_pos && en_pos) + opts.ffcells["$_DFFE_PP_"] = make_pair(IdString("\\D"), IdString("\\Q")); + if (clk_pos && en_neg) + opts.ffcells["$_DFFE_PN_"] = make_pair(IdString("\\D"), IdString("\\Q")); + + if (clk_neg && en_pos) + opts.ffcells["$_DFFE_NP_"] = make_pair(IdString("\\D"), IdString("\\Q")); + if (clk_neg && en_neg) + opts.ffcells["$_DFFE_NN_"] = make_pair(IdString("\\D"), IdString("\\Q")); + + if (en_pos || en_neg) + opts.ffe = true; + } + else + { + if (!clkpol.empty()) + log_cmd_error("Options -clkpol and -match are exclusive!\n"); + if (!enpol.empty()) + log_cmd_error("Options -enpol and -match are exclusive!\n"); + if (opts.params) + log_cmd_error("Options -params and -match are exclusive!\n"); + } + + int dff_count = 0; + int shreg_count = 0; + + for (auto module : design->selected_modules()) { + ShregmapWorker worker(module, opts); + dff_count += worker.dff_count; + shreg_count += worker.shreg_count; + } + + log("Converted %d dff cells into %d shift registers.\n", dff_count, shreg_count); + + if (opts.tech != nullptr) { + delete opts.tech; + opts.tech = nullptr; + } + } +} ShregmapPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc index f6ac3964..0fb64734 100644 --- a/passes/techmap/simplemap.cc +++ b/passes/techmap/simplemap.cc @@ -321,6 +321,36 @@ void simplemap_lut(RTLIL::Module *module, RTLIL::Cell *cell) module->connect(cell->getPort("\\Y"), lut_data); } +void simplemap_sop(RTLIL::Module *module, RTLIL::Cell *cell) +{ + SigSpec ctrl = cell->getPort("\\A"); + SigSpec table = cell->getParam("\\TABLE"); + + int width = cell->getParam("\\WIDTH").as_int(); + int depth = cell->getParam("\\DEPTH").as_int(); + table.extend_u0(2 * width * depth); + + SigSpec products; + + for (int i = 0; i < depth; i++) { + SigSpec in, pat; + for (int j = 0; j < width; j++) { + if (table[2*i*width + 2*j + 0] == State::S1) { + in.append(ctrl[j]); + pat.append(State::S0); + } + if (table[2*i*width + 2*j + 1] == State::S1) { + in.append(ctrl[j]); + pat.append(State::S1); + } + } + + products.append(GetSize(in) > 0 ? module->Eq(NEW_ID, in, pat) : State::S1); + } + + module->connect(cell->getPort("\\Y"), module->ReduceOr(NEW_ID, products)); +} + void simplemap_slice(RTLIL::Module *module, RTLIL::Cell *cell) { int offset = cell->parameters.at("\\OFFSET").as_int(); @@ -498,6 +528,7 @@ void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTL mappers["$mux"] = simplemap_mux; mappers["$tribuf"] = simplemap_tribuf; mappers["$lut"] = simplemap_lut; + mappers["$sop"] = simplemap_sop; mappers["$slice"] = simplemap_slice; mappers["$concat"] = simplemap_concat; mappers["$sr"] = simplemap_sr; @@ -543,7 +574,7 @@ struct SimplemapPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing SIMPLEMAP pass (map simple cells to gate primitives).\n"); + log_header(design, "Executing SIMPLEMAP pass (map simple cells to gate primitives).\n"); extra_args(args, 1, design); std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> mappers; diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 5334ebfa..b2cc492b 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -234,8 +234,10 @@ struct TechmapWorker tpl_written_bits.insert(bit); SigMap port_signal_map; + SigSig port_signal_assign; - for (auto &it : cell->connections()) { + for (auto &it : cell->connections()) + { RTLIL::IdString portname = it.first; if (positional_ports.count(portname) > 0) portname = positional_ports.at(portname); @@ -244,16 +246,22 @@ struct TechmapWorker log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", portname.c_str(), cell->name.c_str(), tpl->name.c_str()); continue; } + RTLIL::Wire *w = tpl->wires_.at(portname); - RTLIL::SigSig c; + RTLIL::SigSig c, extra_connect; + if (w->port_output && !w->port_input) { c.first = it.second; c.second = RTLIL::SigSpec(w); apply_prefix(cell->name.str(), c.second, module); + extra_connect.first = c.second; + extra_connect.second = c.first; } else if (!w->port_output && w->port_input) { c.first = RTLIL::SigSpec(w); c.second = it.second; apply_prefix(cell->name.str(), c.first, module); + extra_connect.first = c.first; + extra_connect.second = c.second; } else { SigSpec sig_tpl = w, sig_tpl_pf = w, sig_mod = it.second; apply_prefix(cell->name.str(), sig_tpl_pf, module); @@ -266,28 +274,48 @@ struct TechmapWorker c.second.append(sig_mod[i]); } } + extra_connect.first = sig_tpl_pf; + extra_connect.second = sig_mod; } + if (c.second.size() > c.first.size()) c.second.remove(c.first.size(), c.second.size() - c.first.size()); + if (c.second.size() < c.first.size()) c.second.append(RTLIL::SigSpec(RTLIL::State::S0, c.first.size() - c.second.size())); + log_assert(c.first.size() == c.second.size()); - if (flatten_mode) { + + if (flatten_mode) + { // more conservative approach: // connect internal and external wires + if (sigmaps.count(module) == 0) sigmaps[module].set(module); + if (sigmaps.at(module)(c.first).has_const()) log_error("Mismatch in directionality for cell port %s.%s.%s: %s <= %s\n", log_id(module), log_id(cell), log_id(it.first), log_signal(c.first), log_signal(c.second)); + module->connect(c); - } else { + } + else + { // approach that yields nicer outputs: // replace internal wires that are connected to external wires + if (w->port_output) port_signal_map.add(c.second, c.first); else port_signal_map.add(c.first, c.second); + + for (auto &attr : w->attributes) { + if (attr.first == "\\src") + continue; + module->connect(extra_connect); + break; + } } } @@ -611,7 +639,7 @@ struct TechmapWorker if (techmap_cache.count(key) > 0) { tpl = techmap_cache[key]; } else { - if (cell->parameters.size() != 0) { + if (parameters.size() != 0) { derived_name = tpl->derive(map, dict<RTLIL::IdString, RTLIL::Const>(parameters.begin(), parameters.end())); tpl = map->module(derived_name); log_continue = true; @@ -779,7 +807,7 @@ struct TechmapWorker if (recursive_mode) { if (log_continue) { - log_header("Continuing TECHMAP pass.\n"); + log_header(design, "Continuing TECHMAP pass.\n"); log_continue = false; } while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { } @@ -790,7 +818,7 @@ struct TechmapWorker continue; if (log_continue) { - log_header("Continuing TECHMAP pass.\n"); + log_header(design, "Continuing TECHMAP pass.\n"); log_continue = false; } @@ -833,7 +861,7 @@ struct TechmapWorker } if (log_continue) { - log_header("Continuing TECHMAP pass.\n"); + log_header(design, "Continuing TECHMAP pass.\n"); log_continue = false; } @@ -976,7 +1004,7 @@ struct TechmapPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing TECHMAP pass (map to technology primitives).\n"); + log_header(design, "Executing TECHMAP pass (map to technology primitives).\n"); log_push(); TechmapWorker worker; @@ -1108,7 +1136,7 @@ struct FlattenPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing FLATTEN pass (flatten design).\n"); + log_header(design, "Executing FLATTEN pass (flatten design).\n"); log_push(); extra_args(args, 1, design); diff --git a/passes/techmap/tribuf.cc b/passes/techmap/tribuf.cc index d0564b4e..03629082 100644 --- a/passes/techmap/tribuf.cc +++ b/passes/techmap/tribuf.cc @@ -160,7 +160,7 @@ struct TribufPass : public Pass { { TribufConfig config; - log_header("Executing TRIBUF pass.\n"); + log_header(design, "Executing TRIBUF pass.\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { diff --git a/passes/tests/test_autotb.cc b/passes/tests/test_autotb.cc index bb516fca..cb31056f 100644 --- a/passes/tests/test_autotb.cc +++ b/passes/tests/test_autotb.cc @@ -71,16 +71,21 @@ static std::string idy(std::string str1, std::string str2 = std::string(), std:: return id(str1); } -static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter) +static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter, int seed) { + f << stringf("`ifndef outfile\n"); + f << stringf("\t`define outfile \"/dev/stdout\"\n"); + f << stringf("`endif\n"); + f << stringf("module testbench;\n\n"); - f << stringf("integer i;\n\n"); + f << stringf("integer i;\n"); + f << stringf("integer file;\n\n"); f << stringf("reg [31:0] xorshift128_x = 123456789;\n"); f << stringf("reg [31:0] xorshift128_y = 362436069;\n"); f << stringf("reg [31:0] xorshift128_z = 521288629;\n"); - f << stringf("reg [31:0] xorshift128_w = %u; // <-- seed value\n", int(time(NULL))); + f << stringf("reg [31:0] xorshift128_w = %u; // <-- seed value\n", seed ? seed : int(time(NULL))); f << stringf("reg [31:0] xorshift128_t;\n\n"); f << stringf("task xorshift128;\n"); f << stringf("begin\n"); @@ -150,6 +155,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter) f << stringf("\t%s <= #%d 0;\n", it->first.c_str(), ++delay_counter*2); for (auto it = signal_clk.begin(); it != signal_clk.end(); ++it) f << stringf("\t%s <= #%d 0;\n", it->first.c_str(), ++delay_counter*2); + f << stringf("\t#%d;\n", ((2*delay_counter+99)/100)*100); for (auto it = signal_clk.begin(); it != signal_clk.end(); ++it) { f << stringf("\t#100; %s <= 1;\n", it->first.c_str()); f << stringf("\t#100; %s <= 0;\n", it->first.c_str()); @@ -157,6 +163,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter) delay_counter = 0; for (auto it = signal_in.begin(); it != signal_in.end(); ++it) f << stringf("\t%s <= #%d ~0;\n", it->first.c_str(), ++delay_counter*2); + f << stringf("\t#%d;\n", ((2*delay_counter+99)/100)*100); for (auto it = signal_clk.begin(); it != signal_clk.end(); ++it) { f << stringf("\t#100; %s <= 1;\n", it->first.c_str()); f << stringf("\t#100; %s <= 0;\n", it->first.c_str()); @@ -167,6 +174,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter) continue; f << stringf("\t%s <= #%d 'b%s;\n", it->first.c_str(), ++delay_counter*2, signal_const[it->first].c_str()); } + f << stringf("\t#%d;\n", ((2*delay_counter+99)/100)*100); f << stringf("end\n"); f << stringf("endtask\n\n"); @@ -179,6 +187,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter) f << stringf("\txorshift128;\n"); f << stringf("\t%s <= #%d { xorshift128_x, xorshift128_y, xorshift128_z, xorshift128_w };\n", it->first.c_str(), ++delay_counter*2); } + f << stringf("\t#%d;\n", ((2*delay_counter+99)/100)*100); f << stringf("end\n"); f << stringf("endtask\n\n"); @@ -206,61 +215,70 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter) f << stringf("task %s;\n", idy(mod->name.str(), "print_status").c_str()); f << stringf("begin\n"); - f << stringf("\t$display(\"#OUT# %%b %%b %%b %%t %%d\", {"); + f << stringf("\t$fdisplay(file, \"#OUT# %%b %%b %%b %%t %%d\", {"); if (signal_in.size()) for (auto it = signal_in.begin(); it != signal_in.end(); it++) { f << stringf("%s %s", it == signal_in.begin() ? "" : ",", it->first.c_str()); int len = it->second; + header2 += ", \""; if (len > 1) header2 += "/", len--; while (len > 1) header2 += "-", len--; if (len > 0) header2 += shorthand, len--; + header2 += "\""; header1.push_back(" " + it->first); - header1.back()[0] = shorthand++; + header1.back()[0] = shorthand; + shorthand = shorthand == 'Z' ? 'A' : shorthand+1; } else { f << stringf(" 1'bx"); - header2 += "#"; + header2 += ", \"#\""; } f << stringf(" }, {"); - header2 += " "; + header2 += ", \" \""; if (signal_clk.size()) { for (auto it = signal_clk.begin(); it != signal_clk.end(); it++) { f << stringf("%s %s", it == signal_clk.begin() ? "" : ",", it->first.c_str()); int len = it->second; + header2 += ", \""; if (len > 1) header2 += "/", len--; while (len > 1) header2 += "-", len--; if (len > 0) header2 += shorthand, len--; + header2 += "\""; header1.push_back(" " + it->first); - header1.back()[0] = shorthand++; + header1.back()[0] = shorthand; + shorthand = shorthand == 'Z' ? 'A' : shorthand+1; } } else { f << stringf(" 1'bx"); - header2 += "#"; + header2 += ", \"#\""; } f << stringf(" }, {"); - header2 += " "; + header2 += ", \" \""; if (signal_out.size()) { for (auto it = signal_out.begin(); it != signal_out.end(); it++) { f << stringf("%s %s", it == signal_out.begin() ? "" : ",", it->first.c_str()); int len = it->second; + header2 += ", \""; if (len > 1) header2 += "/", len--; while (len > 1) header2 += "-", len--; if (len > 0) header2 += shorthand, len--; + header2 += "\""; header1.push_back(" " + it->first); - header1.back()[0] = shorthand++; + header1.back()[0] = shorthand; + shorthand = shorthand == 'Z' ? 'A' : shorthand+1; } } else { f << stringf(" 1'bx"); - header2 += "#"; + header2 += ", \"#\""; } f << stringf(" }, $time, i);\n"); f << stringf("end\n"); @@ -268,17 +286,17 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter) f << stringf("task %s;\n", idy(mod->name.str(), "print_header").c_str()); f << stringf("begin\n"); - f << stringf("\t$display(\"#OUT#\");\n"); + f << stringf("\t$fdisplay(file, \"#OUT#\");\n"); for (auto &hdr : header1) - f << stringf("\t$display(\"#OUT# %s\");\n", hdr.c_str()); - f << stringf("\t$display(\"#OUT#\");\n"); - f << stringf("\t$display(\"#OUT# %s\");\n", header2.c_str()); + f << stringf("\t$fdisplay(file, \"#OUT# %s\");\n", hdr.c_str()); + f << stringf("\t$fdisplay(file, \"#OUT#\");\n"); + f << stringf("\t$fdisplay(file, {\"#OUT# \"%s});\n", header2.c_str()); f << stringf("end\n"); f << stringf("endtask\n\n"); f << stringf("task %s;\n", idy(mod->name.str(), "test").c_str()); f << stringf("begin\n"); - f << stringf("\t$display(\"#OUT#\\n#OUT# ==== %s ====\");\n", idy(mod->name.str()).c_str()); + f << stringf("\t$fdisplay(file, \"#OUT#\\n#OUT# ==== %s ====\");\n", idy(mod->name.str()).c_str()); f << stringf("\t%s;\n", idy(mod->name.str(), "reset").c_str()); f << stringf("\tfor (i=0; i<%d; i=i+1) begin\n", num_iter); f << stringf("\t\tif (i %% 20 == 0) %s;\n", idy(mod->name.str(), "print_header").c_str()); @@ -293,9 +311,11 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter) f << stringf("initial begin\n"); f << stringf("\t// $dumpfile(\"testbench.vcd\");\n"); f << stringf("\t// $dumpvars(0, testbench);\n"); + f << stringf("\tfile = $fopen(`outfile);\n"); for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) if (!it->second->get_bool_attribute("\\gentb_skip")) f << stringf("\t%s;\n", idy(it->first.str(), "test").c_str()); + f << stringf("\t$fclose(file);\n"); f << stringf("\t$finish;\n"); f << stringf("end\n\n"); @@ -332,8 +352,9 @@ struct TestAutotbBackend : public Backend { virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) { int num_iter = 1000; + int seed = 0; - log_header("Executing TEST_AUTOTB backend (auto-generate pseudo-random test benches).\n"); + log_header(design, "Executing TEST_AUTOTB backend (auto-generate pseudo-random test benches).\n"); int argidx; for (argidx = 1; argidx < GetSize(args); argidx++) @@ -342,11 +363,15 @@ struct TestAutotbBackend : public Backend { num_iter = atoi(args[++argidx].c_str()); continue; } + if (args[argidx] == "-seed" && argidx+1 < GetSize(args)) { + seed = atoi(args[++argidx].c_str()); + continue; + } break; } extra_args(f, filename, args, argidx); - autotest(*f, design, num_iter); + autotest(*f, design, num_iter, seed); } } TestAutotbBackend; diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc index a8fcac9b..049c2053 100644 --- a/passes/tests/test_cell.cc +++ b/passes/tests/test_cell.cc @@ -21,6 +21,7 @@ #include "kernel/yosys.h" #include "kernel/satgen.h" #include "kernel/consteval.h" +#include "kernel/celledges.h" #include "kernel/macc.h" #include <algorithm> @@ -42,6 +43,32 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type, RTLIL::Cell *cell = module->addCell("\\UUT", cell_type); RTLIL::Wire *wire; + if (cell_type == "$mux" || cell_type == "$pmux") + { + int width = 1 + xorshift32(8); + int swidth = cell_type == "$mux" ? 1 : 1 + xorshift32(8); + + wire = module->addWire("\\A"); + wire->width = width; + wire->port_input = true; + cell->setPort("\\A", wire); + + wire = module->addWire("\\B"); + wire->width = width * swidth; + wire->port_input = true; + cell->setPort("\\B", wire); + + wire = module->addWire("\\S"); + wire->width = swidth; + wire->port_input = true; + cell->setPort("\\S", wire); + + wire = module->addWire("\\Y"); + wire->width = width; + wire->port_output = true; + cell->setPort("\\Y", wire); + } + if (cell_type == "$fa") { int width = 1 + xorshift32(8); @@ -164,6 +191,41 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type, cell->setParam("\\LUT", config.as_const()); } + if (cell_type == "$sop") + { + int width = 1 + xorshift32(8); + int depth = 1 + xorshift32(8); + + wire = module->addWire("\\A"); + wire->width = width; + wire->port_input = true; + cell->setPort("\\A", wire); + + wire = module->addWire("\\Y"); + wire->port_output = true; + cell->setPort("\\Y", wire); + + RTLIL::SigSpec config; + for (int i = 0; i < width*depth; i++) + switch (xorshift32(3)) { + case 0: + config.append(RTLIL::S1); + config.append(RTLIL::S0); + break; + case 1: + config.append(RTLIL::S0); + config.append(RTLIL::S1); + break; + case 2: + config.append(RTLIL::S0); + config.append(RTLIL::S0); + break; + } + + cell->setParam("\\DEPTH", depth); + cell->setParam("\\TABLE", config.as_const()); + } + if (cell_type_flags.find('A') != std::string::npos) { wire = module->addWire("\\A"); wire->width = 1 + xorshift32(8); @@ -270,6 +332,91 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type, cell->check(); } +static void run_edges_test(RTLIL::Design *design, bool verbose) +{ + Module *module = *design->modules().begin(); + Cell *cell = *module->cells().begin(); + + ezSatPtr ezptr; + ezSAT &ez = *ezptr.get(); + + SigMap sigmap(module); + SatGen satgen(&ez, &sigmap); + + FwdCellEdgesDatabase edges_db(sigmap); + if (!edges_db.add_edges_from_cell(cell)) + log_error("Creating edge database failed for this cell!\n"); + + dict<SigBit, pool<SigBit>> satgen_db; + + satgen.setContext(&sigmap, "X:"); + satgen.importCell(cell); + + satgen.setContext(&sigmap, "Y:"); + satgen.importCell(cell); + + vector<tuple<SigBit, int, int>> input_db, output_db; + + for (auto &conn : cell->connections()) + { + SigSpec bits = sigmap(conn.second); + + satgen.setContext(&sigmap, "X:"); + std::vector<int> xbits = satgen.importSigSpec(bits); + + satgen.setContext(&sigmap, "Y:"); + std::vector<int> ybits = satgen.importSigSpec(bits); + + for (int i = 0; i < GetSize(bits); i++) + if (cell->input(conn.first)) + input_db.emplace_back(bits[i], xbits[i], ybits[i]); + else + output_db.emplace_back(bits[i], xbits[i], ybits[i]); + } + + if (verbose) + log("\nSAT solving for all edges:\n"); + + for (int i = 0; i < GetSize(input_db); i++) + { + SigBit inbit = std::get<0>(input_db[i]); + + if (verbose) + log(" Testing input signal %s:\n", log_signal(inbit)); + + vector<int> xinbits, yinbits; + for (int k = 0; k < GetSize(input_db); k++) + if (k != i) { + xinbits.push_back(std::get<1>(input_db[k])); + yinbits.push_back(std::get<2>(input_db[k])); + } + + int xyinbit_ok = ez.vec_eq(xinbits, yinbits); + + for (int k = 0; k < GetSize(output_db); k++) + { + SigBit outbit = std::get<0>(output_db[k]); + int xoutbit = std::get<1>(output_db[k]); + int youtbit = std::get<2>(output_db[k]); + + bool is_edge = ez.solve(xyinbit_ok, ez.XOR(xoutbit, youtbit)); + + if (is_edge) + satgen_db[inbit].insert(outbit); + + if (verbose) { + bool is_ref_edge = edges_db.db.count(inbit) && edges_db.db.at(inbit).count(outbit); + log(" %c %s %s\n", is_edge ? 'x' : 'o', log_signal(outbit), is_edge == is_ref_edge ? "OK" : "ERROR"); + } + } + } + + if (satgen_db == edges_db.db) + log("PASS.\n"); + else + log_error("SAT-based edge table does not match the database!\n"); +} + static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::string uut_name, std::ofstream &vlog_file) { log("Eval testing:%c", verbose ? '\n' : ' '); @@ -534,7 +681,7 @@ struct TestCellPass : public Pass { log(" pass this option to techmap.\n"); log("\n"); log(" -simlib\n"); - log(" use \"techmap -map +/simlib.v -max_iter 2 -autoproc\"\n"); + log(" use \"techmap -D SIMLIB_NOCHECKS -map +/simlib.v -max_iter 2 -autoproc\"\n"); log("\n"); log(" -aigmap\n"); log(" instead of calling \"techmap\", call \"aigmap\"\n"); @@ -555,6 +702,9 @@ struct TestCellPass : public Pass { log(" -noeval\n"); log(" do not check const-eval models\n"); log("\n"); + log(" -edges\n"); + log(" test cell edges db creator against sat-based implementation\n"); + log("\n"); log(" -v\n"); log(" print additional debug information to the console\n"); log("\n"); @@ -574,6 +724,7 @@ struct TestCellPass : public Pass { bool constmode = false; bool nosat = false; bool noeval = false; + bool edges = false; int argidx; for (argidx = 1; argidx < GetSize(args); argidx++) @@ -604,7 +755,7 @@ struct TestCellPass : public Pass { continue; } if (args[argidx] == "-simlib") { - techmap_cmd = "techmap -map +/simlib.v -max_iter 2 -autoproc"; + techmap_cmd = "techmap -D SIMLIB_NOCHECKS -map +/simlib.v -max_iter 2 -autoproc"; continue; } if (args[argidx] == "-aigmap") { @@ -627,6 +778,10 @@ struct TestCellPass : public Pass { noeval = true; continue; } + if (args[argidx] == "-edges") { + edges = true; + continue; + } if (args[argidx] == "-v") { verbose = true; continue; @@ -690,13 +845,18 @@ struct TestCellPass : public Pass { cell_types["$logic_and"] = "ABSY"; cell_types["$logic_or"] = "ABSY"; - // cell_types["$mux"] = "A"; - // cell_types["$pmux"] = "A"; + if (edges) { + cell_types["$mux"] = "*"; + cell_types["$pmux"] = "*"; + } + // cell_types["$slice"] = "A"; // cell_types["$concat"] = "A"; // cell_types["$assert"] = "A"; + // cell_types["$assume"] = "A"; cell_types["$lut"] = "*"; + cell_types["$sop"] = "*"; cell_types["$alu"] = "ABSY"; cell_types["$lcu"] = "*"; cell_types["$macc"] = "*"; @@ -763,6 +923,9 @@ struct TestCellPass : public Pass { create_gold_module(design, cell_type, cell_types.at(cell_type), constmode, muxdiv); if (!write_prefix.empty()) { Pass::call(design, stringf("write_ilang %s_%s_%05d.il", write_prefix.c_str(), cell_type.c_str()+1, i)); + } else if (edges) { + Pass::call(design, "dump gold"); + run_edges_test(design, verbose); } else { Pass::call(design, stringf("copy gold gate; cd gate; %s; cd ..; opt -fast gate", techmap_cmd.c_str())); if (!nosat) diff --git a/techlibs/common/prep.cc b/techlibs/common/prep.cc index 8bae920d..fac6c4ba 100644 --- a/techlibs/common/prep.cc +++ b/techlibs/common/prep.cc @@ -25,22 +25,11 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -bool check_label(bool &active, std::string run_from, std::string run_to, std::string label) +struct PrepPass : public ScriptPass { - if (!run_from.empty() && run_from == run_to) { - active = (label == run_from); - } else { - if (label == run_from) - active = true; - if (label == run_to) - active = false; - } - return active; -} + PrepPass() : ScriptPass("prep", "generic synthesis script") { } -struct PrepPass : public Pass { - PrepPass() : Pass("prep", "generic synthesis script") { } - virtual void help() + virtual void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -53,6 +42,24 @@ struct PrepPass : public Pass { log(" -top <module>\n"); log(" use the specified module as top module (default='top')\n"); log("\n"); + log(" -auto-top\n"); + log(" automatically determine the top of the design hierarchy\n"); + log("\n"); + log(" -flatten\n"); + log(" flatten the design before synthesis. this will pass '-auto-top' to\n"); + log(" 'hierarchy' if no top module is specified.\n"); + log("\n"); + log(" -ifx\n"); + log(" passed to 'proc'. uses verilog simulation behavior for verilog if/case\n"); + log(" undef handling. this also prevents 'wreduce' from being run.\n"); + log("\n"); + log(" -memx\n"); + log(" simulate verilog simulation behavior for out-of-bounds memory accesses\n"); + log(" using the 'memory_memx' pass. This option implies -nordff.\n"); + log("\n"); + log(" -nomem\n"); + log(" do not run any of the memory_* passes\n"); + log("\n"); log(" -nordff\n"); log(" passed to 'memory_dff'. prohibits merging of FFs into memory read ports\n"); log("\n"); @@ -63,31 +70,28 @@ struct PrepPass : public Pass { log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); + help_script(); log("\n"); - log(" begin:\n"); - log(" hierarchy -check [-top <top>]\n"); - log("\n"); - log(" prep:\n"); - log(" proc\n"); - log(" opt_const\n"); - log(" opt_clean\n"); - log(" check\n"); - log(" opt -keepdc\n"); - log(" wreduce\n"); - log(" memory_dff [-nordff]\n"); - log(" opt_clean\n"); - log(" memory_collect\n"); - log(" opt -keepdc -fast\n"); - log("\n"); - log(" check:\n"); - log(" stat\n"); - log(" check\n"); - log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + + string top_module, fsm_opts, memory_opts; + bool autotop, flatten, ifxmode, memxmode, nomemmode; + + virtual void clear_flags() YS_OVERRIDE + { + top_module.clear(); + memory_opts.clear(); + + autotop = false; + flatten = false; + ifxmode = false; + memxmode = false; + nomemmode = false; + } + + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { - std::string top_module, memory_opts; - std::string run_from, run_to; + string run_from, run_to; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -107,6 +111,27 @@ struct PrepPass : public Pass { } continue; } + if (args[argidx] == "-auto-top") { + autotop = true; + continue; + } + if (args[argidx] == "-flatten") { + flatten = true; + continue; + } + if (args[argidx] == "-ifx") { + ifxmode = true; + continue; + } + if (args[argidx] == "-memx") { + memxmode = true; + memory_opts += " -nordff"; + continue; + } + if (args[argidx] == "-nomem") { + nomemmode = true; + continue; + } if (args[argidx] == "-nordff") { memory_opts += " -nordff"; continue; @@ -118,40 +143,65 @@ struct PrepPass : public Pass { if (!design->full_selection()) log_cmd_error("This comannd only operates on fully selected designs!\n"); - bool active = run_from.empty(); - - log_header("Executing PREP pass.\n"); + log_header(design, "Executing PREP pass.\n"); log_push(); - if (check_label(active, run_from, run_to, "begin")) + run_script(design, run_from, run_to); + + log_pop(); + } + + virtual void script() YS_OVERRIDE + { + + if (check_label("begin")) { - if (top_module.empty()) - Pass::call(design, stringf("hierarchy -check")); - else - Pass::call(design, stringf("hierarchy -check -top %s", top_module.c_str())); + if (help_mode) { + run("hierarchy -check [-top <top> | -auto-top]"); + } else { + if (top_module.empty()) { + if (flatten || autotop) + run("hierarchy -check -auto-top"); + else + run("hierarchy -check"); + } else + run(stringf("hierarchy -check -top %s", top_module.c_str())); + } } - if (check_label(active, run_from, run_to, "coarse")) + if (check_label("coarse")) { - Pass::call(design, "proc"); - Pass::call(design, "opt_const"); - Pass::call(design, "opt_clean"); - Pass::call(design, "check"); - Pass::call(design, "opt -keepdc"); - Pass::call(design, "wreduce"); - Pass::call(design, "memory_dff" + memory_opts); - Pass::call(design, "opt_clean"); - Pass::call(design, "memory_collect"); - Pass::call(design, "opt -keepdc -fast"); + if (help_mode) + run("proc [-ifx]"); + else + run(ifxmode ? "proc -ifx" : "proc"); + if (help_mode || flatten) + run("flatten", "(if -flatten)"); + run("opt_expr -keepdc"); + run("opt_clean"); + run("check"); + run("opt -keepdc"); + if (!ifxmode) { + if (help_mode) + run("wreduce [-memx]"); + else + run(memxmode ? "wreduce -memx" : "wreduce"); + } + if (!nomemmode) { + run("memory_dff" + (help_mode ? " [-nordff]" : memory_opts)); + if (help_mode || memxmode) + run("memory_memx", "(if -memx)"); + run("opt_clean"); + run("memory_collect"); + } + run("opt -keepdc -fast"); } - if (check_label(active, run_from, run_to, "check")) + if (check_label("check")) { - Pass::call(design, "stat"); - Pass::call(design, "check"); + run("stat"); + run("check"); } - - log_pop(); } } PrepPass; diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index a2dc466d..922a47ca 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -33,6 +33,12 @@ // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $not (A, Y) +//- +//- A bit-wise inverter. This corresponds to the Verilog unary prefix '~' operator. +//- module \$not (A, Y); parameter A_SIGNED = 0; @@ -55,6 +61,12 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $pos (A, Y) +//- +//- A buffer. This corresponds to the Verilog unary prefix '+' operator. +//- module \$pos (A, Y); parameter A_SIGNED = 0; @@ -76,6 +88,12 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $neg (A, Y) +//- +//- An arithmetic inverter. This corresponds to the Verilog unary prefix '-' operator. +//- module \$neg (A, Y); parameter A_SIGNED = 0; @@ -97,6 +115,12 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $and (A, B, Y) +//- +//- A bit-wise AND. This corresponds to the Verilog '&' operator. +//- module \$and (A, B, Y); parameter A_SIGNED = 0; @@ -121,6 +145,12 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $or (A, B, Y) +//- +//- A bit-wise OR. This corresponds to the Verilog '|' operator. +//- module \$or (A, B, Y); parameter A_SIGNED = 0; @@ -145,6 +175,12 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $xor (A, B, Y) +//- +//- A bit-wise XOR. This corresponds to the Verilog '^' operator. +//- module \$xor (A, B, Y); parameter A_SIGNED = 0; @@ -169,6 +205,12 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $xnor (A, B, Y) +//- +//- A bit-wise XNOR. This corresponds to the Verilog '~^' operator. +//- module \$xnor (A, B, Y); parameter A_SIGNED = 0; @@ -193,6 +235,12 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $reduce_and (A, B, Y) +//- +//- An AND reduction. This corresponds to the Verilog unary prefix '&' operator. +//- module \$reduce_and (A, Y); parameter A_SIGNED = 0; @@ -214,6 +262,12 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $reduce_or (A, B, Y) +//- +//- An OR reduction. This corresponds to the Verilog unary prefix '|' operator. +//- module \$reduce_or (A, Y); parameter A_SIGNED = 0; @@ -235,6 +289,12 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $reduce_xor (A, B, Y) +//- +//- A XOR reduction. This corresponds to the Verilog unary prefix '^' operator. +//- module \$reduce_xor (A, Y); parameter A_SIGNED = 0; @@ -256,6 +316,12 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $reduce_xnor (A, B, Y) +//- +//- A XNOR reduction. This corresponds to the Verilog unary prefix '~^' operator. +//- module \$reduce_xnor (A, Y); parameter A_SIGNED = 0; @@ -277,6 +343,13 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $reduce_bool (A, B, Y) +//- +//- An OR reduction. This cell type is used instead of $reduce_or when a signal is +//- implicitly converted to a boolean signal, e.g. for operands of '&&' and '||'. +//- module \$reduce_bool (A, Y); parameter A_SIGNED = 0; @@ -1156,6 +1229,34 @@ endmodule `endif // -------------------------------------------------------- +module \$sop (A, Y); + +parameter WIDTH = 0; +parameter DEPTH = 0; +parameter TABLE = 0; + +input [WIDTH-1:0] A; +output reg Y; + +integer i, j; +reg match; + +always @* begin + Y = 0; + for (i = 0; i < DEPTH; i=i+1) begin + match = 1; + for (j = 0; j < WIDTH; j=j+1) begin + if (TABLE[2*WIDTH*i + 2*j + 0] && A[j]) match = 0; + if (TABLE[2*WIDTH*i + 2*j + 1] && !A[j]) match = 0; + end + if (match) Y = 1; + end +end + +endmodule + +// -------------------------------------------------------- + module \$tribuf (A, EN, Y); parameter WIDTH = 0; @@ -1204,6 +1305,35 @@ endmodule // -------------------------------------------------------- +module \$initstate (Y); + +output reg Y = 1; +reg [3:0] cnt = 1; +reg trig = 0; + +initial trig <= 1; + +always @(cnt, trig) begin + Y <= |cnt; + cnt <= cnt + |cnt; +end + +endmodule + +// -------------------------------------------------------- + +module \$anyconst (Y); + +parameter WIDTH = 0; + +output [WIDTH-1:0] Y; + +assign Y = 'bx; + +endmodule + +// -------------------------------------------------------- + module \$equiv (A, B, Y); input A, B; @@ -1239,7 +1369,7 @@ wire [WIDTH-1:0] pos_clr = CLR_POLARITY ? CLR : ~CLR; genvar i; generate - for (i = 0; i < WIDTH; i = i+1) begin:bit + for (i = 0; i < WIDTH; i = i+1) begin:bitslices always @(posedge pos_set[i], posedge pos_clr[i]) if (pos_clr[i]) Q[i] <= 0; @@ -1308,7 +1438,7 @@ wire [WIDTH-1:0] pos_clr = CLR_POLARITY ? CLR : ~CLR; genvar i; generate - for (i = 0; i < WIDTH; i = i+1) begin:bit + for (i = 0; i < WIDTH; i = i+1) begin:bitslices always @(posedge pos_set[i], posedge pos_clr[i], posedge pos_clk) if (pos_clr[i]) Q[i] <= 0; @@ -1384,7 +1514,7 @@ wire [WIDTH-1:0] pos_clr = CLR_POLARITY ? CLR : ~CLR; genvar i; generate - for (i = 0; i < WIDTH; i = i+1) begin:bit + for (i = 0; i < WIDTH; i = i+1) begin:bitslices always @* if (pos_clr[i]) Q[i] = 0; diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc index 83d00f32..11ebe533 100644 --- a/techlibs/common/synth.cc +++ b/techlibs/common/synth.cc @@ -25,22 +25,11 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -bool check_label(bool &active, std::string run_from, std::string run_to, std::string label) +struct SynthPass : public ScriptPass { - if (!run_from.empty() && run_from == run_to) { - active = (label == run_from); - } else { - if (label == run_from) - active = true; - if (label == run_to) - active = false; - } - return active; -} + SynthPass() : ScriptPass("synth", "generic synthesis script") { } -struct SynthPass : public Pass { - SynthPass() : Pass("synth", "generic synthesis script") { } - virtual void help() + virtual void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -52,6 +41,13 @@ struct SynthPass : public Pass { log(" -top <module>\n"); log(" use the specified module as top module (default='top')\n"); log("\n"); + log(" -auto-top\n"); + log(" automatically determine the top of the design hierarchy\n"); + log("\n"); + log(" -flatten\n"); + log(" flatten the design before synthesis. this will pass '-auto-top' to\n"); + log(" 'hierarchy' if no top module is specified.\n"); + log("\n"); log(" -encfile <file>\n"); log(" passed to 'fsm_recode' via 'fsm'\n"); log("\n"); @@ -75,49 +71,30 @@ struct SynthPass : public Pass { log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); - log("\n"); - log(" begin:\n"); - log(" hierarchy -check [-top <top>]\n"); - log("\n"); - log(" coarse:\n"); - log(" proc\n"); - log(" opt_const\n"); - log(" opt_clean\n"); - log(" check\n"); - log(" opt\n"); - log(" wreduce\n"); - log(" alumacc\n"); - log(" share\n"); - log(" opt\n"); - log(" fsm\n"); - log(" opt -fast\n"); - log(" memory -nomap\n"); - log(" opt_clean\n"); - log("\n"); - log(" fine:\n"); - log(" opt -fast -full\n"); - log(" memory_map\n"); - log(" opt -full\n"); - log(" techmap\n"); - log(" opt -fast\n"); - #ifdef YOSYS_ENABLE_ABC - log(" abc -fast\n"); - log(" opt -fast\n"); - #endif - log("\n"); - log(" check:\n"); - log(" hierarchy -check\n"); - log(" stat\n"); - log(" check\n"); + help_script(); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + + string top_module, fsm_opts, memory_opts; + bool autotop, flatten, noalumacc, nofsm, noabc; + + virtual void clear_flags() YS_OVERRIDE + { + top_module.clear(); + fsm_opts.clear(); + memory_opts.clear(); + + autotop = false; + flatten = false; + noalumacc = false; + nofsm = false; + noabc = false; + } + + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { - std::string top_module, fsm_opts, memory_opts; - std::string run_from, run_to; - bool noalumacc = false; - bool nofsm = false; - bool noabc = false; + string run_from, run_to; + clear_flags(); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -141,6 +118,14 @@ struct SynthPass : public Pass { } continue; } + if (args[argidx] == "-auto-top") { + autotop = true; + continue; + } + if (args[argidx] == "-flatten") { + flatten = true; + continue; + } if (args[argidx] == "-nofsm") { nofsm = true; continue; @@ -164,62 +149,74 @@ struct SynthPass : public Pass { if (!design->full_selection()) log_cmd_error("This comannd only operates on fully selected designs!\n"); - bool active = run_from.empty(); - - log_header("Executing SYNTH pass.\n"); + log_header(design, "Executing SYNTH pass.\n"); log_push(); - if (check_label(active, run_from, run_to, "begin")) + run_script(design, run_from, run_to); + + log_pop(); + } + + virtual void script() YS_OVERRIDE + { + if (check_label("begin")) { - if (top_module.empty()) - Pass::call(design, stringf("hierarchy -check")); - else - Pass::call(design, stringf("hierarchy -check -top %s", top_module.c_str())); + if (help_mode) { + run("hierarchy -check [-top <top> | -auto-top]"); + } else { + if (top_module.empty()) { + if (flatten || autotop) + run("hierarchy -check -auto-top"); + else + run("hierarchy -check"); + } else + run(stringf("hierarchy -check -top %s", top_module.c_str())); + } } - if (check_label(active, run_from, run_to, "coarse")) + if (check_label("coarse")) { - Pass::call(design, "proc"); - Pass::call(design, "opt_const"); - Pass::call(design, "opt_clean"); - Pass::call(design, "check"); - Pass::call(design, "opt"); - Pass::call(design, "wreduce"); + run("proc"); + if (help_mode || flatten) + run("flatten", "(if -flatten)"); + run("opt_expr"); + run("opt_clean"); + run("check"); + run("opt"); + run("wreduce"); if (!noalumacc) - Pass::call(design, "alumacc"); - Pass::call(design, "share"); - Pass::call(design, "opt"); + run("alumacc"); + run("share"); + run("opt"); if (!nofsm) - Pass::call(design, "fsm" + fsm_opts); - Pass::call(design, "opt -fast"); - Pass::call(design, "memory -nomap" + memory_opts); - Pass::call(design, "opt_clean"); + run("fsm" + fsm_opts); + run("opt -fast"); + run("memory -nomap" + memory_opts); + run("opt_clean"); } - if (check_label(active, run_from, run_to, "fine")) + if (check_label("fine")) { - Pass::call(design, "opt -fast -full"); - Pass::call(design, "memory_map"); - Pass::call(design, "opt -full"); - Pass::call(design, "techmap"); - Pass::call(design, "opt -fast"); + run("opt -fast -full"); + run("memory_map"); + run("opt -full"); + run("techmap"); + run("opt -fast"); if (!noabc) { #ifdef YOSYS_ENABLE_ABC - Pass::call(design, "abc -fast"); - Pass::call(design, "opt -fast"); + run("abc -fast"); + run("opt -fast"); #endif } } - if (check_label(active, run_from, run_to, "check")) + if (check_label("check")) { - Pass::call(design, "hierarchy -check"); - Pass::call(design, "stat"); - Pass::call(design, "check"); + run("hierarchy -check"); + run("stat"); + run("check"); } - - log_pop(); } } SynthPass; diff --git a/techlibs/common/techmap.v b/techlibs/common/techmap.v index ae08c3d1..90c4ed7e 100644 --- a/techlibs/common/techmap.v +++ b/techlibs/common/techmap.v @@ -93,7 +93,7 @@ module _90_shift_ops_shr_shl_sshl_sshr (A, B, Y); localparam BB_WIDTH = `MIN($clog2(shift_left ? Y_WIDTH : A_SIGNED ? WIDTH : A_WIDTH) + 1, B_WIDTH); wire [1023:0] _TECHMAP_DO_00_ = "proc;;"; - wire [1023:0] _TECHMAP_DO_01_ = "RECURSION; CONSTMAP; opt_muxtree; opt_const -mux_undef -mux_bool -fine;;;"; + wire [1023:0] _TECHMAP_DO_01_ = "RECURSION; CONSTMAP; opt_muxtree; opt_expr -mux_undef -mux_bool -fine;;;"; integer i; reg [WIDTH-1:0] buffer; @@ -136,7 +136,7 @@ module _90_shift_shiftx (A, B, Y); localparam extbit = _TECHMAP_CELLTYPE_ == "$shift" ? 1'b0 : 1'bx; wire [1023:0] _TECHMAP_DO_00_ = "proc;;"; - wire [1023:0] _TECHMAP_DO_01_ = "CONSTMAP; opt_muxtree; opt_const -mux_undef -mux_bool -fine;;;"; + wire [1023:0] _TECHMAP_DO_01_ = "CONSTMAP; opt_muxtree; opt_expr -mux_undef -mux_bool -fine;;;"; integer i; reg [WIDTH-1:0] buffer; @@ -452,7 +452,7 @@ endmodule `ifndef NOLUT (* techmap_simplemap *) -(* techmap_celltype = "$lut" *) +(* techmap_celltype = "$lut $sop" *) module _90_lut; endmodule `endif diff --git a/techlibs/greenpak4/Makefile.inc b/techlibs/greenpak4/Makefile.inc index 5808e7bd..1c9871e2 100644 --- a/techlibs/greenpak4/Makefile.inc +++ b/techlibs/greenpak4/Makefile.inc @@ -1,5 +1,7 @@ OBJS += techlibs/greenpak4/synth_greenpak4.o +OBJS += techlibs/greenpak4/greenpak4_counters.o +OBJS += techlibs/greenpak4/greenpak4_dffinv.o $(eval $(call add_share_file,share/greenpak4,techlibs/greenpak4/cells_map.v)) $(eval $(call add_share_file,share/greenpak4,techlibs/greenpak4/cells_sim.v)) diff --git a/techlibs/greenpak4/cells_map.v b/techlibs/greenpak4/cells_map.v index 667d853d..111a77a1 100644 --- a/techlibs/greenpak4/cells_map.v +++ b/techlibs/greenpak4/cells_map.v @@ -1,20 +1,61 @@ -module \$_DFF_P_ (input D, C, output Q); - GP_DFF _TECHMAP_REPLACE_ ( +module GP_DFFS(input D, CLK, nSET, output reg Q); + parameter [0:0] INIT = 1'bx; + GP_DFFSR #( + .INIT(INIT), + .SRMODE(1'b1), + ) _TECHMAP_REPLACE_ ( .D(D), - .Q(Q), - .CLK(C), - .nRSTZ(1'b1), - .nSETZ(1'b1) + .CLK(CLK), + .nSR(nSET), + .Q(Q) ); endmodule -module \$_DFFSR_PNN_ (input C, S, R, D, output Q); - GP_DFF _TECHMAP_REPLACE_ ( +module GP_DFFR(input D, CLK, nRST, output reg Q); + parameter [0:0] INIT = 1'bx; + GP_DFFSR #( + .INIT(INIT), + .SRMODE(1'b0), + ) _TECHMAP_REPLACE_ ( .D(D), - .Q(Q), - .CLK(C), - .nRSTZ(R), - .nSETZ(S) + .CLK(CLK), + .nSR(nRST), + .Q(Q) + ); +endmodule + +module GP_DFFSI(input D, CLK, nSET, output reg nQ); + parameter [0:0] INIT = 1'bx; + GP_DFFSRI #( + .INIT(INIT), + .SRMODE(1'b1), + ) _TECHMAP_REPLACE_ ( + .D(D), + .CLK(CLK), + .nSR(nSET), + .nQ(nQ) + ); +endmodule + +module GP_DFFRI(input D, CLK, nRST, output reg nQ); + parameter [0:0] INIT = 1'bx; + GP_DFFSRI #( + .INIT(INIT), + .SRMODE(1'b0), + ) _TECHMAP_REPLACE_ ( + .D(D), + .CLK(CLK), + .nSR(nRST), + .nQ(nQ) + ); +endmodule + +module GP_OBUFT(input IN, input OE, output OUT); + GP_IOBUF _TECHMAP_REPLACE_ ( + .IN(IN), + .OE(OE), + .IO(OUT), + .OUT() ); endmodule @@ -27,8 +68,13 @@ module \$lut (A, Y); generate if (WIDTH == 1) begin - GP_2LUT #(.INIT({2'b00, LUT})) _TECHMAP_REPLACE_ (.OUT(Y), - .IN0(A[0]), .IN1(1'b0)); + if(LUT == 2'b01) begin + GP_INV _TECHMAP_REPLACE_ (.OUT(Y), .IN(A[0]) ); + end + else begin + GP_2LUT #(.INIT({2'b00, LUT})) _TECHMAP_REPLACE_ (.OUT(Y), + .IN0(A[0]), .IN1(1'b0)); + end end else if (WIDTH == 2) begin GP_2LUT #(.INIT(LUT)) _TECHMAP_REPLACE_ (.OUT(Y), diff --git a/techlibs/greenpak4/cells_sim.v b/techlibs/greenpak4/cells_sim.v index d9ddaacc..6ae9ae79 100644 --- a/techlibs/greenpak4/cells_sim.v +++ b/techlibs/greenpak4/cells_sim.v @@ -1,13 +1,4 @@ -module GP_DFF(input D, CLK, nRSTZ, nSETZ, output reg Q); - always @(posedge CLK, negedge nRSTZ, negedge nSETZ) begin - if (!nRSTZ) - Q <= 1'b0; - else if (!nSETZ) - Q <= 1'b1; - else - Q <= D; - end -endmodule +`timescale 1ns/1ps module GP_2LUT(input IN0, IN1, output OUT); parameter [3:0] INIT = 0; @@ -23,3 +14,417 @@ module GP_4LUT(input IN0, IN1, IN2, IN3, output OUT); parameter [15:0] INIT = 0; assign OUT = INIT[{IN3, IN2, IN1, IN0}]; endmodule + +module GP_ABUF(input wire IN, output wire OUT); + + assign OUT = IN; + + //cannot simulate mixed signal IP + +endmodule + +module GP_ACMP(input wire PWREN, input wire VIN, input wire VREF, output reg OUT); + + parameter BANDWIDTH = "HIGH"; + parameter VIN_ATTEN = 1; + parameter VIN_ISRC_EN = 0; + parameter HYSTERESIS = 0; + + initial OUT = 0; + + //cannot simulate mixed signal IP + +endmodule + +module GP_BANDGAP(output reg OK); + parameter AUTO_PWRDN = 1; + parameter CHOPPER_EN = 1; + parameter OUT_DELAY = 100; + + //cannot simulate mixed signal IP + +endmodule + +module GP_COUNT8(input CLK, input wire RST, output reg OUT); + + parameter RESET_MODE = "RISING"; + + parameter COUNT_TO = 8'h1; + parameter CLKIN_DIVIDE = 1; + + //more complex hard IP blocks are not supported for simulation yet + + reg[7:0] count = COUNT_TO; + + //Combinatorially output whenever we wrap low + always @(*) begin + OUT <= (count == 8'h0); + end + + //POR or SYSRST reset value is COUNT_TO. Datasheet is unclear but conversations w/ Silego confirm. + //Runtime reset value is clearly 0 except in count/FSM cells where it's configurable but we leave at 0 for now. + //Datasheet seems to indicate that reset is asynchronous, but for now we model as sync due to Yosys issues... + always @(posedge CLK) begin + + count <= count - 1'd1; + + if(count == 0) + count <= COUNT_TO; + + /* + if((RESET_MODE == "RISING") && RST) + count <= 0; + if((RESET_MODE == "FALLING") && !RST) + count <= 0; + if((RESET_MODE == "BOTH") && RST) + count <= 0; + */ + end + +endmodule + +module GP_COUNT14(input CLK, input wire RST, output reg OUT); + + parameter RESET_MODE = "RISING"; + + parameter COUNT_TO = 14'h1; + parameter CLKIN_DIVIDE = 1; + + //more complex hard IP blocks are not supported for simulation yet + +endmodule + +module GP_COUNT8_ADV(input CLK, input RST, output reg OUT, + input UP, input KEEP); + + parameter RESET_MODE = "RISING"; + parameter RESET_VALUE = "ZERO"; + + parameter COUNT_TO = 8'h1; + parameter CLKIN_DIVIDE = 1; + + //more complex hard IP blocks are not supported for simulation yet + +endmodule + +module GP_COUNT14_ADV(input CLK, input RST, output reg OUT, + input UP, input KEEP); + + parameter RESET_MODE = "RISING"; + parameter RESET_VALUE = "ZERO"; + + parameter COUNT_TO = 14'h1; + parameter CLKIN_DIVIDE = 1; + + //more complex hard IP blocks are not supported for simulation yet + +endmodule + +module GP_DAC(input[7:0] DIN, input wire VREF, output reg VOUT); + + initial VOUT = 0; + + //analog hard IP is not supported for simulation + +endmodule + +module GP_DELAY(input IN, output reg OUT); + + parameter DELAY_STEPS = 1; + + //TODO: additional delay/glitch filter mode + + initial OUT = 0; + + generate + + //TODO: These delays are PTV dependent! For now, hard code 3v3 timing + //Change simulation-mode delay depending on global Vdd range (how to specify this?) + always @(*) begin + case(DELAY_STEPS) + 1: #166 OUT = IN; + 2: #318 OUT = IN; + 2: #471 OUT = IN; + 3: #622 OUT = IN; + default: begin + $display("ERROR: GP_DELAY must have DELAY_STEPS in range [1,4]"); + $finish; + end + endcase + end + + endgenerate + +endmodule + +module GP_DFF(input D, CLK, output reg Q); + parameter [0:0] INIT = 1'bx; + initial Q = INIT; + always @(posedge CLK) begin + Q <= D; + end +endmodule + +module GP_DFFI(input D, CLK, output reg nQ); + parameter [0:0] INIT = 1'bx; + initial nQ = INIT; + always @(posedge CLK) begin + nQ <= ~D; + end +endmodule + +module GP_DFFR(input D, CLK, nRST, output reg Q); + parameter [0:0] INIT = 1'bx; + initial Q = INIT; + always @(posedge CLK, negedge nRST) begin + if (!nRST) + Q <= 1'b0; + else + Q <= D; + end +endmodule + +module GP_DFFRI(input D, CLK, nRST, output reg nQ); + parameter [0:0] INIT = 1'bx; + initial nQ = INIT; + always @(posedge CLK, negedge nRST) begin + if (!nRST) + nQ <= 1'b1; + else + nQ <= ~D; + end +endmodule + +module GP_DFFS(input D, CLK, nSET, output reg Q); + parameter [0:0] INIT = 1'bx; + initial Q = INIT; + always @(posedge CLK, negedge nSET) begin + if (!nSET) + Q <= 1'b1; + else + Q <= D; + end +endmodule + +module GP_DFFSI(input D, CLK, nSET, output reg nQ); + parameter [0:0] INIT = 1'bx; + initial nQ = INIT; + always @(posedge CLK, negedge nSET) begin + if (!nSET) + nQ <= 1'b0; + else + nQ <= ~D; + end +endmodule + +module GP_DFFSR(input D, CLK, nSR, output reg Q); + parameter [0:0] INIT = 1'bx; + parameter [0:0] SRMODE = 1'bx; + initial Q = INIT; + always @(posedge CLK, negedge nSR) begin + if (!nSR) + Q <= SRMODE; + else + Q <= D; + end +endmodule + +module GP_DFFSRI(input D, CLK, nSR, output reg nQ); + parameter [0:0] INIT = 1'bx; + parameter [0:0] SRMODE = 1'bx; + initial nQ = INIT; + always @(posedge CLK, negedge nSR) begin + if (!nSR) + nQ <= ~SRMODE; + else + nQ <= ~D; + end +endmodule + +module GP_IBUF(input IN, output OUT); + assign OUT = IN; +endmodule + +module GP_IOBUF(input IN, input OE, output OUT, inout IO); + assign OUT = IO; + assign IO = OE ? IN : 1'bz; +endmodule + +module GP_INV(input IN, output OUT); + assign OUT = ~IN; +endmodule + +module GP_LFOSC(input PWRDN, output reg CLKOUT); + + parameter PWRDN_EN = 0; + parameter AUTO_PWRDN = 0; + parameter OUT_DIV = 1; + + initial CLKOUT = 0; + + //auto powerdown not implemented for simulation + //output dividers not implemented for simulation + + always begin + if(PWRDN) + CLKOUT = 0; + else begin + //half period of 1730 Hz + #289017; + CLKOUT = ~CLKOUT; + end + end + +endmodule + +module GP_OBUF(input IN, output OUT); + assign OUT = IN; +endmodule + +module GP_OBUFT(input IN, input OE, output OUT); + assign OUT = OE ? IN : 1'bz; +endmodule + +module GP_PGA(input wire VIN_P, input wire VIN_N, input wire VIN_SEL, output reg VOUT); + + parameter GAIN = 1; + parameter INPUT_MODE = "SINGLE"; + + initial VOUT = 0; + + //cannot simulate mixed signal IP + +endmodule + +module GP_POR(output reg RST_DONE); + parameter POR_TIME = 500; + + initial begin + RST_DONE = 0; + + if(POR_TIME == 4) + #4000; + else if(POR_TIME == 500) + #500000; + else begin + $display("ERROR: bad POR_TIME for GP_POR cell"); + $finish; + end + + RST_DONE = 1; + + end + +endmodule + +module GP_RCOSC(input PWRDN, output reg CLKOUT_HARDIP, output reg CLKOUT_FABRIC); + + parameter PWRDN_EN = 0; + parameter AUTO_PWRDN = 0; + parameter HARDIP_DIV = 1; + parameter FABRIC_DIV = 1; + parameter OSC_FREQ = "25k"; + + initial CLKOUT_HARDIP = 0; + initial CLKOUT_FABRIC = 0; + + //output dividers not implemented for simulation + //auto powerdown not implemented for simulation + + always begin + if(PWRDN) begin + CLKOUT_HARDIP = 0; + CLKOUT_FABRIC = 0; + end + else begin + + if(OSC_FREQ == "25k") begin + //half period of 25 kHz + #20000; + end + + else begin + //half period of 2 MHz + #250; + end + + CLKOUT_HARDIP = ~CLKOUT_HARDIP; + CLKOUT_FABRIC = ~CLKOUT_FABRIC; + end + end + +endmodule + +module GP_RINGOSC(input PWRDN, output reg CLKOUT_HARDIP, output reg CLKOUT_FABRIC); + + parameter PWRDN_EN = 0; + parameter AUTO_PWRDN = 0; + parameter HARDIP_DIV = 1; + parameter FABRIC_DIV = 1; + + initial CLKOUT_HARDIP = 0; + initial CLKOUT_FABRIC = 0; + + //output dividers not implemented for simulation + //auto powerdown not implemented for simulation + + always begin + if(PWRDN) begin + CLKOUT_HARDIP = 0; + CLKOUT_FABRIC = 0; + end + else begin + //half period of 27 MHz + #18.518; + CLKOUT_HARDIP = ~CLKOUT_HARDIP; + CLKOUT_FABRIC = ~CLKOUT_FABRIC; + end + end + +endmodule + +module GP_SHREG(input nRST, input CLK, input IN, output OUTA, output OUTB); + + parameter OUTA_TAP = 1; + parameter OUTA_INVERT = 0; + parameter OUTB_TAP = 1; + + reg[15:0] shreg = 0; + + always @(posedge CLK, negedge nRST) begin + + if(!nRST) + shreg = 0; + + else + shreg <= {shreg[14:0], IN}; + + end + + assign OUTA = (OUTA_INVERT) ? ~shreg[OUTA_TAP - 1] : shreg[OUTA_TAP - 1]; + assign OUTB = shreg[OUTB_TAP - 1]; + +endmodule + +//keep constraint needed to prevent optimization since we have no outputs +(* keep *) +module GP_SYSRESET(input RST); + parameter RESET_MODE = "RISING"; + + //cannot simulate whole system reset + +endmodule + +module GP_VDD(output OUT); + assign OUT = 1; +endmodule + +module GP_VREF(input VIN, output reg VOUT); + parameter VIN_DIV = 1; + parameter VREF = 0; + //cannot simulate mixed signal IP +endmodule + +module GP_VSS(output OUT); + assign OUT = 0; +endmodule diff --git a/techlibs/greenpak4/gp_dff.lib b/techlibs/greenpak4/gp_dff.lib index 9e2e46cb..b4b8c102 100644 --- a/techlibs/greenpak4/gp_dff.lib +++ b/techlibs/greenpak4/gp_dff.lib @@ -1,26 +1,36 @@ library(gp_dff) { - cell(GP_DFF_NOSR) { + cell(GP_DFF) { area: 1; ff("IQ", "IQN") { clocked_on: CLK; - next_state: D; } + next_state: D; } pin(CLK) { direction: input; - clock: true; } + clock: true; } pin(D) { direction: input; } pin(Q) { direction: output; function: "IQ"; } } - cell(GP_DFF_SR) { + cell(GP_DFFS) { area: 1; ff("IQ", "IQN") { clocked_on: CLK; next_state: D; - preset: "nSETZ'"; - clear: "nRSTZ'"; } + preset: "nSET'"; } pin(CLK) { direction: input; clock: true; } pin(D) { direction: input; } pin(Q) { direction: output; function: "IQ"; } - pin(nRSTZ) { direction: input; } - pin(nSETZ) { direction: input; } + pin(nSET) { direction: input; } + } + cell(GP_DFFR) { + area: 1; + ff("IQ", "IQN") { clocked_on: CLK; + next_state: D; + clear: "nRST'"; } + pin(CLK) { direction: input; + clock: true; } + pin(D) { direction: input; } + pin(Q) { direction: output; + function: "IQ"; } + pin(nRST) { direction: input; } } } diff --git a/techlibs/greenpak4/greenpak4_counters.cc b/techlibs/greenpak4/greenpak4_counters.cc new file mode 100644 index 00000000..998bb73b --- /dev/null +++ b/techlibs/greenpak4/greenpak4_counters.cc @@ -0,0 +1,442 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2016 Clifford Wolf <clifford@clifford.at> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" +#include "kernel/modtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +//get the list of cells hooked up to at least one bit of a given net +pool<Cell*> get_other_cells(const RTLIL::SigSpec& port, ModIndex& index, Cell* src) +{ + pool<Cell*> rval; + for(auto b : port) + { + pool<ModIndex::PortInfo> ports = index.query_ports(b); + for(auto x : ports) + { + if(x.cell == src) + continue; + rval.insert(x.cell); + } + } + return rval; +} + +//return true if there is a full-width bus connection from cell a port ap to cell b port bp +//if other_conns_allowed is false, then we require a strict point to point connection (no other links) +bool is_full_bus( + const RTLIL::SigSpec& sig, + ModIndex& index, + Cell* a, + RTLIL::IdString ap, + Cell* b, + RTLIL::IdString bp, + bool other_conns_allowed = false) +{ + for(auto s : sig) + { + pool<ModIndex::PortInfo> ports = index.query_ports(s); + bool found_a = false; + bool found_b = false; + for(auto x : ports) + { + if( (x.cell == a) && (x.port == ap) ) + found_a = true; + else if( (x.cell == b) && (x.port == bp) ) + found_b = true; + else if(!other_conns_allowed) + return false; + } + + if( (!found_a) || (!found_b) ) + return false; + } + + return true; +} + +//return true if the signal connects to one port only (nothing on the other end) +bool is_unconnected(const RTLIL::SigSpec& port, ModIndex& index) +{ + for(auto b : port) + { + pool<ModIndex::PortInfo> ports = index.query_ports(b); + if(ports.size() > 1) + return false; + } + + return true; +} + +struct CounterExtraction +{ + int width; //counter width + RTLIL::Wire* rwire; //the register output + bool has_reset; //true if we have a reset + RTLIL::SigSpec rst; //reset pin + int count_value; //value we count from + RTLIL::SigSpec clk; //clock signal + RTLIL::SigSpec outsig; //counter output signal + RTLIL::Cell* count_mux; //counter mux + RTLIL::Cell* count_reg; //counter register + RTLIL::Cell* underflow_inv; //inverter reduction for output-underflow detect +}; + +//attempt to extract a counter centered on the given cell +int greenpak4_counters_tryextract(ModIndex& index, Cell *cell, CounterExtraction& extract) +{ + SigMap& sigmap = index.sigmap; + + //GreenPak does not support counters larger than 14 bits so immediately skip anything bigger + int a_width = cell->getParam("\\A_WIDTH").as_int(); + extract.width = a_width; + if(a_width > 14) + return 1; + + //Second input must be a single bit + int b_width = cell->getParam("\\B_WIDTH").as_int(); + if(b_width != 1) + return 2; + + //Both inputs must be unsigned, so don't extract anything with a signed input + bool a_sign = cell->getParam("\\A_SIGNED").as_bool(); + bool b_sign = cell->getParam("\\B_SIGNED").as_bool(); + if(a_sign || b_sign) + return 3; + + //To be a counter, one input of the ALU must be a constant 1 + //TODO: can A or B be swapped in synthesized RTL or is B always the 1? + const RTLIL::SigSpec b_port = sigmap(cell->getPort("\\B")); + if(!b_port.is_fully_const() || (b_port.as_int() != 1) ) + return 4; + + //BI and CI must be constant 1 as well + const RTLIL::SigSpec bi_port = sigmap(cell->getPort("\\BI")); + if(!bi_port.is_fully_const() || (bi_port.as_int() != 1) ) + return 5; + const RTLIL::SigSpec ci_port = sigmap(cell->getPort("\\CI")); + if(!ci_port.is_fully_const() || (ci_port.as_int() != 1) ) + return 6; + + //CO and X must be unconnected (exactly one connection to each port) + if(!is_unconnected(sigmap(cell->getPort("\\CO")), index)) + return 7; + if(!is_unconnected(sigmap(cell->getPort("\\X")), index)) + return 8; + + //Y must have exactly one connection, and it has to be a $mux cell. + //We must have a direct bus connection from our Y to their A. + const RTLIL::SigSpec aluy = sigmap(cell->getPort("\\Y")); + pool<Cell*> y_loads = get_other_cells(aluy, index, cell); + if(y_loads.size() != 1) + return 9; + Cell* count_mux = *y_loads.begin(); + extract.count_mux = count_mux; + if(count_mux->type != "$mux") + return 10; + if(!is_full_bus(aluy, index, cell, "\\Y", count_mux, "\\A")) + return 11; + + //B connection of the mux is our underflow value + const RTLIL::SigSpec underflow = sigmap(count_mux->getPort("\\B")); + if(!underflow.is_fully_const()) + return 12; + extract.count_value = underflow.as_int(); + + //S connection of the mux must come from an inverter (need not be the only load) + const RTLIL::SigSpec muxsel = sigmap(count_mux->getPort("\\S")); + extract.outsig = muxsel; + pool<Cell*> muxsel_conns = get_other_cells(muxsel, index, count_mux); + Cell* underflow_inv = NULL; + for(auto c : muxsel_conns) + { + if(c->type != "$logic_not") + continue; + if(!is_full_bus(muxsel, index, c, "\\Y", count_mux, "\\S", true)) + continue; + + underflow_inv = c; + break; + } + if(underflow_inv == NULL) + return 13; + extract.underflow_inv = underflow_inv; + + //Y connection of the mux must have exactly one load, the counter's internal register + const RTLIL::SigSpec muxy = sigmap(count_mux->getPort("\\Y")); + pool<Cell*> muxy_loads = get_other_cells(muxy, index, count_mux); + if(muxy_loads.size() != 1) + return 14; + Cell* count_reg = *muxy_loads.begin(); + extract.count_reg = count_reg; + if(count_reg->type == "$dff") + extract.has_reset = false; + else if(count_reg->type == "$adff") + { + extract.has_reset = true; + + //Verify ARST_VALUE is zero and ARST_POLARITY is 1 + //TODO: infer an inverter to make it 1 if necessary, so we can support negative level resets? + if(count_reg->getParam("\\ARST_POLARITY").as_int() != 1) + return 22; + if(count_reg->getParam("\\ARST_VALUE").as_int() != 0) + return 23; + + //Save the reset + extract.rst = sigmap(count_reg->getPort("\\ARST")); + } + //TODO: support synchronous reset + else + return 15; + if(!is_full_bus(muxy, index, count_mux, "\\Y", count_reg, "\\D")) + return 16; + + //TODO: Verify count_reg CLK_POLARITY is 1 + + //Register output must have exactly two loads, the inverter and ALU + const RTLIL::SigSpec cnout = sigmap(count_reg->getPort("\\Q")); + pool<Cell*> cnout_loads = get_other_cells(cnout, index, count_reg); + if(cnout_loads.size() != 2) + return 17; + if(!is_full_bus(cnout, index, count_reg, "\\Q", underflow_inv, "\\A", true)) + return 18; + if(!is_full_bus(cnout, index, count_reg, "\\Q", cell, "\\A", true)) + return 19; + + //Look up the clock from the register + extract.clk = sigmap(count_reg->getPort("\\CLK")); + + //Register output net must have an INIT attribute equal to the count value + extract.rwire = cnout.as_wire(); + if(extract.rwire->attributes.find("\\init") == extract.rwire->attributes.end()) + return 20; + int rinit = extract.rwire->attributes["\\init"].as_int(); + if(rinit != extract.count_value) + return 21; + + return 0; +} + +void greenpak4_counters_worker( + ModIndex& index, + Cell *cell, + unsigned int& total_counters, + pool<Cell*>& cells_to_remove) +{ + SigMap& sigmap = index.sigmap; + + //Core of the counter must be an ALU + if (cell->type != "$alu") + return; + + //A input is the count value. Check if it has COUNT_EXTRACT set. + //If it's not a wire, don't even try + auto port = sigmap(cell->getPort("\\A")); + if(!port.is_wire()) + return; + RTLIL::Wire* a_wire = port.as_wire(); + bool force_extract = false; + bool never_extract = false; + string count_reg_src = a_wire->attributes["\\src"].decode_string().c_str(); + if(a_wire->attributes.find("\\COUNT_EXTRACT") != a_wire->attributes.end()) + { + pool<string> sa = a_wire->get_strpool_attribute("\\COUNT_EXTRACT"); + string extract_value; + if(sa.size() >= 1) + { + extract_value = *sa.begin(); + log(" Signal %s declared at %s has COUNT_EXTRACT = %s\n", + log_id(a_wire), + count_reg_src.c_str(), + extract_value.c_str()); + + if(extract_value == "FORCE") + force_extract = true; + else if(extract_value == "NO") + never_extract = true; + else if(extract_value == "AUTO") + {} //default + else + log_error(" Illegal COUNT_EXTRACT value %s (must be one of FORCE, NO, AUTO)\n", + extract_value.c_str()); + } + } + + //If we're explicitly told not to extract, don't infer a counter + if(never_extract) + return; + + //Attempt to extract a counter + CounterExtraction extract; + int reason = greenpak4_counters_tryextract(index, cell, extract); + + //Nonzero code - we could not find a matchable counter. + //Do nothing, unless extraction was forced in which case give an error + if(reason != 0) + { + static const char* reasons[24]= + { + "no problem", //0 + "counter is larger than 14 bits", //1 + "counter does not count by one", //2 + "counter uses signed math", //3 + "counter does not count by one", //4 + "ALU is not a subtractor", //5 + "ALU is not a subtractor", //6 + "ALU ports used outside counter", //7 + "ALU ports used outside counter", //8 + "ALU output used outside counter", //9 + "ALU output is not a mux", //10 + "ALU output is not full bus", //11 + "Underflow value is not constant", //12 + "No underflow detector found", //13 + "Mux output is used outside counter", //14 + "Counter reg is not DFF/ADFF", //15 + "Counter input is not full bus", //16 + "Count register is used outside counter", //17 + "Register output is not full bus", //18 + "Register output is not full bus", //19 + "No init value found", //20 + "Underflow value is not equal to init value", //21 + "Reset polarity is not positive", //22 + "Reset is not to zero" //23 + }; + + if(force_extract) + { + log_error( + "Counter extraction is set to FORCE on register %s, but a counter could not be inferred (%s)\n", + log_id(a_wire), + reasons[reason]); + } + return; + } + + //Figure out the final cell type based on the counter size + string celltype = "\\GP_COUNT8"; + if(extract.width > 8) + celltype = "\\GP_COUNT14"; + + //Log it + total_counters ++; + string reset_type = "non-resettable"; + if(extract.has_reset) + { + //TODO: support other kind of reset + reset_type = "async resettable"; + } + log(" Found %d-bit %s down counter (from %d) for register %s declared at %s\n", + extract.width, + reset_type.c_str(), + extract.count_value, + log_id(extract.rwire->name), + count_reg_src.c_str()); + + //Wipe all of the old connections to the ALU + cell->unsetPort("\\A"); + cell->unsetPort("\\B"); + cell->unsetPort("\\BI"); + cell->unsetPort("\\CI"); + cell->unsetPort("\\CO"); + cell->unsetPort("\\X"); + cell->unsetPort("\\Y"); + cell->unsetParam("\\A_SIGNED"); + cell->unsetParam("\\A_WIDTH"); + cell->unsetParam("\\B_SIGNED"); + cell->unsetParam("\\B_WIDTH"); + cell->unsetParam("\\Y_WIDTH"); + + //Change the cell type + cell->type = celltype; + + //Hook up resets + if(extract.has_reset) + { + //TODO: support other kinds of reset + cell->setParam("\\RESET_MODE", RTLIL::Const("LEVEL")); + cell->setPort("\\RST", extract.rst); + } + else + { + cell->setParam("\\RESET_MODE", RTLIL::Const("RISING")); + cell->setPort("\\RST", RTLIL::SigSpec(false)); + } + + //Hook up other stuff + cell->setParam("\\CLKIN_DIVIDE", RTLIL::Const(1)); + cell->setParam("\\COUNT_TO", RTLIL::Const(extract.count_value)); + + cell->setPort("\\CLK", extract.clk); + cell->setPort("\\OUT", extract.outsig); + + //Delete the cells we've replaced (let opt_clean handle deleting the now-redundant wires) + cells_to_remove.insert(extract.count_mux); + cells_to_remove.insert(extract.count_reg); + cells_to_remove.insert(extract.underflow_inv); +} + +struct Greenpak4CountersPass : public Pass { + Greenpak4CountersPass() : Pass("greenpak4_counters", "Extract GreenPak4 counter cells") { } + virtual void help() + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" greenpak4_counters [options] [selection]\n"); + log("\n"); + log("This pass converts non-resettable or async resettable down counters to GreenPak4\n"); + log("counter cells (All other GreenPak4 counter modes must be instantiated manually.)\n"); + log("\n"); + } + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + { + log_header(design, "Executing GREENPAK4_COUNTERS pass (mapping counters to hard IP blocks).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-v") { + // continue; + // } + break; + } + extra_args(args, argidx, design); + + //Extract all of the counters we could find + unsigned int total_counters = 0; + for (auto module : design->selected_modules()) + { + pool<Cell*> cells_to_remove; + + ModIndex index(module); + for (auto cell : module->selected_cells()) + greenpak4_counters_worker(index, cell, total_counters, cells_to_remove); + + for(auto cell : cells_to_remove) + module->remove(cell); + } + + if(total_counters) + log("Extracted %u counters\n", total_counters); + } +} Greenpak4CountersPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/greenpak4/greenpak4_dffinv.cc b/techlibs/greenpak4/greenpak4_dffinv.cc new file mode 100644 index 00000000..ff63958e --- /dev/null +++ b/techlibs/greenpak4/greenpak4_dffinv.cc @@ -0,0 +1,197 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +void invert_gp_dff(Cell *cell, bool invert_input) +{ + string cell_type = cell->type.str(); + bool cell_type_i = cell_type.find('I') != string::npos; + bool cell_type_r = cell_type.find('R') != string::npos; + bool cell_type_s = cell_type.find('S') != string::npos; + + if (!invert_input) + { + Const initval = cell->getParam("\\INIT"); + if (GetSize(initval) >= 1) { + if (initval.bits[0] == State::S0) + initval.bits[0] = State::S1; + else if (initval.bits[0] == State::S1) + initval.bits[0] = State::S0; + cell->setParam("\\INIT", initval); + } + + if (cell_type_r && cell_type_s) + { + Const srmode = cell->getParam("\\SRMODE"); + if (GetSize(srmode) >= 1) { + if (srmode.bits[0] == State::S0) + srmode.bits[0] = State::S1; + else if (srmode.bits[0] == State::S1) + srmode.bits[0] = State::S0; + cell->setParam("\\SRMODE", srmode); + } + } + else + { + if (cell_type_r) { + cell->setPort("\\nSET", cell->getPort("\\nRST")); + cell->unsetPort("\\nRST"); + cell_type_r = false; + cell_type_s = true; + } else + if (cell_type_s) { + cell->setPort("\\nRST", cell->getPort("\\nSET")); + cell->unsetPort("\\nSET"); + cell_type_r = true; + cell_type_s = false; + } + } + } + + if (cell_type_i) { + cell->setPort("\\Q", cell->getPort("\\nQ")); + cell->unsetPort("\\nQ"); + cell_type_i = false; + } else { + cell->setPort("\\nQ", cell->getPort("\\Q")); + cell->unsetPort("\\Q"); + cell_type_i = true; + } + + cell->type = stringf("\\GP_DFF%s%s%s", cell_type_s ? "S" : "", cell_type_r ? "R" : "", cell_type_i ? "I" : ""); + + log("Merged %s inverter into cell %s.%s: %s -> %s\n", invert_input ? "input" : "output", + log_id(cell->module), log_id(cell), cell_type.c_str()+1, log_id(cell->type)); +} + +struct Greenpak4DffInvPass : public Pass { + Greenpak4DffInvPass() : Pass("greenpak4_dffinv", "merge greenpak4 inverters and DFFs") { } + virtual void help() + { + log("\n"); + log(" greenpak4_dffinv [options] [selection]\n"); + log("\n"); + log("Merge GP_INV cells with GP_DFF* cells.\n"); + log("\n"); + } + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + { + log_header(design, "Executing GREENPAK4_DFFINV pass (merge synchronous set/reset into FF cells).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-singleton") { + // singleton_mode = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + pool<IdString> gp_dff_types; + gp_dff_types.insert("\\GP_DFF"); + gp_dff_types.insert("\\GP_DFFI"); + gp_dff_types.insert("\\GP_DFFR"); + gp_dff_types.insert("\\GP_DFFRI"); + gp_dff_types.insert("\\GP_DFFS"); + gp_dff_types.insert("\\GP_DFFSI"); + gp_dff_types.insert("\\GP_DFFSR"); + gp_dff_types.insert("\\GP_DFFSRI"); + + for (auto module : design->selected_modules()) + { + SigMap sigmap(module); + dict<SigBit, int> sig_use_cnt; + dict<SigBit, SigBit> inv_in2out, inv_out2in; + dict<SigBit, Cell*> inv_in2cell; + pool<Cell*> dff_cells; + + for (auto wire : module->wires()) + { + if (!wire->port_output) + continue; + + for (auto bit : sigmap(wire)) + sig_use_cnt[bit]++; + } + + for (auto cell : module->cells()) + for (auto &conn : cell->connections()) + if (cell->input(conn.first) || !cell->known()) + for (auto bit : sigmap(conn.second)) + sig_use_cnt[bit]++; + + for (auto cell : module->selected_cells()) + { + if (gp_dff_types.count(cell->type)) { + dff_cells.insert(cell); + continue; + } + + if (cell->type == "\\GP_INV") { + SigBit in_bit = sigmap(cell->getPort("\\IN")); + SigBit out_bit = sigmap(cell->getPort("\\OUT")); + inv_in2out[in_bit] = out_bit; + inv_out2in[out_bit] = in_bit; + inv_in2cell[in_bit] = cell; + continue; + } + } + + for (auto cell : dff_cells) + { + SigBit d_bit = sigmap(cell->getPort("\\D")); + SigBit q_bit = sigmap(cell->hasPort("\\Q") ? cell->getPort("\\Q") : cell->getPort("\\nQ")); + + while (inv_out2in.count(d_bit)) + { + sig_use_cnt[d_bit]--; + invert_gp_dff(cell, true); + d_bit = inv_out2in.at(d_bit); + cell->setPort("\\D", d_bit); + sig_use_cnt[d_bit]++; + } + + while (inv_in2out.count(q_bit) && sig_use_cnt[q_bit] == 1) + { + SigBit new_q_bit = inv_in2out.at(q_bit); + module->remove(inv_in2cell.at(q_bit)); + sig_use_cnt.erase(q_bit); + inv_in2out.erase(q_bit); + inv_out2in.erase(new_q_bit); + inv_in2cell.erase(q_bit); + + invert_gp_dff(cell, false); + if (cell->hasPort("\\Q")) + cell->setPort("\\Q", new_q_bit); + else + cell->setPort("\\nQ", new_q_bit); + } + } + } + } +} Greenpak4DffInvPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/greenpak4/synth_greenpak4.cc b/techlibs/greenpak4/synth_greenpak4.cc index 15b53d62..10e2a149 100644 --- a/techlibs/greenpak4/synth_greenpak4.cc +++ b/techlibs/greenpak4/synth_greenpak4.cc @@ -25,18 +25,11 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -bool check_label(bool &active, std::string run_from, std::string run_to, std::string label) +struct SynthGreenPAK4Pass : public ScriptPass { - if (label == run_from) - active = true; - if (label == run_to) - active = false; - return active; -} - -struct SynthGreenPAK4Pass : public Pass { - SynthGreenPAK4Pass() : Pass("synth_greenpak4", "synthesis for GreenPAK4 FPGAs") { } - virtual void help() + SynthGreenPAK4Pass() : ScriptPass("synth_greenpak4", "synthesis for GreenPAK4 FPGAs") { } + + virtual void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -47,12 +40,12 @@ struct SynthGreenPAK4Pass : public Pass { log(" -top <module>\n"); log(" use the specified module as top module (default='top')\n"); log("\n"); - log(" -blif <file>\n"); - log(" write the design to the specified BLIF file. writing of an output file\n"); - log(" is omitted if this parameter is not specified.\n"); + log(" -part <part>\n"); + log(" synthesize for the specified part. Valid values are SLG46140V,\n"); + log(" SLG46620V, and SLG46621V (default).\n"); log("\n"); - log(" -edif <file>\n"); - log(" write the design to the specified edif file. writing of an output file\n"); + log(" -json <file>\n"); + log(" write the design to the specified JSON file. writing of an output file\n"); log(" is omitted if this parameter is not specified.\n"); log("\n"); log(" -run <from_label>:<to_label>\n"); @@ -68,55 +61,26 @@ struct SynthGreenPAK4Pass : public Pass { log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); + help_script(); log("\n"); - log(" begin:\n"); - log(" read_verilog -lib +/greenpak4/cells_sim.v\n"); - log(" hierarchy -check -top <top>\n"); - log("\n"); - log(" flatten: (unless -noflatten)\n"); - log(" proc\n"); - log(" flatten\n"); - log(" tribuf -logic\n"); - log("\n"); - log(" coarse:\n"); - log(" synth -run coarse\n"); - log("\n"); - log(" fine:\n"); - log(" opt -fast -mux_undef -undriven -fine\n"); - log(" memory_map\n"); - log(" opt -undriven -fine\n"); - log(" techmap\n"); - log(" dfflibmap -prepare -liberty +/greenpak4/gp_dff.lib\n"); - log(" opt -fast\n"); - log(" abc -dff (only if -retime)\n"); - log("\n"); - log(" map_luts:\n"); - log(" nlutmap -luts 0,8,16,2\n"); - log(" clean\n"); - log("\n"); - log(" map_cells:\n"); - log(" techmap -map +/greenpak4/cells_map.v\n"); - log(" clean\n"); - log("\n"); - log(" check:\n"); - log(" hierarchy -check\n"); - log(" stat\n"); - log(" check -noinit\n"); - log("\n"); - log(" blif:\n"); - log(" write_blif -gates -attr -param <file-name>\n"); - log("\n"); - log(" edif:\n"); - log(" write_edif <file-name>\n"); - log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + + string top_opt, part, json_file; + bool flatten, retime; + + virtual void clear_flags() YS_OVERRIDE + { + top_opt = "-auto-top"; + part = "SLG46621V"; + json_file = ""; + flatten = true; + retime = false; + } + + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { - std::string top_opt = "-auto-top"; - std::string run_from, run_to; - std::string blif_file, edif_file; - bool flatten = true; - bool retime = false; + string run_from, run_to; + clear_flags(); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -125,12 +89,12 @@ struct SynthGreenPAK4Pass : public Pass { top_opt = "-top " + args[++argidx]; continue; } - if (args[argidx] == "-blif" && argidx+1 < args.size()) { - blif_file = args[++argidx]; + if (args[argidx] == "-json" && argidx+1 < args.size()) { + json_file = args[++argidx]; continue; } - if (args[argidx] == "-edif" && argidx+1 < args.size()) { - edif_file = args[++argidx]; + if (args[argidx] == "-part" && argidx+1 < args.size()) { + part = args[++argidx]; continue; } if (args[argidx] == "-run" && argidx+1 < args.size()) { @@ -141,10 +105,6 @@ struct SynthGreenPAK4Pass : public Pass { run_to = args[argidx].substr(pos+1); continue; } - if (args[argidx] == "-flatten") { - flatten = true; - continue; - } if (args[argidx] == "-noflatten") { flatten = false; continue; @@ -160,70 +120,86 @@ struct SynthGreenPAK4Pass : public Pass { if (!design->full_selection()) log_cmd_error("This comannd only operates on fully selected designs!\n"); - bool active = run_from.empty(); + if (part != "SLG46140V" && part != "SLG46620V" && part != "SLG46621V") + log_cmd_error("Invalid part name: '%s'\n", part.c_str()); - log_header("Executing SYNTH_GREENPAK4 pass.\n"); + log_header(design, "Executing SYNTH_GREENPAK4 pass.\n"); log_push(); - if (check_label(active, run_from, run_to, "begin")) - { - Pass::call(design, "read_verilog -lib +/greenpak4/cells_sim.v"); - Pass::call(design, stringf("hierarchy -check %s", top_opt.c_str())); - } + run_script(design, run_from, run_to); + + log_pop(); + } - if (flatten && check_label(active, run_from, run_to, "flatten")) + virtual void script() YS_OVERRIDE + { + if (check_label("begin")) { - Pass::call(design, "proc"); - Pass::call(design, "flatten"); - Pass::call(design, "tribuf -logic"); + run("read_verilog -lib +/greenpak4/cells_sim.v"); + run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str())); } - if (check_label(active, run_from, run_to, "coarse")) + if (flatten && check_label("flatten", "(unless -noflatten)")) { - Pass::call(design, "synth -run coarse"); + run("proc"); + run("flatten"); + run("tribuf -logic"); } - if (check_label(active, run_from, run_to, "fine")) + if (check_label("coarse")) { - Pass::call(design, "opt -fast -mux_undef -undriven -fine"); - Pass::call(design, "memory_map"); - Pass::call(design, "opt -undriven -fine"); - Pass::call(design, "techmap"); - Pass::call(design, "dfflibmap -prepare -liberty +/greenpak4/gp_dff.lib"); - Pass::call(design, "opt -fast"); - if (retime) - Pass::call(design, "abc -dff"); + run("synth -run coarse"); } - if (check_label(active, run_from, run_to, "map_luts")) + if (check_label("fine")) { - Pass::call(design, "nlutmap -luts 0,8,16,2"); - Pass::call(design, "clean"); + run("greenpak4_counters"); + run("clean"); + run("opt -fast -mux_undef -undriven -fine"); + run("memory_map"); + run("opt -undriven -fine"); + run("techmap"); + run("dfflibmap -prepare -liberty +/greenpak4/gp_dff.lib"); + run("opt -fast"); + if (retime || help_mode) + run("abc -dff", "(only if -retime)"); } - if (check_label(active, run_from, run_to, "map_cells")) + if (check_label("map_luts")) { - Pass::call(design, "techmap -map +/greenpak4/cells_map.v"); - Pass::call(design, "clean"); + if (help_mode || part == "SLG46140V") run("nlutmap -assert -luts 0,6,8,2", " (for -part SLG46140V)"); + if (help_mode || part == "SLG46620V") run("nlutmap -assert -luts 2,8,16,2", "(for -part SLG46620V)"); + if (help_mode || part == "SLG46621V") run("nlutmap -assert -luts 2,8,16,2", "(for -part SLG46621V)"); + run("clean"); } - if (check_label(active, run_from, run_to, "check")) + if (check_label("map_cells")) { - Pass::call(design, "hierarchy -check"); - Pass::call(design, "stat"); - Pass::call(design, "check -noinit"); + run("shregmap -tech greenpak4"); + run("dfflibmap -liberty +/greenpak4/gp_dff.lib"); + run("dffinit -ff GP_DFF Q INIT"); + run("dffinit -ff GP_DFFR Q INIT"); + run("dffinit -ff GP_DFFS Q INIT"); + run("dffinit -ff GP_DFFSR Q INIT"); + run("iopadmap -bits -inpad GP_IBUF OUT:IN -outpad GP_OBUF IN:OUT -inoutpad GP_OBUF OUT:IN -toutpad GP_OBUFT OE:IN:OUT -tinoutpad GP_IOBUF OE:OUT:IN:IO"); + run("attrmvcp -attr src -attr LOC t:GP_OBUF t:GP_OBUFT t:GP_IOBUF n:*"); + run("attrmvcp -attr src -attr LOC -driven t:GP_IBUF n:*"); + run("techmap -map +/greenpak4/cells_map.v"); + run("greenpak4_dffinv"); + run("clean"); } - if (check_label(active, run_from, run_to, "blif")) + if (check_label("check")) { - if (!blif_file.empty()) - Pass::call(design, stringf("write_blif -gates -attr -param %s", blif_file.c_str())); + run("hierarchy -check"); + run("stat"); + run("check -noinit"); } - if (check_label(active, run_from, run_to, "edif")) + if (check_label("json")) { - if (!edif_file.empty()) - Pass::call(design, stringf("write_edif %s", edif_file.c_str())); + if (!json_file.empty() || help_mode) + run(stringf("write_json %s", help_mode ? "<file-name>" : json_file.c_str())); } log_pop(); diff --git a/techlibs/ice40/Makefile.inc b/techlibs/ice40/Makefile.inc index 83009d17..14761c6c 100644 --- a/techlibs/ice40/Makefile.inc +++ b/techlibs/ice40/Makefile.inc @@ -23,6 +23,7 @@ techlibs/ice40/brams_init3.vh: techlibs/ice40/brams_init.mk $(eval $(call add_share_file,share/ice40,techlibs/ice40/arith_map.v)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_map.v)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_sim.v)) +$(eval $(call add_share_file,share/ice40,techlibs/ice40/latches_map.v)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/brams.txt)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/brams_map.v)) diff --git a/techlibs/ice40/ice40_ffinit.cc b/techlibs/ice40/ice40_ffinit.cc index 8c4b9a37..c914b20e 100644 --- a/techlibs/ice40/ice40_ffinit.cc +++ b/techlibs/ice40/ice40_ffinit.cc @@ -37,7 +37,7 @@ struct Ice40FfinitPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing ICE40_FFINIT pass (implement FF init values).\n"); + log_header(design, "Executing ICE40_FFINIT pass (implement FF init values).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -57,6 +57,7 @@ struct Ice40FfinitPass : public Pass { SigMap sigmap(module); pool<Wire*> init_wires; dict<SigBit, State> initbits; + dict<SigBit, SigBit> initbit_to_wire; pool<SigBit> handled_initbits; for (auto wire : module->selected_wires()) @@ -78,11 +79,14 @@ struct Ice40FfinitPass : public Pass { if (initbits.count(bit)) { if (initbits.at(bit) != val) - log_error("Conflicting init values for signal %s.\n", log_signal(bit)); + log_error("Conflicting init values for signal %s (%s = %s, %s = %s).\n", + log_signal(bit), log_signal(SigBit(wire, i)), log_signal(val), + log_signal(initbit_to_wire[bit]), log_signal(initbits.at(bit))); continue; } initbits[bit] = val; + initbit_to_wire[bit] = SigBit(wire, i); } } @@ -97,17 +101,23 @@ struct Ice40FfinitPass : public Pass { if (!sb_dff_types.count(cell->type)) continue; - SigBit sig_d = sigmap(cell->getPort("\\D")); - SigBit sig_q = sigmap(cell->getPort("\\Q")); + SigSpec sig_d = cell->getPort("\\D"); + SigSpec sig_q = cell->getPort("\\Q"); - if (!initbits.count(sig_q)) + if (GetSize(sig_d) < 1 || GetSize(sig_q) < 1) continue; - State val = initbits.at(sig_q); - handled_initbits.insert(sig_q); + SigBit bit_d = sigmap(sig_d[0]); + SigBit bit_q = sigmap(sig_q[0]); + + if (!initbits.count(bit_q)) + continue; + + State val = initbits.at(bit_q); + handled_initbits.insert(bit_q); log("FF init value for cell %s (%s): %s = %c\n", log_id(cell), log_id(cell->type), - log_signal(sig_q), val != State::S0 ? '1' : '0'); + log_signal(bit_q), val != State::S0 ? '1' : '0'); if (val == State::S0) continue; @@ -127,14 +137,14 @@ struct Ice40FfinitPass : public Pass { cell->unsetPort("\\R"); } - Wire *new_sig_d = module->addWire(NEW_ID); - Wire *new_sig_q = module->addWire(NEW_ID); + Wire *new_bit_d = module->addWire(NEW_ID); + Wire *new_bit_q = module->addWire(NEW_ID); - module->addNotGate(NEW_ID, sig_d, new_sig_d); - module->addNotGate(NEW_ID, new_sig_q, sig_q); + module->addNotGate(NEW_ID, bit_d, new_bit_d); + module->addNotGate(NEW_ID, new_bit_q, bit_q); - cell->setPort("\\D", new_sig_d); - cell->setPort("\\Q", new_sig_q); + cell->setPort("\\D", new_bit_d); + cell->setPort("\\Q", new_bit_q); } for (auto wire : init_wires) diff --git a/techlibs/ice40/ice40_ffssr.cc b/techlibs/ice40/ice40_ffssr.cc index 9ebc3c0d..9afbc0fc 100644 --- a/techlibs/ice40/ice40_ffssr.cc +++ b/techlibs/ice40/ice40_ffssr.cc @@ -35,7 +35,7 @@ struct Ice40FfssrPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing ICE40_FFSSR pass (merge synchronous set/reset into FF cells).\n"); + log_header(design, "Executing ICE40_FFSSR pass (merge synchronous set/reset into FF cells).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -81,7 +81,12 @@ struct Ice40FfssrPass : public Pass { for (auto cell : ff_cells) { - SigBit bit_d = sigmap(cell->getPort("\\D")); + SigSpec sig_d = cell->getPort("\\D"); + + if (GetSize(sig_d) < 1) + continue; + + SigBit bit_d = sigmap(sig_d[0]); if (sr_muxes.count(bit_d) == 0) continue; diff --git a/techlibs/ice40/ice40_opt.cc b/techlibs/ice40/ice40_opt.cc index 677ac8d7..ae72f5d6 100644 --- a/techlibs/ice40/ice40_opt.cc +++ b/techlibs/ice40/ice40_opt.cc @@ -26,7 +26,7 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -static void run_ice40_opts(Module *module) +static void run_ice40_opts(Module *module, bool unlut_mode) { pool<SigBit> optimized_co; vector<Cell*> sb_lut_cells; @@ -84,6 +84,9 @@ static void run_ice40_opts(Module *module) inbits.append(cell->getPort("\\I3")); sigmap.apply(inbits); + if (unlut_mode) + goto remap_lut; + if (optimized_co.count(inbits[0])) goto remap_lut; if (optimized_co.count(inbits[1])) goto remap_lut; if (optimized_co.count(inbits[2])) goto remap_lut; @@ -101,7 +104,7 @@ static void run_ice40_opts(Module *module) cell->setParam("\\LUT", cell->getParam("\\LUT_INIT")); cell->unsetParam("\\LUT_INIT"); - cell->setPort("\\A", SigSpec({cell->getPort("\\I0"), cell->getPort("\\I1"), cell->getPort("\\I2"), cell->getPort("\\I3")})); + cell->setPort("\\A", SigSpec({cell->getPort("\\I3"), cell->getPort("\\I2"), cell->getPort("\\I1"), cell->getPort("\\I0")})); cell->setPort("\\Y", cell->getPort("\\O")); cell->unsetPort("\\I0"); cell->unsetPort("\\I1"); @@ -127,23 +130,32 @@ struct Ice40OptPass : public Pass { log("\n"); log(" do\n"); log(" <ice40 specific optimizations>\n"); - log(" opt_const -mux_undef -undriven [-full]\n"); - log(" opt_share\n"); + log(" opt_expr -mux_undef -undriven [-full]\n"); + log(" opt_merge\n"); log(" opt_rmdff\n"); log(" opt_clean\n"); log(" while <changed design>\n"); log("\n"); + log("When called with the option -unlut, this command will transform all already\n"); + log("mapped SB_LUT4 cells back to logic.\n"); + log("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - string opt_const_args = "-mux_undef -undriven"; - log_header("Executing ICE40_OPT pass (performing simple optimizations).\n"); + string opt_expr_args = "-mux_undef -undriven"; + bool unlut_mode = false; + + log_header(design, "Executing ICE40_OPT pass (performing simple optimizations).\n"); log_push(); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { if (args[argidx] == "-full") { - opt_const_args += " -full"; + opt_expr_args += " -full"; + continue; + } + if (args[argidx] == "-unlut") { + unlut_mode = true; continue; } break; @@ -154,26 +166,26 @@ struct Ice40OptPass : public Pass { { design->scratchpad_unset("opt.did_something"); - log_header("Running ICE40 specific optimizations.\n"); + log_header(design, "Running ICE40 specific optimizations.\n"); for (auto module : design->selected_modules()) - run_ice40_opts(module); + run_ice40_opts(module, unlut_mode); - Pass::call(design, "opt_const " + opt_const_args); - Pass::call(design, "opt_share"); + Pass::call(design, "opt_expr " + opt_expr_args); + Pass::call(design, "opt_merge"); Pass::call(design, "opt_rmdff"); Pass::call(design, "opt_clean"); if (design->scratchpad_get_bool("opt.did_something") == false) break; - log_header("Rerunning OPT passes. (Removed registers in this run.)\n"); + log_header(design, "Rerunning OPT passes. (Removed registers in this run.)\n"); } design->optimize(); design->sort(); design->check(); - log_header("Finished OPT passes. (There is nothing left to do.)\n"); + log_header(design, "Finished OPT passes. (There is nothing left to do.)\n"); log_pop(); } } Ice40OptPass; diff --git a/techlibs/ice40/latches_map.v b/techlibs/ice40/latches_map.v new file mode 100644 index 00000000..c28f88cf --- /dev/null +++ b/techlibs/ice40/latches_map.v @@ -0,0 +1,11 @@ +module \$_DLATCH_N_ (E, D, Q); + wire [1023:0] _TECHMAP_DO_ = "simplemap; opt"; + input E, D; + output Q = !E ? D : Q; +endmodule + +module \$_DLATCH_P_ (E, D, Q); + wire [1023:0] _TECHMAP_DO_ = "simplemap; opt"; + input E, D; + output Q = E ? D : Q; +endmodule diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index 92d53f4a..38a9cf9d 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -25,18 +25,11 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -bool check_label(bool &active, std::string run_from, std::string run_to, std::string label) +struct SynthIce40Pass : public ScriptPass { - if (label == run_from) - active = true; - if (label == run_to) - active = false; - return active; -} + SynthIce40Pass() : ScriptPass("synth_ice40", "synthesis for iCE40 FPGAs") { } -struct SynthIce40Pass : public Pass { - SynthIce40Pass() : Pass("synth_ice40", "synthesis for iCE40 FPGAs") { } - virtual void help() + virtual void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -77,73 +70,29 @@ struct SynthIce40Pass : public Pass { log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); + help_script(); log("\n"); - log(" begin:\n"); - log(" read_verilog -lib +/ice40/cells_sim.v\n"); - log(" hierarchy -check -top <top>\n"); - log("\n"); - log(" flatten: (unless -noflatten)\n"); - log(" proc\n"); - log(" flatten\n"); - log(" tribuf -logic\n"); - log("\n"); - log(" coarse:\n"); - log(" synth -run coarse\n"); - log("\n"); - log(" bram: (skip if -nobram)\n"); - log(" memory_bram -rules +/ice40/brams.txt\n"); - log(" techmap -map +/ice40/brams_map.v\n"); - log("\n"); - log(" fine:\n"); - log(" opt -fast -mux_undef -undriven -fine\n"); - log(" memory_map\n"); - log(" opt -undriven -fine\n"); - log(" techmap -map +/techmap.v [-map +/ice40/arith_map.v]\n"); - log(" abc -dff (only if -retime)\n"); - log(" ice40_opt\n"); - log("\n"); - log(" map_ffs:\n"); - log(" dffsr2dff\n"); - log(" dff2dffe -direct-match $_DFF_*\n"); - log(" techmap -map +/ice40/cells_map.v\n"); - log(" opt_const -mux_undef\n"); - log(" simplemap\n"); - log(" ice40_ffinit\n"); - log(" ice40_ffssr\n"); - log(" ice40_opt -full\n"); - log("\n"); - log(" map_luts:\n"); - log(" abc (only if -abc2)\n"); - log(" ice40_opt (only if -abc2)\n"); - log(" abc -lut 4\n"); - log(" clean\n"); - log("\n"); - log(" map_cells:\n"); - log(" techmap -map +/ice40/cells_map.v\n"); - log(" clean\n"); - log("\n"); - log(" check:\n"); - log(" hierarchy -check\n"); - log(" stat\n"); - log(" check -noinit\n"); - log("\n"); - log(" blif:\n"); - log(" write_blif -gates -attr -param <file-name>\n"); - log("\n"); - log(" edif:\n"); - log(" write_edif <file-name>\n"); - log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + + string top_opt, blif_file, edif_file; + bool nocarry, nobram, flatten, retime, abc2; + + virtual void clear_flags() YS_OVERRIDE + { + top_opt = "-auto-top"; + blif_file = ""; + edif_file = ""; + nocarry = false; + nobram = false; + flatten = true; + retime = false; + abc2 = false; + } + + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { - std::string top_opt = "-auto-top"; - std::string run_from, run_to; - std::string blif_file, edif_file; - bool nocarry = false; - bool nobram = false; - bool flatten = true; - bool retime = false; - bool abc2 = false; + string run_from, run_to; + clear_flags(); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -199,97 +148,102 @@ struct SynthIce40Pass : public Pass { if (!design->full_selection()) log_cmd_error("This comannd only operates on fully selected designs!\n"); - bool active = run_from.empty(); - - log_header("Executing SYNTH_ICE40 pass.\n"); + log_header(design, "Executing SYNTH_ICE40 pass.\n"); log_push(); - if (check_label(active, run_from, run_to, "begin")) + run_script(design, run_from, run_to); + + log_pop(); + } + + virtual void script() YS_OVERRIDE + { + if (check_label("begin")) { - Pass::call(design, "read_verilog -lib +/ice40/cells_sim.v"); - Pass::call(design, stringf("hierarchy -check %s", top_opt.c_str())); + run("read_verilog -lib +/ice40/cells_sim.v"); + run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str())); } - if (flatten && check_label(active, run_from, run_to, "flatten")) + if (flatten && check_label("flatten", "(unless -noflatten)")) { - Pass::call(design, "proc"); - Pass::call(design, "flatten"); - Pass::call(design, "tribuf -logic"); + run("proc"); + run("flatten"); + run("tribuf -logic"); + run("deminout"); } - if (check_label(active, run_from, run_to, "coarse")) + if (check_label("coarse")) { - Pass::call(design, "synth -run coarse"); + run("synth -run coarse"); } - if (!nobram && check_label(active, run_from, run_to, "bram")) + if (!nobram && check_label("bram", "(skip if -nobram)")) { - Pass::call(design, "memory_bram -rules +/ice40/brams.txt"); - Pass::call(design, "techmap -map +/ice40/brams_map.v"); + run("memory_bram -rules +/ice40/brams.txt"); + run("techmap -map +/ice40/brams_map.v"); } - if (check_label(active, run_from, run_to, "fine")) + if (check_label("fine")) { - Pass::call(design, "opt -fast -mux_undef -undriven -fine"); - Pass::call(design, "memory_map"); - Pass::call(design, "opt -undriven -fine"); + run("opt -fast -mux_undef -undriven -fine"); + run("memory_map"); + run("opt -undriven -fine"); if (nocarry) - Pass::call(design, "techmap"); + run("techmap"); else - Pass::call(design, "techmap -map +/techmap.v -map +/ice40/arith_map.v"); - if (retime) - Pass::call(design, "abc -dff"); - Pass::call(design, "ice40_opt"); + run("techmap -map +/techmap.v -map +/ice40/arith_map.v"); + if (retime || help_mode) + run("abc -dff", "(only if -retime)"); + run("ice40_opt"); } - if (check_label(active, run_from, run_to, "map_ffs")) + if (check_label("map_ffs")) { - Pass::call(design, "dffsr2dff"); - Pass::call(design, "dff2dffe -direct-match $_DFF_*"); - Pass::call(design, "techmap -map +/ice40/cells_map.v"); - Pass::call(design, "opt_const -mux_undef"); - Pass::call(design, "simplemap"); - Pass::call(design, "ice40_ffinit"); - Pass::call(design, "ice40_ffssr"); - Pass::call(design, "ice40_opt -full"); + run("dffsr2dff"); + run("dff2dffe -direct-match $_DFF_*"); + run("techmap -map +/ice40/cells_map.v"); + run("opt_expr -mux_undef"); + run("simplemap"); + run("ice40_ffinit"); + run("ice40_ffssr"); + run("ice40_opt -full"); } - if (check_label(active, run_from, run_to, "map_luts")) + if (check_label("map_luts")) { - if (abc2) { - Pass::call(design, "abc"); - Pass::call(design, "ice40_opt"); + if (abc2 || help_mode) { + run("abc", " (only if -abc2)"); + run("ice40_opt", "(only if -abc2)"); } - Pass::call(design, "abc -lut 4"); - Pass::call(design, "clean"); + run("techmap -map +/ice40/latches_map.v"); + run("abc -lut 4"); + run("clean"); } - if (check_label(active, run_from, run_to, "map_cells")) + if (check_label("map_cells")) { - Pass::call(design, "techmap -map +/ice40/cells_map.v"); - Pass::call(design, "clean"); + run("techmap -map +/ice40/cells_map.v"); + run("clean"); } - if (check_label(active, run_from, run_to, "check")) + if (check_label("check")) { - Pass::call(design, "hierarchy -check"); - Pass::call(design, "stat"); - Pass::call(design, "check -noinit"); + run("hierarchy -check"); + run("stat"); + run("check -noinit"); } - if (check_label(active, run_from, run_to, "blif")) + if (check_label("blif")) { - if (!blif_file.empty()) - Pass::call(design, stringf("write_blif -gates -attr -param %s", blif_file.c_str())); + if (!blif_file.empty() || help_mode) + run(stringf("write_blif -gates -attr -param %s", help_mode ? "<file-name>" : blif_file.c_str())); } - if (check_label(active, run_from, run_to, "edif")) + if (check_label("edif")) { - if (!edif_file.empty()) - Pass::call(design, stringf("write_edif %s", edif_file.c_str())); + if (!edif_file.empty() || help_mode) + run(stringf("write_edif %s", help_mode ? "<file-name>" : edif_file.c_str())); } - - log_pop(); } } SynthIce40Pass; diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc index ccf88ec7..5f09ffb0 100644 --- a/techlibs/xilinx/Makefile.inc +++ b/techlibs/xilinx/Makefile.inc @@ -21,6 +21,7 @@ techlibs/xilinx/brams_init_16.vh: techlibs/xilinx/brams_init.mk $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_sim.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_xtra.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams.txt)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_bb.v)) diff --git a/techlibs/xilinx/cells_xtra.sh b/techlibs/xilinx/cells_xtra.sh new file mode 100644 index 00000000..c7ad1604 --- /dev/null +++ b/techlibs/xilinx/cells_xtra.sh @@ -0,0 +1,145 @@ +#!/bin/bash + +set -e +libdir="/opt/Xilinx/Vivado/2015.4/data/verilog/src" + +function xtract_cell_decl() +{ + for dir in $libdir/xeclib $libdir/retarget; do + [ -f $dir/$1.v ] || continue + egrep '^\s*((end)?module|parameter|input|output|(end)?function|(end)?task)' $dir/$1.v | + sed -re '/UNPLACED/ d; /^\s*function/,/endfunction/ d; /^\s*task/,/endtask/ d; + s,//.*,,; s/#?\(.*/(...);/; s/^(input|output|parameter)/ \1/; + s/\s+$//; s/,$/;/; /input|output|parameter/ s/[^;]$/&;/; s/\s+/ /g; + s/^ ((end)?module)/\1/; s/^ / /; /module.*_bb/,/endmodule/ d;' + echo; return + done + echo "Can't find $1." + exit 1 +} + +{ + echo "// Created by cells_xtra.sh from Xilinx models" + echo + + # Design elements types listed in Xilinx UG953 + xtract_cell_decl BSCANE2 + # xtract_cell_decl BUFG + xtract_cell_decl BUFGCE + xtract_cell_decl BUFGCE_1 + xtract_cell_decl BUFGCTRL + xtract_cell_decl BUFGMUX + xtract_cell_decl BUFGMUX_1 + xtract_cell_decl BUFGMUX_CTRL + xtract_cell_decl BUFH + xtract_cell_decl BUFHCE + xtract_cell_decl BUFIO + xtract_cell_decl BUFMR + xtract_cell_decl BUFMRCE + xtract_cell_decl BUFR + xtract_cell_decl CAPTUREE2 + # xtract_cell_decl CARRY4 + xtract_cell_decl CFGLUT5 + xtract_cell_decl DCIRESET + xtract_cell_decl DNA_PORT + xtract_cell_decl DSP48E1 + xtract_cell_decl EFUSE_USR + # xtract_cell_decl FDCE + # xtract_cell_decl FDPE + # xtract_cell_decl FDRE + # xtract_cell_decl FDSE + xtract_cell_decl FIFO18E1 + xtract_cell_decl FIFO36E1 + xtract_cell_decl FRAME_ECCE2 + xtract_cell_decl GTHE2_CHANNEL + xtract_cell_decl GTHE2_COMMON + xtract_cell_decl GTPE2_CHANNEL + xtract_cell_decl GTPE2_COMMON + xtract_cell_decl GTXE2_CHANNEL + xtract_cell_decl GTXE2_COMMON + # xtract_cell_decl IBUF + xtract_cell_decl IBUF_IBUFDISABLE + xtract_cell_decl IBUF_INTERMDISABLE + xtract_cell_decl IBUFDS + xtract_cell_decl IBUFDS_DIFF_OUT + xtract_cell_decl IBUFDS_DIFF_OUT_IBUFDISABLE + xtract_cell_decl IBUFDS_DIFF_OUT_INTERMDISABLE + xtract_cell_decl IBUFDS_GTE2 + xtract_cell_decl IBUFDS_IBUFDISABLE + xtract_cell_decl IBUFDS_INTERMDISABLE + xtract_cell_decl ICAPE2 + xtract_cell_decl IDDR + xtract_cell_decl IDDR_2CLK + xtract_cell_decl IDELAYCTRL + xtract_cell_decl IDELAYE2 + xtract_cell_decl IN_FIFO + xtract_cell_decl IOBUF + xtract_cell_decl IOBUF_DCIEN + xtract_cell_decl IOBUF_INTERMDISABLE + xtract_cell_decl IOBUFDS + xtract_cell_decl IOBUFDS_DCIEN + xtract_cell_decl IOBUFDS_DIFF_OUT + xtract_cell_decl IOBUFDS_DIFF_OUT_DCIEN + xtract_cell_decl IOBUFDS_DIFF_OUT_INTERMDISABLE + xtract_cell_decl ISERDESE2 + xtract_cell_decl KEEPER + xtract_cell_decl LDCE + xtract_cell_decl LDPE + # xtract_cell_decl LUT1 + # xtract_cell_decl LUT2 + # xtract_cell_decl LUT3 + # xtract_cell_decl LUT4 + # xtract_cell_decl LUT5 + # xtract_cell_decl LUT6 + xtract_cell_decl LUT6_2 + xtract_cell_decl MMCME2_ADV + xtract_cell_decl MMCME2_BASE + # xtract_cell_decl MUXF7 + # xtract_cell_decl MUXF8 + # xtract_cell_decl OBUF + xtract_cell_decl OBUFDS + xtract_cell_decl OBUFT + xtract_cell_decl OBUFTDS + xtract_cell_decl ODDR + xtract_cell_decl ODELAYE2 + xtract_cell_decl OSERDESE2 + xtract_cell_decl OUT_FIFO + xtract_cell_decl PHASER_IN + xtract_cell_decl PHASER_IN_PHY + xtract_cell_decl PHASER_OUT + xtract_cell_decl PHASER_OUT_PHY + xtract_cell_decl PHASER_REF + xtract_cell_decl PHY_CONTROL + xtract_cell_decl PLLE2_ADV + xtract_cell_decl PLLE2_BASE + xtract_cell_decl PULLDOWN + xtract_cell_decl PULLUP + # xtract_cell_decl RAM128X1D + xtract_cell_decl RAM128X1S + xtract_cell_decl RAM256X1S + xtract_cell_decl RAM32M + xtract_cell_decl RAM32X1D + xtract_cell_decl RAM32X1S + xtract_cell_decl RAM32X1S_1 + xtract_cell_decl RAM32X2S + xtract_cell_decl RAM64M + # xtract_cell_decl RAM64X1D + xtract_cell_decl RAM64X1S + xtract_cell_decl RAM64X1S_1 + xtract_cell_decl RAM64X2S + # xtract_cell_decl RAMB18E1 + # xtract_cell_decl RAMB36E1 + xtract_cell_decl ROM128X1 + xtract_cell_decl ROM256X1 + xtract_cell_decl ROM32X1 + xtract_cell_decl ROM64X1 + xtract_cell_decl SRL16E + xtract_cell_decl SRLC32E + xtract_cell_decl STARTUPE2 + xtract_cell_decl USR_ACCESSE2 + xtract_cell_decl XADC +} > cells_xtra.new + +mv cells_xtra.new cells_xtra.v +exit 0 + diff --git a/techlibs/xilinx/cells_xtra.v b/techlibs/xilinx/cells_xtra.v new file mode 100644 index 00000000..a2dd01ad --- /dev/null +++ b/techlibs/xilinx/cells_xtra.v @@ -0,0 +1,3293 @@ +// Created by cells_xtra.sh from Xilinx models + +module BSCANE2 (...); + parameter DISABLE_JTAG = "FALSE"; + parameter integer JTAG_CHAIN = 1; + output CAPTURE; + output DRCK; + output RESET; + output RUNTEST; + output SEL; + output SHIFT; + output TCK; + output TDI; + output TMS; + output UPDATE; + input TDO; +endmodule + +module BUFGCE (...); + parameter CE_TYPE = "SYNC"; + parameter [0:0] IS_CE_INVERTED = 1'b0; + parameter [0:0] IS_I_INVERTED = 1'b0; + output O; + input CE; + input I; +endmodule + +module BUFGCE_1 (...); + output O; + input CE, I; +endmodule + +module BUFGCTRL (...); + output O; + input CE0; + input CE1; + input I0; + input I1; + input IGNORE0; + input IGNORE1; + input S0; + input S1; + parameter integer INIT_OUT = 0; + parameter PRESELECT_I0 = "FALSE"; + parameter PRESELECT_I1 = "FALSE"; + parameter [0:0] IS_CE0_INVERTED = 1'b0; + parameter [0:0] IS_CE1_INVERTED = 1'b0; + parameter [0:0] IS_I0_INVERTED = 1'b0; + parameter [0:0] IS_I1_INVERTED = 1'b0; + parameter [0:0] IS_IGNORE0_INVERTED = 1'b0; + parameter [0:0] IS_IGNORE1_INVERTED = 1'b0; + parameter [0:0] IS_S0_INVERTED = 1'b0; + parameter [0:0] IS_S1_INVERTED = 1'b0; +endmodule + +module BUFGMUX (...); + parameter CLK_SEL_TYPE = "SYNC"; + output O; + input I0, I1, S; +endmodule + +module BUFGMUX_1 (...); + parameter CLK_SEL_TYPE = "SYNC"; + output O; + input I0, I1, S; +endmodule + +module BUFGMUX_CTRL (...); + output O; + input I0; + input I1; + input S; +endmodule + +module BUFH (...); + output O; + input I; +endmodule + +module BUFHCE (...); + parameter CE_TYPE = "SYNC"; + parameter integer INIT_OUT = 0; + parameter [0:0] IS_CE_INVERTED = 1'b0; + output O; + input CE; + input I; +endmodule + +module BUFIO (...); + output O; + input I; +endmodule + +module BUFMR (...); + output O; + input I; +endmodule + +module BUFMRCE (...); + parameter CE_TYPE = "SYNC"; + parameter integer INIT_OUT = 0; + parameter [0:0] IS_CE_INVERTED = 1'b0; + output O; + input CE; + input I; +endmodule + +module BUFR (...); + output O; + input CE; + input CLR; + input I; + parameter BUFR_DIVIDE = "BYPASS"; + parameter SIM_DEVICE = "7SERIES"; +endmodule + +module CAPTUREE2 (...); + parameter ONESHOT = "TRUE"; + input CAP; + input CLK; +endmodule + +module CFGLUT5 (...); + parameter [31:0] INIT = 32'h00000000; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + output CDO; + output O5; + output O6; + input I4, I3, I2, I1, I0; + input CDI, CE, CLK; +endmodule + +module DCIRESET (...); + output LOCKED; + input RST; +endmodule + +module DNA_PORT (...); + parameter [56:0] SIM_DNA_VALUE = 57'h0; + output DOUT; + input CLK, DIN, READ, SHIFT; +endmodule + +module DSP48E1 (...); + parameter integer ACASCREG = 1; + parameter integer ADREG = 1; + parameter integer ALUMODEREG = 1; + parameter integer AREG = 1; + parameter AUTORESET_PATDET = "NO_RESET"; + parameter A_INPUT = "DIRECT"; + parameter integer BCASCREG = 1; + parameter integer BREG = 1; + parameter B_INPUT = "DIRECT"; + parameter integer CARRYINREG = 1; + parameter integer CARRYINSELREG = 1; + parameter integer CREG = 1; + parameter integer DREG = 1; + parameter integer INMODEREG = 1; + parameter integer MREG = 1; + parameter integer OPMODEREG = 1; + parameter integer PREG = 1; + parameter SEL_MASK = "MASK"; + parameter SEL_PATTERN = "PATTERN"; + parameter USE_DPORT = "FALSE"; + parameter USE_MULT = "MULTIPLY"; + parameter USE_PATTERN_DETECT = "NO_PATDET"; + parameter USE_SIMD = "ONE48"; + parameter [47:0] MASK = 48'h3FFFFFFFFFFF; + parameter [47:0] PATTERN = 48'h000000000000; + parameter [3:0] IS_ALUMODE_INVERTED = 4'b0; + parameter [0:0] IS_CARRYIN_INVERTED = 1'b0; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + parameter [4:0] IS_INMODE_INVERTED = 5'b0; + parameter [6:0] IS_OPMODE_INVERTED = 7'b0; + output [29:0] ACOUT; + output [17:0] BCOUT; + output CARRYCASCOUT; + output [3:0] CARRYOUT; + output MULTSIGNOUT; + output OVERFLOW; + output [47:0] P; + output PATTERNBDETECT; + output PATTERNDETECT; + output [47:0] PCOUT; + output UNDERFLOW; + input [29:0] A; + input [29:0] ACIN; + input [3:0] ALUMODE; + input [17:0] B; + input [17:0] BCIN; + input [47:0] C; + input CARRYCASCIN; + input CARRYIN; + input [2:0] CARRYINSEL; + input CEA1; + input CEA2; + input CEAD; + input CEALUMODE; + input CEB1; + input CEB2; + input CEC; + input CECARRYIN; + input CECTRL; + input CED; + input CEINMODE; + input CEM; + input CEP; + input CLK; + input [24:0] D; + input [4:0] INMODE; + input MULTSIGNIN; + input [6:0] OPMODE; + input [47:0] PCIN; + input RSTA; + input RSTALLCARRYIN; + input RSTALUMODE; + input RSTB; + input RSTC; + input RSTCTRL; + input RSTD; + input RSTINMODE; + input RSTM; + input RSTP; +endmodule + +module EFUSE_USR (...); + parameter [31:0] SIM_EFUSE_VALUE = 32'h00000000; + output [31:0] EFUSEUSR; +endmodule + +module FIFO18E1 (...); + parameter ALMOST_EMPTY_OFFSET = 13'h0080; + parameter ALMOST_FULL_OFFSET = 13'h0080; + parameter integer DATA_WIDTH = 4; + parameter integer DO_REG = 1; + parameter EN_SYN = "FALSE"; + parameter FIFO_MODE = "FIFO18"; + parameter FIRST_WORD_FALL_THROUGH = "FALSE"; + parameter INIT = 36'h0; + parameter SIM_DEVICE = "VIRTEX6"; + parameter SRVAL = 36'h0; + parameter IS_RDCLK_INVERTED = 1'b0; + parameter IS_RDEN_INVERTED = 1'b0; + parameter IS_RSTREG_INVERTED = 1'b0; + parameter IS_RST_INVERTED = 1'b0; + parameter IS_WRCLK_INVERTED = 1'b0; + parameter IS_WREN_INVERTED = 1'b0; + output ALMOSTEMPTY; + output ALMOSTFULL; + output [31:0] DO; + output [3:0] DOP; + output EMPTY; + output FULL; + output [11:0] RDCOUNT; + output RDERR; + output [11:0] WRCOUNT; + output WRERR; + input [31:0] DI; + input [3:0] DIP; + input RDCLK; + input RDEN; + input REGCE; + input RST; + input RSTREG; + input WRCLK; + input WREN; +endmodule + +module FIFO36E1 (...); + parameter ALMOST_EMPTY_OFFSET = 13'h0080; + parameter ALMOST_FULL_OFFSET = 13'h0080; + parameter integer DATA_WIDTH = 4; + parameter integer DO_REG = 1; + parameter EN_ECC_READ = "FALSE"; + parameter EN_ECC_WRITE = "FALSE"; + parameter EN_SYN = "FALSE"; + parameter FIFO_MODE = "FIFO36"; + parameter FIRST_WORD_FALL_THROUGH = "FALSE"; + parameter INIT = 72'h0; + parameter SIM_DEVICE = "VIRTEX6"; + parameter SRVAL = 72'h0; + parameter IS_RDCLK_INVERTED = 1'b0; + parameter IS_RDEN_INVERTED = 1'b0; + parameter IS_RSTREG_INVERTED = 1'b0; + parameter IS_RST_INVERTED = 1'b0; + parameter IS_WRCLK_INVERTED = 1'b0; + parameter IS_WREN_INVERTED = 1'b0; + output ALMOSTEMPTY; + output ALMOSTFULL; + output DBITERR; + output [63:0] DO; + output [7:0] DOP; + output [7:0] ECCPARITY; + output EMPTY; + output FULL; + output [12:0] RDCOUNT; + output RDERR; + output SBITERR; + output [12:0] WRCOUNT; + output WRERR; + input [63:0] DI; + input [7:0] DIP; + input INJECTDBITERR; + input INJECTSBITERR; + input RDCLK; + input RDEN; + input REGCE; + input RST; + input RSTREG; + input WRCLK; + input WREN; +endmodule + +module FRAME_ECCE2 (...); + parameter FARSRC = "EFAR"; + parameter FRAME_RBT_IN_FILENAME = "NONE"; + output CRCERROR; + output ECCERROR; + output ECCERRORSINGLE; + output SYNDROMEVALID; + output [12:0] SYNDROME; + output [25:0] FAR; + output [4:0] SYNBIT; + output [6:0] SYNWORD; +endmodule + +module GTHE2_CHANNEL (...); + parameter [0:0] ACJTAG_DEBUG_MODE = 1'b0; + parameter [0:0] ACJTAG_MODE = 1'b0; + parameter [0:0] ACJTAG_RESET = 1'b0; + parameter [19:0] ADAPT_CFG0 = 20'h00C10; + parameter ALIGN_COMMA_DOUBLE = "FALSE"; + parameter [9:0] ALIGN_COMMA_ENABLE = 10'b0001111111; + parameter integer ALIGN_COMMA_WORD = 1; + parameter ALIGN_MCOMMA_DET = "TRUE"; + parameter [9:0] ALIGN_MCOMMA_VALUE = 10'b1010000011; + parameter ALIGN_PCOMMA_DET = "TRUE"; + parameter [9:0] ALIGN_PCOMMA_VALUE = 10'b0101111100; + parameter [0:0] A_RXOSCALRESET = 1'b0; + parameter CBCC_DATA_SOURCE_SEL = "DECODED"; + parameter [41:0] CFOK_CFG = 42'h24800040E80; + parameter [5:0] CFOK_CFG2 = 6'b100000; + parameter [5:0] CFOK_CFG3 = 6'b100000; + parameter CHAN_BOND_KEEP_ALIGN = "FALSE"; + parameter integer CHAN_BOND_MAX_SKEW = 7; + parameter [9:0] CHAN_BOND_SEQ_1_1 = 10'b0101111100; + parameter [9:0] CHAN_BOND_SEQ_1_2 = 10'b0000000000; + parameter [9:0] CHAN_BOND_SEQ_1_3 = 10'b0000000000; + parameter [9:0] CHAN_BOND_SEQ_1_4 = 10'b0000000000; + parameter [3:0] CHAN_BOND_SEQ_1_ENABLE = 4'b1111; + parameter [9:0] CHAN_BOND_SEQ_2_1 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_2 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_3 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_4 = 10'b0100000000; + parameter [3:0] CHAN_BOND_SEQ_2_ENABLE = 4'b1111; + parameter CHAN_BOND_SEQ_2_USE = "FALSE"; + parameter integer CHAN_BOND_SEQ_LEN = 1; + parameter CLK_CORRECT_USE = "TRUE"; + parameter CLK_COR_KEEP_IDLE = "FALSE"; + parameter integer CLK_COR_MAX_LAT = 20; + parameter integer CLK_COR_MIN_LAT = 18; + parameter CLK_COR_PRECEDENCE = "TRUE"; + parameter integer CLK_COR_REPEAT_WAIT = 0; + parameter [9:0] CLK_COR_SEQ_1_1 = 10'b0100011100; + parameter [9:0] CLK_COR_SEQ_1_2 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_3 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_4 = 10'b0000000000; + parameter [3:0] CLK_COR_SEQ_1_ENABLE = 4'b1111; + parameter [9:0] CLK_COR_SEQ_2_1 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_2 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_3 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_4 = 10'b0100000000; + parameter [3:0] CLK_COR_SEQ_2_ENABLE = 4'b1111; + parameter CLK_COR_SEQ_2_USE = "FALSE"; + parameter integer CLK_COR_SEQ_LEN = 1; + parameter [28:0] CPLL_CFG = 29'h00BC07DC; + parameter integer CPLL_FBDIV = 4; + parameter integer CPLL_FBDIV_45 = 5; + parameter [23:0] CPLL_INIT_CFG = 24'h00001E; + parameter [15:0] CPLL_LOCK_CFG = 16'h01E8; + parameter integer CPLL_REFCLK_DIV = 1; + parameter DEC_MCOMMA_DETECT = "TRUE"; + parameter DEC_PCOMMA_DETECT = "TRUE"; + parameter DEC_VALID_COMMA_ONLY = "TRUE"; + parameter [23:0] DMONITOR_CFG = 24'h000A00; + parameter [0:0] ES_CLK_PHASE_SEL = 1'b0; + parameter [5:0] ES_CONTROL = 6'b000000; + parameter ES_ERRDET_EN = "FALSE"; + parameter ES_EYE_SCAN_EN = "TRUE"; + parameter [11:0] ES_HORZ_OFFSET = 12'h000; + parameter [9:0] ES_PMA_CFG = 10'b0000000000; + parameter [4:0] ES_PRESCALE = 5'b00000; + parameter [79:0] ES_QUALIFIER = 80'h00000000000000000000; + parameter [79:0] ES_QUAL_MASK = 80'h00000000000000000000; + parameter [79:0] ES_SDATA_MASK = 80'h00000000000000000000; + parameter [8:0] ES_VERT_OFFSET = 9'b000000000; + parameter [3:0] FTS_DESKEW_SEQ_ENABLE = 4'b1111; + parameter [3:0] FTS_LANE_DESKEW_CFG = 4'b1111; + parameter FTS_LANE_DESKEW_EN = "FALSE"; + parameter [2:0] GEARBOX_MODE = 3'b000; + parameter [0:0] IS_CLKRSVD0_INVERTED = 1'b0; + parameter [0:0] IS_CLKRSVD1_INVERTED = 1'b0; + parameter [0:0] IS_CPLLLOCKDETCLK_INVERTED = 1'b0; + parameter [0:0] IS_DMONITORCLK_INVERTED = 1'b0; + parameter [0:0] IS_DRPCLK_INVERTED = 1'b0; + parameter [0:0] IS_GTGREFCLK_INVERTED = 1'b0; + parameter [0:0] IS_RXUSRCLK2_INVERTED = 1'b0; + parameter [0:0] IS_RXUSRCLK_INVERTED = 1'b0; + parameter [0:0] IS_SIGVALIDCLK_INVERTED = 1'b0; + parameter [0:0] IS_TXPHDLYTSTCLK_INVERTED = 1'b0; + parameter [0:0] IS_TXUSRCLK2_INVERTED = 1'b0; + parameter [0:0] IS_TXUSRCLK_INVERTED = 1'b0; + parameter [0:0] LOOPBACK_CFG = 1'b0; + parameter [1:0] OUTREFCLK_SEL_INV = 2'b11; + parameter PCS_PCIE_EN = "FALSE"; + parameter [47:0] PCS_RSVD_ATTR = 48'h000000000000; + parameter [11:0] PD_TRANS_TIME_FROM_P2 = 12'h03C; + parameter [7:0] PD_TRANS_TIME_NONE_P2 = 8'h19; + parameter [7:0] PD_TRANS_TIME_TO_P2 = 8'h64; + parameter [31:0] PMA_RSV = 32'b00000000000000000000000010000000; + parameter [31:0] PMA_RSV2 = 32'b00011100000000000000000000001010; + parameter [1:0] PMA_RSV3 = 2'b00; + parameter [14:0] PMA_RSV4 = 15'b000000000001000; + parameter [3:0] PMA_RSV5 = 4'b0000; + parameter [0:0] RESET_POWERSAVE_DISABLE = 1'b0; + parameter [4:0] RXBUFRESET_TIME = 5'b00001; + parameter RXBUF_ADDR_MODE = "FULL"; + parameter [3:0] RXBUF_EIDLE_HI_CNT = 4'b1000; + parameter [3:0] RXBUF_EIDLE_LO_CNT = 4'b0000; + parameter RXBUF_EN = "TRUE"; + parameter RXBUF_RESET_ON_CB_CHANGE = "TRUE"; + parameter RXBUF_RESET_ON_COMMAALIGN = "FALSE"; + parameter RXBUF_RESET_ON_EIDLE = "FALSE"; + parameter RXBUF_RESET_ON_RATE_CHANGE = "TRUE"; + parameter integer RXBUF_THRESH_OVFLW = 61; + parameter RXBUF_THRESH_OVRD = "FALSE"; + parameter integer RXBUF_THRESH_UNDFLW = 4; + parameter [4:0] RXCDRFREQRESET_TIME = 5'b00001; + parameter [4:0] RXCDRPHRESET_TIME = 5'b00001; + parameter [82:0] RXCDR_CFG = 83'h0002007FE2000C208001A; + parameter [0:0] RXCDR_FR_RESET_ON_EIDLE = 1'b0; + parameter [0:0] RXCDR_HOLD_DURING_EIDLE = 1'b0; + parameter [5:0] RXCDR_LOCK_CFG = 6'b001001; + parameter [0:0] RXCDR_PH_RESET_ON_EIDLE = 1'b0; + parameter [6:0] RXDFELPMRESET_TIME = 7'b0001111; + parameter [15:0] RXDLY_CFG = 16'h001F; + parameter [8:0] RXDLY_LCFG = 9'h030; + parameter [15:0] RXDLY_TAP_CFG = 16'h0000; + parameter RXGEARBOX_EN = "FALSE"; + parameter [4:0] RXISCANRESET_TIME = 5'b00001; + parameter [13:0] RXLPM_HF_CFG = 14'b00001000000000; + parameter [17:0] RXLPM_LF_CFG = 18'b001001000000000000; + parameter [6:0] RXOOB_CFG = 7'b0000110; + parameter RXOOB_CLK_CFG = "PMA"; + parameter [4:0] RXOSCALRESET_TIME = 5'b00011; + parameter [4:0] RXOSCALRESET_TIMEOUT = 5'b00000; + parameter integer RXOUT_DIV = 2; + parameter [4:0] RXPCSRESET_TIME = 5'b00001; + parameter [23:0] RXPHDLY_CFG = 24'h084020; + parameter [23:0] RXPH_CFG = 24'hC00002; + parameter [4:0] RXPH_MONITOR_SEL = 5'b00000; + parameter [1:0] RXPI_CFG0 = 2'b00; + parameter [1:0] RXPI_CFG1 = 2'b00; + parameter [1:0] RXPI_CFG2 = 2'b00; + parameter [1:0] RXPI_CFG3 = 2'b00; + parameter [0:0] RXPI_CFG4 = 1'b0; + parameter [0:0] RXPI_CFG5 = 1'b0; + parameter [2:0] RXPI_CFG6 = 3'b100; + parameter [4:0] RXPMARESET_TIME = 5'b00011; + parameter [0:0] RXPRBS_ERR_LOOPBACK = 1'b0; + parameter integer RXSLIDE_AUTO_WAIT = 7; + parameter RXSLIDE_MODE = "OFF"; + parameter [0:0] RXSYNC_MULTILANE = 1'b0; + parameter [0:0] RXSYNC_OVRD = 1'b0; + parameter [0:0] RXSYNC_SKIP_DA = 1'b0; + parameter [23:0] RX_BIAS_CFG = 24'b000011000000000000010000; + parameter [5:0] RX_BUFFER_CFG = 6'b000000; + parameter integer RX_CLK25_DIV = 7; + parameter [0:0] RX_CLKMUX_PD = 1'b1; + parameter [1:0] RX_CM_SEL = 2'b11; + parameter [3:0] RX_CM_TRIM = 4'b0100; + parameter integer RX_DATA_WIDTH = 20; + parameter [5:0] RX_DDI_SEL = 6'b000000; + parameter [13:0] RX_DEBUG_CFG = 14'b00000000000000; + parameter RX_DEFER_RESET_BUF_EN = "TRUE"; + parameter [3:0] RX_DFELPM_CFG0 = 4'b0110; + parameter [0:0] RX_DFELPM_CFG1 = 1'b0; + parameter [0:0] RX_DFELPM_KLKH_AGC_STUP_EN = 1'b1; + parameter [1:0] RX_DFE_AGC_CFG0 = 2'b00; + parameter [2:0] RX_DFE_AGC_CFG1 = 3'b010; + parameter [3:0] RX_DFE_AGC_CFG2 = 4'b0000; + parameter [0:0] RX_DFE_AGC_OVRDEN = 1'b1; + parameter [22:0] RX_DFE_GAIN_CFG = 23'h0020C0; + parameter [11:0] RX_DFE_H2_CFG = 12'b000000000000; + parameter [11:0] RX_DFE_H3_CFG = 12'b000001000000; + parameter [10:0] RX_DFE_H4_CFG = 11'b00011100000; + parameter [10:0] RX_DFE_H5_CFG = 11'b00011100000; + parameter [10:0] RX_DFE_H6_CFG = 11'b00000100000; + parameter [10:0] RX_DFE_H7_CFG = 11'b00000100000; + parameter [32:0] RX_DFE_KL_CFG = 33'b000000000000000000000001100010000; + parameter [1:0] RX_DFE_KL_LPM_KH_CFG0 = 2'b01; + parameter [2:0] RX_DFE_KL_LPM_KH_CFG1 = 3'b010; + parameter [3:0] RX_DFE_KL_LPM_KH_CFG2 = 4'b0010; + parameter [0:0] RX_DFE_KL_LPM_KH_OVRDEN = 1'b1; + parameter [1:0] RX_DFE_KL_LPM_KL_CFG0 = 2'b10; + parameter [2:0] RX_DFE_KL_LPM_KL_CFG1 = 3'b010; + parameter [3:0] RX_DFE_KL_LPM_KL_CFG2 = 4'b0010; + parameter [0:0] RX_DFE_KL_LPM_KL_OVRDEN = 1'b1; + parameter [15:0] RX_DFE_LPM_CFG = 16'h0080; + parameter [0:0] RX_DFE_LPM_HOLD_DURING_EIDLE = 1'b0; + parameter [53:0] RX_DFE_ST_CFG = 54'h00E100000C003F; + parameter [16:0] RX_DFE_UT_CFG = 17'b00011100000000000; + parameter [16:0] RX_DFE_VP_CFG = 17'b00011101010100011; + parameter RX_DISPERR_SEQ_MATCH = "TRUE"; + parameter integer RX_INT_DATAWIDTH = 0; + parameter [12:0] RX_OS_CFG = 13'b0000010000000; + parameter integer RX_SIG_VALID_DLY = 10; + parameter RX_XCLK_SEL = "RXREC"; + parameter integer SAS_MAX_COM = 64; + parameter integer SAS_MIN_COM = 36; + parameter [3:0] SATA_BURST_SEQ_LEN = 4'b1111; + parameter [2:0] SATA_BURST_VAL = 3'b100; + parameter SATA_CPLL_CFG = "VCO_3000MHZ"; + parameter [2:0] SATA_EIDLE_VAL = 3'b100; + parameter integer SATA_MAX_BURST = 8; + parameter integer SATA_MAX_INIT = 21; + parameter integer SATA_MAX_WAKE = 7; + parameter integer SATA_MIN_BURST = 4; + parameter integer SATA_MIN_INIT = 12; + parameter integer SATA_MIN_WAKE = 4; + parameter SHOW_REALIGN_COMMA = "TRUE"; + parameter [2:0] SIM_CPLLREFCLK_SEL = 3'b001; + parameter SIM_RECEIVER_DETECT_PASS = "TRUE"; + parameter SIM_RESET_SPEEDUP = "TRUE"; + parameter SIM_TX_EIDLE_DRIVE_LEVEL = "X"; + parameter SIM_VERSION = "1.1"; + parameter [14:0] TERM_RCAL_CFG = 15'b100001000010000; + parameter [2:0] TERM_RCAL_OVRD = 3'b000; + parameter [7:0] TRANS_TIME_RATE = 8'h0E; + parameter [31:0] TST_RSV = 32'h00000000; + parameter TXBUF_EN = "TRUE"; + parameter TXBUF_RESET_ON_RATE_CHANGE = "FALSE"; + parameter [15:0] TXDLY_CFG = 16'h001F; + parameter [8:0] TXDLY_LCFG = 9'h030; + parameter [15:0] TXDLY_TAP_CFG = 16'h0000; + parameter TXGEARBOX_EN = "FALSE"; + parameter [0:0] TXOOB_CFG = 1'b0; + parameter integer TXOUT_DIV = 2; + parameter [4:0] TXPCSRESET_TIME = 5'b00001; + parameter [23:0] TXPHDLY_CFG = 24'h084020; + parameter [15:0] TXPH_CFG = 16'h0780; + parameter [4:0] TXPH_MONITOR_SEL = 5'b00000; + parameter [1:0] TXPI_CFG0 = 2'b00; + parameter [1:0] TXPI_CFG1 = 2'b00; + parameter [1:0] TXPI_CFG2 = 2'b00; + parameter [0:0] TXPI_CFG3 = 1'b0; + parameter [0:0] TXPI_CFG4 = 1'b0; + parameter [2:0] TXPI_CFG5 = 3'b100; + parameter [0:0] TXPI_GREY_SEL = 1'b0; + parameter [0:0] TXPI_INVSTROBE_SEL = 1'b0; + parameter TXPI_PPMCLK_SEL = "TXUSRCLK2"; + parameter [7:0] TXPI_PPM_CFG = 8'b00000000; + parameter [2:0] TXPI_SYNFREQ_PPM = 3'b000; + parameter [4:0] TXPMARESET_TIME = 5'b00001; + parameter [0:0] TXSYNC_MULTILANE = 1'b0; + parameter [0:0] TXSYNC_OVRD = 1'b0; + parameter [0:0] TXSYNC_SKIP_DA = 1'b0; + parameter integer TX_CLK25_DIV = 7; + parameter [0:0] TX_CLKMUX_PD = 1'b1; + parameter integer TX_DATA_WIDTH = 20; + parameter [5:0] TX_DEEMPH0 = 6'b000000; + parameter [5:0] TX_DEEMPH1 = 6'b000000; + parameter TX_DRIVE_MODE = "DIRECT"; + parameter [2:0] TX_EIDLE_ASSERT_DELAY = 3'b110; + parameter [2:0] TX_EIDLE_DEASSERT_DELAY = 3'b100; + parameter integer TX_INT_DATAWIDTH = 0; + parameter TX_LOOPBACK_DRIVE_HIZ = "FALSE"; + parameter [0:0] TX_MAINCURSOR_SEL = 1'b0; + parameter [6:0] TX_MARGIN_FULL_0 = 7'b1001110; + parameter [6:0] TX_MARGIN_FULL_1 = 7'b1001001; + parameter [6:0] TX_MARGIN_FULL_2 = 7'b1000101; + parameter [6:0] TX_MARGIN_FULL_3 = 7'b1000010; + parameter [6:0] TX_MARGIN_FULL_4 = 7'b1000000; + parameter [6:0] TX_MARGIN_LOW_0 = 7'b1000110; + parameter [6:0] TX_MARGIN_LOW_1 = 7'b1000100; + parameter [6:0] TX_MARGIN_LOW_2 = 7'b1000010; + parameter [6:0] TX_MARGIN_LOW_3 = 7'b1000000; + parameter [6:0] TX_MARGIN_LOW_4 = 7'b1000000; + parameter [0:0] TX_QPI_STATUS_EN = 1'b0; + parameter [13:0] TX_RXDETECT_CFG = 14'h1832; + parameter [16:0] TX_RXDETECT_PRECHARGE_TIME = 17'h00000; + parameter [2:0] TX_RXDETECT_REF = 3'b100; + parameter TX_XCLK_SEL = "TXUSR"; + parameter [0:0] UCODEER_CLR = 1'b0; + parameter [0:0] USE_PCS_CLK_PHASE_SEL = 1'b0; + output CPLLFBCLKLOST; + output CPLLLOCK; + output CPLLREFCLKLOST; + output DRPRDY; + output EYESCANDATAERROR; + output GTHTXN; + output GTHTXP; + output GTREFCLKMONITOR; + output PHYSTATUS; + output RSOSINTDONE; + output RXBYTEISALIGNED; + output RXBYTEREALIGN; + output RXCDRLOCK; + output RXCHANBONDSEQ; + output RXCHANISALIGNED; + output RXCHANREALIGN; + output RXCOMINITDET; + output RXCOMMADET; + output RXCOMSASDET; + output RXCOMWAKEDET; + output RXDFESLIDETAPSTARTED; + output RXDFESLIDETAPSTROBEDONE; + output RXDFESLIDETAPSTROBESTARTED; + output RXDFESTADAPTDONE; + output RXDLYSRESETDONE; + output RXELECIDLE; + output RXOSINTSTARTED; + output RXOSINTSTROBEDONE; + output RXOSINTSTROBESTARTED; + output RXOUTCLK; + output RXOUTCLKFABRIC; + output RXOUTCLKPCS; + output RXPHALIGNDONE; + output RXPMARESETDONE; + output RXPRBSERR; + output RXQPISENN; + output RXQPISENP; + output RXRATEDONE; + output RXRESETDONE; + output RXSYNCDONE; + output RXSYNCOUT; + output RXVALID; + output TXCOMFINISH; + output TXDLYSRESETDONE; + output TXGEARBOXREADY; + output TXOUTCLK; + output TXOUTCLKFABRIC; + output TXOUTCLKPCS; + output TXPHALIGNDONE; + output TXPHINITDONE; + output TXPMARESETDONE; + output TXQPISENN; + output TXQPISENP; + output TXRATEDONE; + output TXRESETDONE; + output TXSYNCDONE; + output TXSYNCOUT; + output [14:0] DMONITOROUT; + output [15:0] DRPDO; + output [15:0] PCSRSVDOUT; + output [1:0] RXCLKCORCNT; + output [1:0] RXDATAVALID; + output [1:0] RXHEADERVALID; + output [1:0] RXSTARTOFSEQ; + output [1:0] TXBUFSTATUS; + output [2:0] RXBUFSTATUS; + output [2:0] RXSTATUS; + output [4:0] RXCHBONDO; + output [4:0] RXPHMONITOR; + output [4:0] RXPHSLIPMONITOR; + output [5:0] RXHEADER; + output [63:0] RXDATA; + output [6:0] RXMONITOROUT; + output [7:0] RXCHARISCOMMA; + output [7:0] RXCHARISK; + output [7:0] RXDISPERR; + output [7:0] RXNOTINTABLE; + input CFGRESET; + input CLKRSVD0; + input CLKRSVD1; + input CPLLLOCKDETCLK; + input CPLLLOCKEN; + input CPLLPD; + input CPLLRESET; + input DMONFIFORESET; + input DMONITORCLK; + input DRPCLK; + input DRPEN; + input DRPWE; + input EYESCANMODE; + input EYESCANRESET; + input EYESCANTRIGGER; + input GTGREFCLK; + input GTHRXN; + input GTHRXP; + input GTNORTHREFCLK0; + input GTNORTHREFCLK1; + input GTREFCLK0; + input GTREFCLK1; + input GTRESETSEL; + input GTRXRESET; + input GTSOUTHREFCLK0; + input GTSOUTHREFCLK1; + input GTTXRESET; + input QPLLCLK; + input QPLLREFCLK; + input RESETOVRD; + input RX8B10BEN; + input RXBUFRESET; + input RXCDRFREQRESET; + input RXCDRHOLD; + input RXCDROVRDEN; + input RXCDRRESET; + input RXCDRRESETRSV; + input RXCHBONDEN; + input RXCHBONDMASTER; + input RXCHBONDSLAVE; + input RXCOMMADETEN; + input RXDDIEN; + input RXDFEAGCHOLD; + input RXDFEAGCOVRDEN; + input RXDFECM1EN; + input RXDFELFHOLD; + input RXDFELFOVRDEN; + input RXDFELPMRESET; + input RXDFESLIDETAPADAPTEN; + input RXDFESLIDETAPHOLD; + input RXDFESLIDETAPINITOVRDEN; + input RXDFESLIDETAPONLYADAPTEN; + input RXDFESLIDETAPOVRDEN; + input RXDFESLIDETAPSTROBE; + input RXDFETAP2HOLD; + input RXDFETAP2OVRDEN; + input RXDFETAP3HOLD; + input RXDFETAP3OVRDEN; + input RXDFETAP4HOLD; + input RXDFETAP4OVRDEN; + input RXDFETAP5HOLD; + input RXDFETAP5OVRDEN; + input RXDFETAP6HOLD; + input RXDFETAP6OVRDEN; + input RXDFETAP7HOLD; + input RXDFETAP7OVRDEN; + input RXDFEUTHOLD; + input RXDFEUTOVRDEN; + input RXDFEVPHOLD; + input RXDFEVPOVRDEN; + input RXDFEVSEN; + input RXDFEXYDEN; + input RXDLYBYPASS; + input RXDLYEN; + input RXDLYOVRDEN; + input RXDLYSRESET; + input RXGEARBOXSLIP; + input RXLPMEN; + input RXLPMHFHOLD; + input RXLPMHFOVRDEN; + input RXLPMLFHOLD; + input RXLPMLFKLOVRDEN; + input RXMCOMMAALIGNEN; + input RXOOBRESET; + input RXOSCALRESET; + input RXOSHOLD; + input RXOSINTEN; + input RXOSINTHOLD; + input RXOSINTNTRLEN; + input RXOSINTOVRDEN; + input RXOSINTSTROBE; + input RXOSINTTESTOVRDEN; + input RXOSOVRDEN; + input RXPCOMMAALIGNEN; + input RXPCSRESET; + input RXPHALIGN; + input RXPHALIGNEN; + input RXPHDLYPD; + input RXPHDLYRESET; + input RXPHOVRDEN; + input RXPMARESET; + input RXPOLARITY; + input RXPRBSCNTRESET; + input RXQPIEN; + input RXRATEMODE; + input RXSLIDE; + input RXSYNCALLIN; + input RXSYNCIN; + input RXSYNCMODE; + input RXUSERRDY; + input RXUSRCLK2; + input RXUSRCLK; + input SETERRSTATUS; + input SIGVALIDCLK; + input TX8B10BEN; + input TXCOMINIT; + input TXCOMSAS; + input TXCOMWAKE; + input TXDEEMPH; + input TXDETECTRX; + input TXDIFFPD; + input TXDLYBYPASS; + input TXDLYEN; + input TXDLYHOLD; + input TXDLYOVRDEN; + input TXDLYSRESET; + input TXDLYUPDOWN; + input TXELECIDLE; + input TXINHIBIT; + input TXPCSRESET; + input TXPDELECIDLEMODE; + input TXPHALIGN; + input TXPHALIGNEN; + input TXPHDLYPD; + input TXPHDLYRESET; + input TXPHDLYTSTCLK; + input TXPHINIT; + input TXPHOVRDEN; + input TXPIPPMEN; + input TXPIPPMOVRDEN; + input TXPIPPMPD; + input TXPIPPMSEL; + input TXPISOPD; + input TXPMARESET; + input TXPOLARITY; + input TXPOSTCURSORINV; + input TXPRBSFORCEERR; + input TXPRECURSORINV; + input TXQPIBIASEN; + input TXQPISTRONGPDOWN; + input TXQPIWEAKPUP; + input TXRATEMODE; + input TXSTARTSEQ; + input TXSWING; + input TXSYNCALLIN; + input TXSYNCIN; + input TXSYNCMODE; + input TXUSERRDY; + input TXUSRCLK2; + input TXUSRCLK; + input [13:0] RXADAPTSELTEST; + input [15:0] DRPDI; + input [15:0] GTRSVD; + input [15:0] PCSRSVDIN; + input [19:0] TSTIN; + input [1:0] RXELECIDLEMODE; + input [1:0] RXMONITORSEL; + input [1:0] RXPD; + input [1:0] RXSYSCLKSEL; + input [1:0] TXPD; + input [1:0] TXSYSCLKSEL; + input [2:0] CPLLREFCLKSEL; + input [2:0] LOOPBACK; + input [2:0] RXCHBONDLEVEL; + input [2:0] RXOUTCLKSEL; + input [2:0] RXPRBSSEL; + input [2:0] RXRATE; + input [2:0] TXBUFDIFFCTRL; + input [2:0] TXHEADER; + input [2:0] TXMARGIN; + input [2:0] TXOUTCLKSEL; + input [2:0] TXPRBSSEL; + input [2:0] TXRATE; + input [3:0] RXOSINTCFG; + input [3:0] RXOSINTID0; + input [3:0] TXDIFFCTRL; + input [4:0] PCSRSVDIN2; + input [4:0] PMARSVDIN; + input [4:0] RXCHBONDI; + input [4:0] RXDFEAGCTRL; + input [4:0] RXDFESLIDETAP; + input [4:0] TXPIPPMSTEPSIZE; + input [4:0] TXPOSTCURSOR; + input [4:0] TXPRECURSOR; + input [5:0] RXDFESLIDETAPID; + input [63:0] TXDATA; + input [6:0] TXMAINCURSOR; + input [6:0] TXSEQUENCE; + input [7:0] TX8B10BBYPASS; + input [7:0] TXCHARDISPMODE; + input [7:0] TXCHARDISPVAL; + input [7:0] TXCHARISK; + input [8:0] DRPADDR; +endmodule + +module GTHE2_COMMON (...); + parameter [63:0] BIAS_CFG = 64'h0000040000001000; + parameter [31:0] COMMON_CFG = 32'h0000001C; + parameter [0:0] IS_DRPCLK_INVERTED = 1'b0; + parameter [0:0] IS_GTGREFCLK_INVERTED = 1'b0; + parameter [0:0] IS_QPLLLOCKDETCLK_INVERTED = 1'b0; + parameter [26:0] QPLL_CFG = 27'h0480181; + parameter [3:0] QPLL_CLKOUT_CFG = 4'b0000; + parameter [5:0] QPLL_COARSE_FREQ_OVRD = 6'b010000; + parameter [0:0] QPLL_COARSE_FREQ_OVRD_EN = 1'b0; + parameter [9:0] QPLL_CP = 10'b0000011111; + parameter [0:0] QPLL_CP_MONITOR_EN = 1'b0; + parameter [0:0] QPLL_DMONITOR_SEL = 1'b0; + parameter [9:0] QPLL_FBDIV = 10'b0000000000; + parameter [0:0] QPLL_FBDIV_MONITOR_EN = 1'b0; + parameter [0:0] QPLL_FBDIV_RATIO = 1'b0; + parameter [23:0] QPLL_INIT_CFG = 24'h000006; + parameter [15:0] QPLL_LOCK_CFG = 16'h01E8; + parameter [3:0] QPLL_LPF = 4'b1111; + parameter integer QPLL_REFCLK_DIV = 2; + parameter [0:0] QPLL_RP_COMP = 1'b0; + parameter [1:0] QPLL_VTRL_RESET = 2'b00; + parameter [1:0] RCAL_CFG = 2'b00; + parameter [15:0] RSVD_ATTR0 = 16'h0000; + parameter [15:0] RSVD_ATTR1 = 16'h0000; + parameter [2:0] SIM_QPLLREFCLK_SEL = 3'b001; + parameter SIM_RESET_SPEEDUP = "TRUE"; + parameter SIM_VERSION = "1.1"; + output DRPRDY; + output QPLLFBCLKLOST; + output QPLLLOCK; + output QPLLOUTCLK; + output QPLLOUTREFCLK; + output QPLLREFCLKLOST; + output REFCLKOUTMONITOR; + output [15:0] DRPDO; + output [15:0] PMARSVDOUT; + output [7:0] QPLLDMONITOR; + input BGBYPASSB; + input BGMONITORENB; + input BGPDB; + input BGRCALOVRDENB; + input DRPCLK; + input DRPEN; + input DRPWE; + input GTGREFCLK; + input GTNORTHREFCLK0; + input GTNORTHREFCLK1; + input GTREFCLK0; + input GTREFCLK1; + input GTSOUTHREFCLK0; + input GTSOUTHREFCLK1; + input QPLLLOCKDETCLK; + input QPLLLOCKEN; + input QPLLOUTRESET; + input QPLLPD; + input QPLLRESET; + input RCALENB; + input [15:0] DRPDI; + input [15:0] QPLLRSVD1; + input [2:0] QPLLREFCLKSEL; + input [4:0] BGRCALOVRD; + input [4:0] QPLLRSVD2; + input [7:0] DRPADDR; + input [7:0] PMARSVD; +endmodule + +module GTPE2_CHANNEL (...); + parameter [0:0] ACJTAG_DEBUG_MODE = 1'b0; + parameter [0:0] ACJTAG_MODE = 1'b0; + parameter [0:0] ACJTAG_RESET = 1'b0; + parameter [19:0] ADAPT_CFG0 = 20'b00000000000000000000; + parameter ALIGN_COMMA_DOUBLE = "FALSE"; + parameter [9:0] ALIGN_COMMA_ENABLE = 10'b0001111111; + parameter integer ALIGN_COMMA_WORD = 1; + parameter ALIGN_MCOMMA_DET = "TRUE"; + parameter [9:0] ALIGN_MCOMMA_VALUE = 10'b1010000011; + parameter ALIGN_PCOMMA_DET = "TRUE"; + parameter [9:0] ALIGN_PCOMMA_VALUE = 10'b0101111100; + parameter CBCC_DATA_SOURCE_SEL = "DECODED"; + parameter [42:0] CFOK_CFG = 43'b1001001000000000000000001000000111010000000; + parameter [6:0] CFOK_CFG2 = 7'b0100000; + parameter [6:0] CFOK_CFG3 = 7'b0100000; + parameter [0:0] CFOK_CFG4 = 1'b0; + parameter [1:0] CFOK_CFG5 = 2'b00; + parameter [3:0] CFOK_CFG6 = 4'b0000; + parameter CHAN_BOND_KEEP_ALIGN = "FALSE"; + parameter integer CHAN_BOND_MAX_SKEW = 7; + parameter [9:0] CHAN_BOND_SEQ_1_1 = 10'b0101111100; + parameter [9:0] CHAN_BOND_SEQ_1_2 = 10'b0000000000; + parameter [9:0] CHAN_BOND_SEQ_1_3 = 10'b0000000000; + parameter [9:0] CHAN_BOND_SEQ_1_4 = 10'b0000000000; + parameter [3:0] CHAN_BOND_SEQ_1_ENABLE = 4'b1111; + parameter [9:0] CHAN_BOND_SEQ_2_1 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_2 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_3 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_4 = 10'b0100000000; + parameter [3:0] CHAN_BOND_SEQ_2_ENABLE = 4'b1111; + parameter CHAN_BOND_SEQ_2_USE = "FALSE"; + parameter integer CHAN_BOND_SEQ_LEN = 1; + parameter [0:0] CLK_COMMON_SWING = 1'b0; + parameter CLK_CORRECT_USE = "TRUE"; + parameter CLK_COR_KEEP_IDLE = "FALSE"; + parameter integer CLK_COR_MAX_LAT = 20; + parameter integer CLK_COR_MIN_LAT = 18; + parameter CLK_COR_PRECEDENCE = "TRUE"; + parameter integer CLK_COR_REPEAT_WAIT = 0; + parameter [9:0] CLK_COR_SEQ_1_1 = 10'b0100011100; + parameter [9:0] CLK_COR_SEQ_1_2 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_3 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_4 = 10'b0000000000; + parameter [3:0] CLK_COR_SEQ_1_ENABLE = 4'b1111; + parameter [9:0] CLK_COR_SEQ_2_1 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_2 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_3 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_4 = 10'b0100000000; + parameter [3:0] CLK_COR_SEQ_2_ENABLE = 4'b1111; + parameter CLK_COR_SEQ_2_USE = "FALSE"; + parameter integer CLK_COR_SEQ_LEN = 1; + parameter DEC_MCOMMA_DETECT = "TRUE"; + parameter DEC_PCOMMA_DETECT = "TRUE"; + parameter DEC_VALID_COMMA_ONLY = "TRUE"; + parameter [23:0] DMONITOR_CFG = 24'h000A00; + parameter [0:0] ES_CLK_PHASE_SEL = 1'b0; + parameter [5:0] ES_CONTROL = 6'b000000; + parameter ES_ERRDET_EN = "FALSE"; + parameter ES_EYE_SCAN_EN = "FALSE"; + parameter [11:0] ES_HORZ_OFFSET = 12'h010; + parameter [9:0] ES_PMA_CFG = 10'b0000000000; + parameter [4:0] ES_PRESCALE = 5'b00000; + parameter [79:0] ES_QUALIFIER = 80'h00000000000000000000; + parameter [79:0] ES_QUAL_MASK = 80'h00000000000000000000; + parameter [79:0] ES_SDATA_MASK = 80'h00000000000000000000; + parameter [8:0] ES_VERT_OFFSET = 9'b000000000; + parameter [3:0] FTS_DESKEW_SEQ_ENABLE = 4'b1111; + parameter [3:0] FTS_LANE_DESKEW_CFG = 4'b1111; + parameter FTS_LANE_DESKEW_EN = "FALSE"; + parameter [2:0] GEARBOX_MODE = 3'b000; + parameter [0:0] IS_CLKRSVD0_INVERTED = 1'b0; + parameter [0:0] IS_CLKRSVD1_INVERTED = 1'b0; + parameter [0:0] IS_DMONITORCLK_INVERTED = 1'b0; + parameter [0:0] IS_DRPCLK_INVERTED = 1'b0; + parameter [0:0] IS_RXUSRCLK2_INVERTED = 1'b0; + parameter [0:0] IS_RXUSRCLK_INVERTED = 1'b0; + parameter [0:0] IS_SIGVALIDCLK_INVERTED = 1'b0; + parameter [0:0] IS_TXPHDLYTSTCLK_INVERTED = 1'b0; + parameter [0:0] IS_TXUSRCLK2_INVERTED = 1'b0; + parameter [0:0] IS_TXUSRCLK_INVERTED = 1'b0; + parameter [0:0] LOOPBACK_CFG = 1'b0; + parameter [1:0] OUTREFCLK_SEL_INV = 2'b11; + parameter PCS_PCIE_EN = "FALSE"; + parameter [47:0] PCS_RSVD_ATTR = 48'h000000000000; + parameter [11:0] PD_TRANS_TIME_FROM_P2 = 12'h03C; + parameter [7:0] PD_TRANS_TIME_NONE_P2 = 8'h19; + parameter [7:0] PD_TRANS_TIME_TO_P2 = 8'h64; + parameter [0:0] PMA_LOOPBACK_CFG = 1'b0; + parameter [31:0] PMA_RSV = 32'h00000333; + parameter [31:0] PMA_RSV2 = 32'h00002050; + parameter [1:0] PMA_RSV3 = 2'b00; + parameter [3:0] PMA_RSV4 = 4'b0000; + parameter [0:0] PMA_RSV5 = 1'b0; + parameter [0:0] PMA_RSV6 = 1'b0; + parameter [0:0] PMA_RSV7 = 1'b0; + parameter [4:0] RXBUFRESET_TIME = 5'b00001; + parameter RXBUF_ADDR_MODE = "FULL"; + parameter [3:0] RXBUF_EIDLE_HI_CNT = 4'b1000; + parameter [3:0] RXBUF_EIDLE_LO_CNT = 4'b0000; + parameter RXBUF_EN = "TRUE"; + parameter RXBUF_RESET_ON_CB_CHANGE = "TRUE"; + parameter RXBUF_RESET_ON_COMMAALIGN = "FALSE"; + parameter RXBUF_RESET_ON_EIDLE = "FALSE"; + parameter RXBUF_RESET_ON_RATE_CHANGE = "TRUE"; + parameter integer RXBUF_THRESH_OVFLW = 61; + parameter RXBUF_THRESH_OVRD = "FALSE"; + parameter integer RXBUF_THRESH_UNDFLW = 4; + parameter [4:0] RXCDRFREQRESET_TIME = 5'b00001; + parameter [4:0] RXCDRPHRESET_TIME = 5'b00001; + parameter [82:0] RXCDR_CFG = 83'h0000107FE406001041010; + parameter [0:0] RXCDR_FR_RESET_ON_EIDLE = 1'b0; + parameter [0:0] RXCDR_HOLD_DURING_EIDLE = 1'b0; + parameter [5:0] RXCDR_LOCK_CFG = 6'b001001; + parameter [0:0] RXCDR_PH_RESET_ON_EIDLE = 1'b0; + parameter [15:0] RXDLY_CFG = 16'h0010; + parameter [8:0] RXDLY_LCFG = 9'h020; + parameter [15:0] RXDLY_TAP_CFG = 16'h0000; + parameter RXGEARBOX_EN = "FALSE"; + parameter [4:0] RXISCANRESET_TIME = 5'b00001; + parameter [6:0] RXLPMRESET_TIME = 7'b0001111; + parameter [0:0] RXLPM_BIAS_STARTUP_DISABLE = 1'b0; + parameter [3:0] RXLPM_CFG = 4'b0110; + parameter [0:0] RXLPM_CFG1 = 1'b0; + parameter [0:0] RXLPM_CM_CFG = 1'b0; + parameter [8:0] RXLPM_GC_CFG = 9'b111100010; + parameter [2:0] RXLPM_GC_CFG2 = 3'b001; + parameter [13:0] RXLPM_HF_CFG = 14'b00001111110000; + parameter [4:0] RXLPM_HF_CFG2 = 5'b01010; + parameter [3:0] RXLPM_HF_CFG3 = 4'b0000; + parameter [0:0] RXLPM_HOLD_DURING_EIDLE = 1'b0; + parameter [0:0] RXLPM_INCM_CFG = 1'b0; + parameter [0:0] RXLPM_IPCM_CFG = 1'b0; + parameter [17:0] RXLPM_LF_CFG = 18'b000000001111110000; + parameter [4:0] RXLPM_LF_CFG2 = 5'b01010; + parameter [2:0] RXLPM_OSINT_CFG = 3'b100; + parameter [6:0] RXOOB_CFG = 7'b0000110; + parameter RXOOB_CLK_CFG = "PMA"; + parameter [4:0] RXOSCALRESET_TIME = 5'b00011; + parameter [4:0] RXOSCALRESET_TIMEOUT = 5'b00000; + parameter integer RXOUT_DIV = 2; + parameter [4:0] RXPCSRESET_TIME = 5'b00001; + parameter [23:0] RXPHDLY_CFG = 24'h084000; + parameter [23:0] RXPH_CFG = 24'hC00002; + parameter [4:0] RXPH_MONITOR_SEL = 5'b00000; + parameter [2:0] RXPI_CFG0 = 3'b000; + parameter [0:0] RXPI_CFG1 = 1'b0; + parameter [0:0] RXPI_CFG2 = 1'b0; + parameter [4:0] RXPMARESET_TIME = 5'b00011; + parameter [0:0] RXPRBS_ERR_LOOPBACK = 1'b0; + parameter integer RXSLIDE_AUTO_WAIT = 7; + parameter RXSLIDE_MODE = "OFF"; + parameter [0:0] RXSYNC_MULTILANE = 1'b0; + parameter [0:0] RXSYNC_OVRD = 1'b0; + parameter [0:0] RXSYNC_SKIP_DA = 1'b0; + parameter [15:0] RX_BIAS_CFG = 16'b0000111100110011; + parameter [5:0] RX_BUFFER_CFG = 6'b000000; + parameter integer RX_CLK25_DIV = 7; + parameter [0:0] RX_CLKMUX_EN = 1'b1; + parameter [1:0] RX_CM_SEL = 2'b11; + parameter [3:0] RX_CM_TRIM = 4'b0100; + parameter integer RX_DATA_WIDTH = 20; + parameter [5:0] RX_DDI_SEL = 6'b000000; + parameter [13:0] RX_DEBUG_CFG = 14'b00000000000000; + parameter RX_DEFER_RESET_BUF_EN = "TRUE"; + parameter RX_DISPERR_SEQ_MATCH = "TRUE"; + parameter [12:0] RX_OS_CFG = 13'b0001111110000; + parameter integer RX_SIG_VALID_DLY = 10; + parameter RX_XCLK_SEL = "RXREC"; + parameter integer SAS_MAX_COM = 64; + parameter integer SAS_MIN_COM = 36; + parameter [3:0] SATA_BURST_SEQ_LEN = 4'b1111; + parameter [2:0] SATA_BURST_VAL = 3'b100; + parameter [2:0] SATA_EIDLE_VAL = 3'b100; + parameter integer SATA_MAX_BURST = 8; + parameter integer SATA_MAX_INIT = 21; + parameter integer SATA_MAX_WAKE = 7; + parameter integer SATA_MIN_BURST = 4; + parameter integer SATA_MIN_INIT = 12; + parameter integer SATA_MIN_WAKE = 4; + parameter SATA_PLL_CFG = "VCO_3000MHZ"; + parameter SHOW_REALIGN_COMMA = "TRUE"; + parameter SIM_RECEIVER_DETECT_PASS = "TRUE"; + parameter SIM_RESET_SPEEDUP = "TRUE"; + parameter SIM_TX_EIDLE_DRIVE_LEVEL = "X"; + parameter SIM_VERSION = "1.0"; + parameter [14:0] TERM_RCAL_CFG = 15'b100001000010000; + parameter [2:0] TERM_RCAL_OVRD = 3'b000; + parameter [7:0] TRANS_TIME_RATE = 8'h0E; + parameter [31:0] TST_RSV = 32'h00000000; + parameter TXBUF_EN = "TRUE"; + parameter TXBUF_RESET_ON_RATE_CHANGE = "FALSE"; + parameter [15:0] TXDLY_CFG = 16'h0010; + parameter [8:0] TXDLY_LCFG = 9'h020; + parameter [15:0] TXDLY_TAP_CFG = 16'h0000; + parameter TXGEARBOX_EN = "FALSE"; + parameter [0:0] TXOOB_CFG = 1'b0; + parameter integer TXOUT_DIV = 2; + parameter [4:0] TXPCSRESET_TIME = 5'b00001; + parameter [23:0] TXPHDLY_CFG = 24'h084000; + parameter [15:0] TXPH_CFG = 16'h0400; + parameter [4:0] TXPH_MONITOR_SEL = 5'b00000; + parameter [1:0] TXPI_CFG0 = 2'b00; + parameter [1:0] TXPI_CFG1 = 2'b00; + parameter [1:0] TXPI_CFG2 = 2'b00; + parameter [0:0] TXPI_CFG3 = 1'b0; + parameter [0:0] TXPI_CFG4 = 1'b0; + parameter [2:0] TXPI_CFG5 = 3'b000; + parameter [0:0] TXPI_GREY_SEL = 1'b0; + parameter [0:0] TXPI_INVSTROBE_SEL = 1'b0; + parameter TXPI_PPMCLK_SEL = "TXUSRCLK2"; + parameter [7:0] TXPI_PPM_CFG = 8'b00000000; + parameter [2:0] TXPI_SYNFREQ_PPM = 3'b000; + parameter [4:0] TXPMARESET_TIME = 5'b00001; + parameter [0:0] TXSYNC_MULTILANE = 1'b0; + parameter [0:0] TXSYNC_OVRD = 1'b0; + parameter [0:0] TXSYNC_SKIP_DA = 1'b0; + parameter integer TX_CLK25_DIV = 7; + parameter [0:0] TX_CLKMUX_EN = 1'b1; + parameter integer TX_DATA_WIDTH = 20; + parameter [5:0] TX_DEEMPH0 = 6'b000000; + parameter [5:0] TX_DEEMPH1 = 6'b000000; + parameter TX_DRIVE_MODE = "DIRECT"; + parameter [2:0] TX_EIDLE_ASSERT_DELAY = 3'b110; + parameter [2:0] TX_EIDLE_DEASSERT_DELAY = 3'b100; + parameter TX_LOOPBACK_DRIVE_HIZ = "FALSE"; + parameter [0:0] TX_MAINCURSOR_SEL = 1'b0; + parameter [6:0] TX_MARGIN_FULL_0 = 7'b1001110; + parameter [6:0] TX_MARGIN_FULL_1 = 7'b1001001; + parameter [6:0] TX_MARGIN_FULL_2 = 7'b1000101; + parameter [6:0] TX_MARGIN_FULL_3 = 7'b1000010; + parameter [6:0] TX_MARGIN_FULL_4 = 7'b1000000; + parameter [6:0] TX_MARGIN_LOW_0 = 7'b1000110; + parameter [6:0] TX_MARGIN_LOW_1 = 7'b1000100; + parameter [6:0] TX_MARGIN_LOW_2 = 7'b1000010; + parameter [6:0] TX_MARGIN_LOW_3 = 7'b1000000; + parameter [6:0] TX_MARGIN_LOW_4 = 7'b1000000; + parameter [0:0] TX_PREDRIVER_MODE = 1'b0; + parameter [13:0] TX_RXDETECT_CFG = 14'h1832; + parameter [2:0] TX_RXDETECT_REF = 3'b100; + parameter TX_XCLK_SEL = "TXUSR"; + parameter [0:0] UCODEER_CLR = 1'b0; + parameter [0:0] USE_PCS_CLK_PHASE_SEL = 1'b0; + output DRPRDY; + output EYESCANDATAERROR; + output GTPTXN; + output GTPTXP; + output PHYSTATUS; + output PMARSVDOUT0; + output PMARSVDOUT1; + output RXBYTEISALIGNED; + output RXBYTEREALIGN; + output RXCDRLOCK; + output RXCHANBONDSEQ; + output RXCHANISALIGNED; + output RXCHANREALIGN; + output RXCOMINITDET; + output RXCOMMADET; + output RXCOMSASDET; + output RXCOMWAKEDET; + output RXDLYSRESETDONE; + output RXELECIDLE; + output RXHEADERVALID; + output RXOSINTDONE; + output RXOSINTSTARTED; + output RXOSINTSTROBEDONE; + output RXOSINTSTROBESTARTED; + output RXOUTCLK; + output RXOUTCLKFABRIC; + output RXOUTCLKPCS; + output RXPHALIGNDONE; + output RXPMARESETDONE; + output RXPRBSERR; + output RXRATEDONE; + output RXRESETDONE; + output RXSYNCDONE; + output RXSYNCOUT; + output RXVALID; + output TXCOMFINISH; + output TXDLYSRESETDONE; + output TXGEARBOXREADY; + output TXOUTCLK; + output TXOUTCLKFABRIC; + output TXOUTCLKPCS; + output TXPHALIGNDONE; + output TXPHINITDONE; + output TXPMARESETDONE; + output TXRATEDONE; + output TXRESETDONE; + output TXSYNCDONE; + output TXSYNCOUT; + output [14:0] DMONITOROUT; + output [15:0] DRPDO; + output [15:0] PCSRSVDOUT; + output [1:0] RXCLKCORCNT; + output [1:0] RXDATAVALID; + output [1:0] RXSTARTOFSEQ; + output [1:0] TXBUFSTATUS; + output [2:0] RXBUFSTATUS; + output [2:0] RXHEADER; + output [2:0] RXSTATUS; + output [31:0] RXDATA; + output [3:0] RXCHARISCOMMA; + output [3:0] RXCHARISK; + output [3:0] RXCHBONDO; + output [3:0] RXDISPERR; + output [3:0] RXNOTINTABLE; + output [4:0] RXPHMONITOR; + output [4:0] RXPHSLIPMONITOR; + input CFGRESET; + input CLKRSVD0; + input CLKRSVD1; + input DMONFIFORESET; + input DMONITORCLK; + input DRPCLK; + input DRPEN; + input DRPWE; + input EYESCANMODE; + input EYESCANRESET; + input EYESCANTRIGGER; + input GTPRXN; + input GTPRXP; + input GTRESETSEL; + input GTRXRESET; + input GTTXRESET; + input PLL0CLK; + input PLL0REFCLK; + input PLL1CLK; + input PLL1REFCLK; + input PMARSVDIN0; + input PMARSVDIN1; + input PMARSVDIN2; + input PMARSVDIN3; + input PMARSVDIN4; + input RESETOVRD; + input RX8B10BEN; + input RXBUFRESET; + input RXCDRFREQRESET; + input RXCDRHOLD; + input RXCDROVRDEN; + input RXCDRRESET; + input RXCDRRESETRSV; + input RXCHBONDEN; + input RXCHBONDMASTER; + input RXCHBONDSLAVE; + input RXCOMMADETEN; + input RXDDIEN; + input RXDFEXYDEN; + input RXDLYBYPASS; + input RXDLYEN; + input RXDLYOVRDEN; + input RXDLYSRESET; + input RXGEARBOXSLIP; + input RXLPMHFHOLD; + input RXLPMHFOVRDEN; + input RXLPMLFHOLD; + input RXLPMLFOVRDEN; + input RXLPMOSINTNTRLEN; + input RXLPMRESET; + input RXMCOMMAALIGNEN; + input RXOOBRESET; + input RXOSCALRESET; + input RXOSHOLD; + input RXOSINTEN; + input RXOSINTHOLD; + input RXOSINTNTRLEN; + input RXOSINTOVRDEN; + input RXOSINTPD; + input RXOSINTSTROBE; + input RXOSINTTESTOVRDEN; + input RXOSOVRDEN; + input RXPCOMMAALIGNEN; + input RXPCSRESET; + input RXPHALIGN; + input RXPHALIGNEN; + input RXPHDLYPD; + input RXPHDLYRESET; + input RXPHOVRDEN; + input RXPMARESET; + input RXPOLARITY; + input RXPRBSCNTRESET; + input RXRATEMODE; + input RXSLIDE; + input RXSYNCALLIN; + input RXSYNCIN; + input RXSYNCMODE; + input RXUSERRDY; + input RXUSRCLK2; + input RXUSRCLK; + input SETERRSTATUS; + input SIGVALIDCLK; + input TX8B10BEN; + input TXCOMINIT; + input TXCOMSAS; + input TXCOMWAKE; + input TXDEEMPH; + input TXDETECTRX; + input TXDIFFPD; + input TXDLYBYPASS; + input TXDLYEN; + input TXDLYHOLD; + input TXDLYOVRDEN; + input TXDLYSRESET; + input TXDLYUPDOWN; + input TXELECIDLE; + input TXINHIBIT; + input TXPCSRESET; + input TXPDELECIDLEMODE; + input TXPHALIGN; + input TXPHALIGNEN; + input TXPHDLYPD; + input TXPHDLYRESET; + input TXPHDLYTSTCLK; + input TXPHINIT; + input TXPHOVRDEN; + input TXPIPPMEN; + input TXPIPPMOVRDEN; + input TXPIPPMPD; + input TXPIPPMSEL; + input TXPISOPD; + input TXPMARESET; + input TXPOLARITY; + input TXPOSTCURSORINV; + input TXPRBSFORCEERR; + input TXPRECURSORINV; + input TXRATEMODE; + input TXSTARTSEQ; + input TXSWING; + input TXSYNCALLIN; + input TXSYNCIN; + input TXSYNCMODE; + input TXUSERRDY; + input TXUSRCLK2; + input TXUSRCLK; + input [13:0] RXADAPTSELTEST; + input [15:0] DRPDI; + input [15:0] GTRSVD; + input [15:0] PCSRSVDIN; + input [19:0] TSTIN; + input [1:0] RXELECIDLEMODE; + input [1:0] RXPD; + input [1:0] RXSYSCLKSEL; + input [1:0] TXPD; + input [1:0] TXSYSCLKSEL; + input [2:0] LOOPBACK; + input [2:0] RXCHBONDLEVEL; + input [2:0] RXOUTCLKSEL; + input [2:0] RXPRBSSEL; + input [2:0] RXRATE; + input [2:0] TXBUFDIFFCTRL; + input [2:0] TXHEADER; + input [2:0] TXMARGIN; + input [2:0] TXOUTCLKSEL; + input [2:0] TXPRBSSEL; + input [2:0] TXRATE; + input [31:0] TXDATA; + input [3:0] RXCHBONDI; + input [3:0] RXOSINTCFG; + input [3:0] RXOSINTID0; + input [3:0] TX8B10BBYPASS; + input [3:0] TXCHARDISPMODE; + input [3:0] TXCHARDISPVAL; + input [3:0] TXCHARISK; + input [3:0] TXDIFFCTRL; + input [4:0] TXPIPPMSTEPSIZE; + input [4:0] TXPOSTCURSOR; + input [4:0] TXPRECURSOR; + input [6:0] TXMAINCURSOR; + input [6:0] TXSEQUENCE; + input [8:0] DRPADDR; +endmodule + +module GTPE2_COMMON (...); + parameter [63:0] BIAS_CFG = 64'h0000000000000000; + parameter [31:0] COMMON_CFG = 32'h00000000; + parameter [0:0] IS_DRPCLK_INVERTED = 1'b0; + parameter [0:0] IS_GTGREFCLK0_INVERTED = 1'b0; + parameter [0:0] IS_GTGREFCLK1_INVERTED = 1'b0; + parameter [0:0] IS_PLL0LOCKDETCLK_INVERTED = 1'b0; + parameter [0:0] IS_PLL1LOCKDETCLK_INVERTED = 1'b0; + parameter [26:0] PLL0_CFG = 27'h01F03DC; + parameter [0:0] PLL0_DMON_CFG = 1'b0; + parameter integer PLL0_FBDIV = 4; + parameter integer PLL0_FBDIV_45 = 5; + parameter [23:0] PLL0_INIT_CFG = 24'h00001E; + parameter [8:0] PLL0_LOCK_CFG = 9'h1E8; + parameter integer PLL0_REFCLK_DIV = 1; + parameter [26:0] PLL1_CFG = 27'h01F03DC; + parameter [0:0] PLL1_DMON_CFG = 1'b0; + parameter integer PLL1_FBDIV = 4; + parameter integer PLL1_FBDIV_45 = 5; + parameter [23:0] PLL1_INIT_CFG = 24'h00001E; + parameter [8:0] PLL1_LOCK_CFG = 9'h1E8; + parameter integer PLL1_REFCLK_DIV = 1; + parameter [7:0] PLL_CLKOUT_CFG = 8'b00000000; + parameter [15:0] RSVD_ATTR0 = 16'h0000; + parameter [15:0] RSVD_ATTR1 = 16'h0000; + parameter [2:0] SIM_PLL0REFCLK_SEL = 3'b001; + parameter [2:0] SIM_PLL1REFCLK_SEL = 3'b001; + parameter SIM_RESET_SPEEDUP = "TRUE"; + parameter SIM_VERSION = "1.0"; + output DRPRDY; + output PLL0FBCLKLOST; + output PLL0LOCK; + output PLL0OUTCLK; + output PLL0OUTREFCLK; + output PLL0REFCLKLOST; + output PLL1FBCLKLOST; + output PLL1LOCK; + output PLL1OUTCLK; + output PLL1OUTREFCLK; + output PLL1REFCLKLOST; + output REFCLKOUTMONITOR0; + output REFCLKOUTMONITOR1; + output [15:0] DRPDO; + output [15:0] PMARSVDOUT; + output [7:0] DMONITOROUT; + input BGBYPASSB; + input BGMONITORENB; + input BGPDB; + input BGRCALOVRDENB; + input DRPCLK; + input DRPEN; + input DRPWE; + input GTEASTREFCLK0; + input GTEASTREFCLK1; + input GTGREFCLK0; + input GTGREFCLK1; + input GTREFCLK0; + input GTREFCLK1; + input GTWESTREFCLK0; + input GTWESTREFCLK1; + input PLL0LOCKDETCLK; + input PLL0LOCKEN; + input PLL0PD; + input PLL0RESET; + input PLL1LOCKDETCLK; + input PLL1LOCKEN; + input PLL1PD; + input PLL1RESET; + input RCALENB; + input [15:0] DRPDI; + input [15:0] PLLRSVD1; + input [2:0] PLL0REFCLKSEL; + input [2:0] PLL1REFCLKSEL; + input [4:0] BGRCALOVRD; + input [4:0] PLLRSVD2; + input [7:0] DRPADDR; + input [7:0] PMARSVD; +endmodule + +module GTXE2_CHANNEL (...); + parameter ALIGN_COMMA_DOUBLE = "FALSE"; + parameter [9:0] ALIGN_COMMA_ENABLE = 10'b0001111111; + parameter integer ALIGN_COMMA_WORD = 1; + parameter ALIGN_MCOMMA_DET = "TRUE"; + parameter [9:0] ALIGN_MCOMMA_VALUE = 10'b1010000011; + parameter ALIGN_PCOMMA_DET = "TRUE"; + parameter [9:0] ALIGN_PCOMMA_VALUE = 10'b0101111100; + parameter CBCC_DATA_SOURCE_SEL = "DECODED"; + parameter CHAN_BOND_KEEP_ALIGN = "FALSE"; + parameter integer CHAN_BOND_MAX_SKEW = 7; + parameter [9:0] CHAN_BOND_SEQ_1_1 = 10'b0101111100; + parameter [9:0] CHAN_BOND_SEQ_1_2 = 10'b0000000000; + parameter [9:0] CHAN_BOND_SEQ_1_3 = 10'b0000000000; + parameter [9:0] CHAN_BOND_SEQ_1_4 = 10'b0000000000; + parameter [3:0] CHAN_BOND_SEQ_1_ENABLE = 4'b1111; + parameter [9:0] CHAN_BOND_SEQ_2_1 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_2 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_3 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_4 = 10'b0100000000; + parameter [3:0] CHAN_BOND_SEQ_2_ENABLE = 4'b1111; + parameter CHAN_BOND_SEQ_2_USE = "FALSE"; + parameter integer CHAN_BOND_SEQ_LEN = 1; + parameter CLK_CORRECT_USE = "TRUE"; + parameter CLK_COR_KEEP_IDLE = "FALSE"; + parameter integer CLK_COR_MAX_LAT = 20; + parameter integer CLK_COR_MIN_LAT = 18; + parameter CLK_COR_PRECEDENCE = "TRUE"; + parameter integer CLK_COR_REPEAT_WAIT = 0; + parameter [9:0] CLK_COR_SEQ_1_1 = 10'b0100011100; + parameter [9:0] CLK_COR_SEQ_1_2 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_3 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_4 = 10'b0000000000; + parameter [3:0] CLK_COR_SEQ_1_ENABLE = 4'b1111; + parameter [9:0] CLK_COR_SEQ_2_1 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_2 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_3 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_4 = 10'b0100000000; + parameter [3:0] CLK_COR_SEQ_2_ENABLE = 4'b1111; + parameter CLK_COR_SEQ_2_USE = "FALSE"; + parameter integer CLK_COR_SEQ_LEN = 1; + parameter [23:0] CPLL_CFG = 24'hB007D8; + parameter integer CPLL_FBDIV = 4; + parameter integer CPLL_FBDIV_45 = 5; + parameter [23:0] CPLL_INIT_CFG = 24'h00001E; + parameter [15:0] CPLL_LOCK_CFG = 16'h01E8; + parameter integer CPLL_REFCLK_DIV = 1; + parameter DEC_MCOMMA_DETECT = "TRUE"; + parameter DEC_PCOMMA_DETECT = "TRUE"; + parameter DEC_VALID_COMMA_ONLY = "TRUE"; + parameter [23:0] DMONITOR_CFG = 24'h000A00; + parameter [5:0] ES_CONTROL = 6'b000000; + parameter ES_ERRDET_EN = "FALSE"; + parameter ES_EYE_SCAN_EN = "FALSE"; + parameter [11:0] ES_HORZ_OFFSET = 12'h000; + parameter [9:0] ES_PMA_CFG = 10'b0000000000; + parameter [4:0] ES_PRESCALE = 5'b00000; + parameter [79:0] ES_QUALIFIER = 80'h00000000000000000000; + parameter [79:0] ES_QUAL_MASK = 80'h00000000000000000000; + parameter [79:0] ES_SDATA_MASK = 80'h00000000000000000000; + parameter [8:0] ES_VERT_OFFSET = 9'b000000000; + parameter [3:0] FTS_DESKEW_SEQ_ENABLE = 4'b1111; + parameter [3:0] FTS_LANE_DESKEW_CFG = 4'b1111; + parameter FTS_LANE_DESKEW_EN = "FALSE"; + parameter [2:0] GEARBOX_MODE = 3'b000; + parameter [0:0] IS_CPLLLOCKDETCLK_INVERTED = 1'b0; + parameter [0:0] IS_DRPCLK_INVERTED = 1'b0; + parameter [0:0] IS_GTGREFCLK_INVERTED = 1'b0; + parameter [0:0] IS_RXUSRCLK2_INVERTED = 1'b0; + parameter [0:0] IS_RXUSRCLK_INVERTED = 1'b0; + parameter [0:0] IS_TXPHDLYTSTCLK_INVERTED = 1'b0; + parameter [0:0] IS_TXUSRCLK2_INVERTED = 1'b0; + parameter [0:0] IS_TXUSRCLK_INVERTED = 1'b0; + parameter [1:0] OUTREFCLK_SEL_INV = 2'b11; + parameter PCS_PCIE_EN = "FALSE"; + parameter [47:0] PCS_RSVD_ATTR = 48'h000000000000; + parameter [11:0] PD_TRANS_TIME_FROM_P2 = 12'h03C; + parameter [7:0] PD_TRANS_TIME_NONE_P2 = 8'h19; + parameter [7:0] PD_TRANS_TIME_TO_P2 = 8'h64; + parameter [31:0] PMA_RSV = 32'h00000000; + parameter [15:0] PMA_RSV2 = 16'h2050; + parameter [1:0] PMA_RSV3 = 2'b00; + parameter [31:0] PMA_RSV4 = 32'h00000000; + parameter [4:0] RXBUFRESET_TIME = 5'b00001; + parameter RXBUF_ADDR_MODE = "FULL"; + parameter [3:0] RXBUF_EIDLE_HI_CNT = 4'b1000; + parameter [3:0] RXBUF_EIDLE_LO_CNT = 4'b0000; + parameter RXBUF_EN = "TRUE"; + parameter RXBUF_RESET_ON_CB_CHANGE = "TRUE"; + parameter RXBUF_RESET_ON_COMMAALIGN = "FALSE"; + parameter RXBUF_RESET_ON_EIDLE = "FALSE"; + parameter RXBUF_RESET_ON_RATE_CHANGE = "TRUE"; + parameter integer RXBUF_THRESH_OVFLW = 61; + parameter RXBUF_THRESH_OVRD = "FALSE"; + parameter integer RXBUF_THRESH_UNDFLW = 4; + parameter [4:0] RXCDRFREQRESET_TIME = 5'b00001; + parameter [4:0] RXCDRPHRESET_TIME = 5'b00001; + parameter [71:0] RXCDR_CFG = 72'h0B000023FF20400020; + parameter [0:0] RXCDR_FR_RESET_ON_EIDLE = 1'b0; + parameter [0:0] RXCDR_HOLD_DURING_EIDLE = 1'b0; + parameter [5:0] RXCDR_LOCK_CFG = 6'b010101; + parameter [0:0] RXCDR_PH_RESET_ON_EIDLE = 1'b0; + parameter [6:0] RXDFELPMRESET_TIME = 7'b0001111; + parameter [15:0] RXDLY_CFG = 16'h001F; + parameter [8:0] RXDLY_LCFG = 9'h030; + parameter [15:0] RXDLY_TAP_CFG = 16'h0000; + parameter RXGEARBOX_EN = "FALSE"; + parameter [4:0] RXISCANRESET_TIME = 5'b00001; + parameter [13:0] RXLPM_HF_CFG = 14'b00000011110000; + parameter [13:0] RXLPM_LF_CFG = 14'b00000011110000; + parameter [6:0] RXOOB_CFG = 7'b0000110; + parameter integer RXOUT_DIV = 2; + parameter [4:0] RXPCSRESET_TIME = 5'b00001; + parameter [23:0] RXPHDLY_CFG = 24'h084020; + parameter [23:0] RXPH_CFG = 24'h000000; + parameter [4:0] RXPH_MONITOR_SEL = 5'b00000; + parameter [4:0] RXPMARESET_TIME = 5'b00011; + parameter [0:0] RXPRBS_ERR_LOOPBACK = 1'b0; + parameter integer RXSLIDE_AUTO_WAIT = 7; + parameter RXSLIDE_MODE = "OFF"; + parameter [11:0] RX_BIAS_CFG = 12'b000000000000; + parameter [5:0] RX_BUFFER_CFG = 6'b000000; + parameter integer RX_CLK25_DIV = 7; + parameter [0:0] RX_CLKMUX_PD = 1'b1; + parameter [1:0] RX_CM_SEL = 2'b11; + parameter [2:0] RX_CM_TRIM = 3'b100; + parameter integer RX_DATA_WIDTH = 20; + parameter [5:0] RX_DDI_SEL = 6'b000000; + parameter [11:0] RX_DEBUG_CFG = 12'b000000000000; + parameter RX_DEFER_RESET_BUF_EN = "TRUE"; + parameter [22:0] RX_DFE_GAIN_CFG = 23'h180E0F; + parameter [11:0] RX_DFE_H2_CFG = 12'b000111100000; + parameter [11:0] RX_DFE_H3_CFG = 12'b000111100000; + parameter [10:0] RX_DFE_H4_CFG = 11'b00011110000; + parameter [10:0] RX_DFE_H5_CFG = 11'b00011110000; + parameter [12:0] RX_DFE_KL_CFG = 13'b0001111110000; + parameter [31:0] RX_DFE_KL_CFG2 = 32'h3008E56A; + parameter [15:0] RX_DFE_LPM_CFG = 16'h0904; + parameter [0:0] RX_DFE_LPM_HOLD_DURING_EIDLE = 1'b0; + parameter [16:0] RX_DFE_UT_CFG = 17'b00111111000000000; + parameter [16:0] RX_DFE_VP_CFG = 17'b00011111100000000; + parameter [12:0] RX_DFE_XYD_CFG = 13'b0000000010000; + parameter RX_DISPERR_SEQ_MATCH = "TRUE"; + parameter integer RX_INT_DATAWIDTH = 0; + parameter [12:0] RX_OS_CFG = 13'b0001111110000; + parameter integer RX_SIG_VALID_DLY = 10; + parameter RX_XCLK_SEL = "RXREC"; + parameter integer SAS_MAX_COM = 64; + parameter integer SAS_MIN_COM = 36; + parameter [3:0] SATA_BURST_SEQ_LEN = 4'b1111; + parameter [2:0] SATA_BURST_VAL = 3'b100; + parameter SATA_CPLL_CFG = "VCO_3000MHZ"; + parameter [2:0] SATA_EIDLE_VAL = 3'b100; + parameter integer SATA_MAX_BURST = 8; + parameter integer SATA_MAX_INIT = 21; + parameter integer SATA_MAX_WAKE = 7; + parameter integer SATA_MIN_BURST = 4; + parameter integer SATA_MIN_INIT = 12; + parameter integer SATA_MIN_WAKE = 4; + parameter SHOW_REALIGN_COMMA = "TRUE"; + parameter [2:0] SIM_CPLLREFCLK_SEL = 3'b001; + parameter SIM_RECEIVER_DETECT_PASS = "TRUE"; + parameter SIM_RESET_SPEEDUP = "TRUE"; + parameter SIM_TX_EIDLE_DRIVE_LEVEL = "X"; + parameter SIM_VERSION = "4.0"; + parameter [4:0] TERM_RCAL_CFG = 5'b10000; + parameter [0:0] TERM_RCAL_OVRD = 1'b0; + parameter [7:0] TRANS_TIME_RATE = 8'h0E; + parameter [31:0] TST_RSV = 32'h00000000; + parameter TXBUF_EN = "TRUE"; + parameter TXBUF_RESET_ON_RATE_CHANGE = "FALSE"; + parameter [15:0] TXDLY_CFG = 16'h001F; + parameter [8:0] TXDLY_LCFG = 9'h030; + parameter [15:0] TXDLY_TAP_CFG = 16'h0000; + parameter TXGEARBOX_EN = "FALSE"; + parameter integer TXOUT_DIV = 2; + parameter [4:0] TXPCSRESET_TIME = 5'b00001; + parameter [23:0] TXPHDLY_CFG = 24'h084020; + parameter [15:0] TXPH_CFG = 16'h0780; + parameter [4:0] TXPH_MONITOR_SEL = 5'b00000; + parameter [4:0] TXPMARESET_TIME = 5'b00001; + parameter integer TX_CLK25_DIV = 7; + parameter [0:0] TX_CLKMUX_PD = 1'b1; + parameter integer TX_DATA_WIDTH = 20; + parameter [4:0] TX_DEEMPH0 = 5'b00000; + parameter [4:0] TX_DEEMPH1 = 5'b00000; + parameter TX_DRIVE_MODE = "DIRECT"; + parameter [2:0] TX_EIDLE_ASSERT_DELAY = 3'b110; + parameter [2:0] TX_EIDLE_DEASSERT_DELAY = 3'b100; + parameter integer TX_INT_DATAWIDTH = 0; + parameter TX_LOOPBACK_DRIVE_HIZ = "FALSE"; + parameter [0:0] TX_MAINCURSOR_SEL = 1'b0; + parameter [6:0] TX_MARGIN_FULL_0 = 7'b1001110; + parameter [6:0] TX_MARGIN_FULL_1 = 7'b1001001; + parameter [6:0] TX_MARGIN_FULL_2 = 7'b1000101; + parameter [6:0] TX_MARGIN_FULL_3 = 7'b1000010; + parameter [6:0] TX_MARGIN_FULL_4 = 7'b1000000; + parameter [6:0] TX_MARGIN_LOW_0 = 7'b1000110; + parameter [6:0] TX_MARGIN_LOW_1 = 7'b1000100; + parameter [6:0] TX_MARGIN_LOW_2 = 7'b1000010; + parameter [6:0] TX_MARGIN_LOW_3 = 7'b1000000; + parameter [6:0] TX_MARGIN_LOW_4 = 7'b1000000; + parameter [0:0] TX_PREDRIVER_MODE = 1'b0; + parameter [0:0] TX_QPI_STATUS_EN = 1'b0; + parameter [13:0] TX_RXDETECT_CFG = 14'h1832; + parameter [2:0] TX_RXDETECT_REF = 3'b100; + parameter TX_XCLK_SEL = "TXUSR"; + parameter [0:0] UCODEER_CLR = 1'b0; + output CPLLFBCLKLOST; + output CPLLLOCK; + output CPLLREFCLKLOST; + output DRPRDY; + output EYESCANDATAERROR; + output GTREFCLKMONITOR; + output GTXTXN; + output GTXTXP; + output PHYSTATUS; + output RXBYTEISALIGNED; + output RXBYTEREALIGN; + output RXCDRLOCK; + output RXCHANBONDSEQ; + output RXCHANISALIGNED; + output RXCHANREALIGN; + output RXCOMINITDET; + output RXCOMMADET; + output RXCOMSASDET; + output RXCOMWAKEDET; + output RXDATAVALID; + output RXDLYSRESETDONE; + output RXELECIDLE; + output RXHEADERVALID; + output RXOUTCLK; + output RXOUTCLKFABRIC; + output RXOUTCLKPCS; + output RXPHALIGNDONE; + output RXPRBSERR; + output RXQPISENN; + output RXQPISENP; + output RXRATEDONE; + output RXRESETDONE; + output RXSTARTOFSEQ; + output RXVALID; + output TXCOMFINISH; + output TXDLYSRESETDONE; + output TXGEARBOXREADY; + output TXOUTCLK; + output TXOUTCLKFABRIC; + output TXOUTCLKPCS; + output TXPHALIGNDONE; + output TXPHINITDONE; + output TXQPISENN; + output TXQPISENP; + output TXRATEDONE; + output TXRESETDONE; + output [15:0] DRPDO; + output [15:0] PCSRSVDOUT; + output [1:0] RXCLKCORCNT; + output [1:0] TXBUFSTATUS; + output [2:0] RXBUFSTATUS; + output [2:0] RXHEADER; + output [2:0] RXSTATUS; + output [4:0] RXCHBONDO; + output [4:0] RXPHMONITOR; + output [4:0] RXPHSLIPMONITOR; + output [63:0] RXDATA; + output [6:0] RXMONITOROUT; + output [7:0] DMONITOROUT; + output [7:0] RXCHARISCOMMA; + output [7:0] RXCHARISK; + output [7:0] RXDISPERR; + output [7:0] RXNOTINTABLE; + output [9:0] TSTOUT; + input CFGRESET; + input CPLLLOCKDETCLK; + input CPLLLOCKEN; + input CPLLPD; + input CPLLRESET; + input DRPCLK; + input DRPEN; + input DRPWE; + input EYESCANMODE; + input EYESCANRESET; + input EYESCANTRIGGER; + input GTGREFCLK; + input GTNORTHREFCLK0; + input GTNORTHREFCLK1; + input GTREFCLK0; + input GTREFCLK1; + input GTRESETSEL; + input GTRXRESET; + input GTSOUTHREFCLK0; + input GTSOUTHREFCLK1; + input GTTXRESET; + input GTXRXN; + input GTXRXP; + input QPLLCLK; + input QPLLREFCLK; + input RESETOVRD; + input RX8B10BEN; + input RXBUFRESET; + input RXCDRFREQRESET; + input RXCDRHOLD; + input RXCDROVRDEN; + input RXCDRRESET; + input RXCDRRESETRSV; + input RXCHBONDEN; + input RXCHBONDMASTER; + input RXCHBONDSLAVE; + input RXCOMMADETEN; + input RXDDIEN; + input RXDFEAGCHOLD; + input RXDFEAGCOVRDEN; + input RXDFECM1EN; + input RXDFELFHOLD; + input RXDFELFOVRDEN; + input RXDFELPMRESET; + input RXDFETAP2HOLD; + input RXDFETAP2OVRDEN; + input RXDFETAP3HOLD; + input RXDFETAP3OVRDEN; + input RXDFETAP4HOLD; + input RXDFETAP4OVRDEN; + input RXDFETAP5HOLD; + input RXDFETAP5OVRDEN; + input RXDFEUTHOLD; + input RXDFEUTOVRDEN; + input RXDFEVPHOLD; + input RXDFEVPOVRDEN; + input RXDFEVSEN; + input RXDFEXYDEN; + input RXDFEXYDHOLD; + input RXDFEXYDOVRDEN; + input RXDLYBYPASS; + input RXDLYEN; + input RXDLYOVRDEN; + input RXDLYSRESET; + input RXGEARBOXSLIP; + input RXLPMEN; + input RXLPMHFHOLD; + input RXLPMHFOVRDEN; + input RXLPMLFHOLD; + input RXLPMLFKLOVRDEN; + input RXMCOMMAALIGNEN; + input RXOOBRESET; + input RXOSHOLD; + input RXOSOVRDEN; + input RXPCOMMAALIGNEN; + input RXPCSRESET; + input RXPHALIGN; + input RXPHALIGNEN; + input RXPHDLYPD; + input RXPHDLYRESET; + input RXPHOVRDEN; + input RXPMARESET; + input RXPOLARITY; + input RXPRBSCNTRESET; + input RXQPIEN; + input RXSLIDE; + input RXUSERRDY; + input RXUSRCLK2; + input RXUSRCLK; + input SETERRSTATUS; + input TX8B10BEN; + input TXCOMINIT; + input TXCOMSAS; + input TXCOMWAKE; + input TXDEEMPH; + input TXDETECTRX; + input TXDIFFPD; + input TXDLYBYPASS; + input TXDLYEN; + input TXDLYHOLD; + input TXDLYOVRDEN; + input TXDLYSRESET; + input TXDLYUPDOWN; + input TXELECIDLE; + input TXINHIBIT; + input TXPCSRESET; + input TXPDELECIDLEMODE; + input TXPHALIGN; + input TXPHALIGNEN; + input TXPHDLYPD; + input TXPHDLYRESET; + input TXPHDLYTSTCLK; + input TXPHINIT; + input TXPHOVRDEN; + input TXPISOPD; + input TXPMARESET; + input TXPOLARITY; + input TXPOSTCURSORINV; + input TXPRBSFORCEERR; + input TXPRECURSORINV; + input TXQPIBIASEN; + input TXQPISTRONGPDOWN; + input TXQPIWEAKPUP; + input TXSTARTSEQ; + input TXSWING; + input TXUSERRDY; + input TXUSRCLK2; + input TXUSRCLK; + input [15:0] DRPDI; + input [15:0] GTRSVD; + input [15:0] PCSRSVDIN; + input [19:0] TSTIN; + input [1:0] RXELECIDLEMODE; + input [1:0] RXMONITORSEL; + input [1:0] RXPD; + input [1:0] RXSYSCLKSEL; + input [1:0] TXPD; + input [1:0] TXSYSCLKSEL; + input [2:0] CPLLREFCLKSEL; + input [2:0] LOOPBACK; + input [2:0] RXCHBONDLEVEL; + input [2:0] RXOUTCLKSEL; + input [2:0] RXPRBSSEL; + input [2:0] RXRATE; + input [2:0] TXBUFDIFFCTRL; + input [2:0] TXHEADER; + input [2:0] TXMARGIN; + input [2:0] TXOUTCLKSEL; + input [2:0] TXPRBSSEL; + input [2:0] TXRATE; + input [3:0] CLKRSVD; + input [3:0] TXDIFFCTRL; + input [4:0] PCSRSVDIN2; + input [4:0] PMARSVDIN2; + input [4:0] PMARSVDIN; + input [4:0] RXCHBONDI; + input [4:0] TXPOSTCURSOR; + input [4:0] TXPRECURSOR; + input [63:0] TXDATA; + input [6:0] TXMAINCURSOR; + input [6:0] TXSEQUENCE; + input [7:0] TX8B10BBYPASS; + input [7:0] TXCHARDISPMODE; + input [7:0] TXCHARDISPVAL; + input [7:0] TXCHARISK; + input [8:0] DRPADDR; +endmodule + +module GTXE2_COMMON (...); + parameter [63:0] BIAS_CFG = 64'h0000040000001000; + parameter [31:0] COMMON_CFG = 32'h00000000; + parameter [0:0] IS_DRPCLK_INVERTED = 1'b0; + parameter [0:0] IS_GTGREFCLK_INVERTED = 1'b0; + parameter [0:0] IS_QPLLLOCKDETCLK_INVERTED = 1'b0; + parameter [26:0] QPLL_CFG = 27'h0680181; + parameter [3:0] QPLL_CLKOUT_CFG = 4'b0000; + parameter [5:0] QPLL_COARSE_FREQ_OVRD = 6'b010000; + parameter [0:0] QPLL_COARSE_FREQ_OVRD_EN = 1'b0; + parameter [9:0] QPLL_CP = 10'b0000011111; + parameter [0:0] QPLL_CP_MONITOR_EN = 1'b0; + parameter [0:0] QPLL_DMONITOR_SEL = 1'b0; + parameter [9:0] QPLL_FBDIV = 10'b0000000000; + parameter [0:0] QPLL_FBDIV_MONITOR_EN = 1'b0; + parameter [0:0] QPLL_FBDIV_RATIO = 1'b0; + parameter [23:0] QPLL_INIT_CFG = 24'h000006; + parameter [15:0] QPLL_LOCK_CFG = 16'h21E8; + parameter [3:0] QPLL_LPF = 4'b1111; + parameter integer QPLL_REFCLK_DIV = 2; + parameter [2:0] SIM_QPLLREFCLK_SEL = 3'b001; + parameter SIM_RESET_SPEEDUP = "TRUE"; + parameter SIM_VERSION = "4.0"; + output DRPRDY; + output QPLLFBCLKLOST; + output QPLLLOCK; + output QPLLOUTCLK; + output QPLLOUTREFCLK; + output QPLLREFCLKLOST; + output REFCLKOUTMONITOR; + output [15:0] DRPDO; + output [7:0] QPLLDMONITOR; + input BGBYPASSB; + input BGMONITORENB; + input BGPDB; + input DRPCLK; + input DRPEN; + input DRPWE; + input GTGREFCLK; + input GTNORTHREFCLK0; + input GTNORTHREFCLK1; + input GTREFCLK0; + input GTREFCLK1; + input GTSOUTHREFCLK0; + input GTSOUTHREFCLK1; + input QPLLLOCKDETCLK; + input QPLLLOCKEN; + input QPLLOUTRESET; + input QPLLPD; + input QPLLRESET; + input RCALENB; + input [15:0] DRPDI; + input [15:0] QPLLRSVD1; + input [2:0] QPLLREFCLKSEL; + input [4:0] BGRCALOVRD; + input [4:0] QPLLRSVD2; + input [7:0] DRPADDR; + input [7:0] PMARSVD; +endmodule + +module IBUF_IBUFDISABLE (...); + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + input I; + input IBUFDISABLE; +endmodule + +module IBUF_INTERMDISABLE (...); + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + input I; + input IBUFDISABLE; + input INTERMDISABLE; +endmodule + +module IBUFDS (...); + parameter CAPACITANCE = "DONT_CARE"; + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_DELAY_VALUE = "0"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IFD_DELAY_VALUE = "AUTO"; + parameter IOSTANDARD = "DEFAULT"; + output O; + input I, IB; +endmodule + +module IBUFDS_DIFF_OUT (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + output O, OB; + input I, IB; +endmodule + +module IBUFDS_DIFF_OUT_IBUFDISABLE (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + output OB; + input I; + input IB; + input IBUFDISABLE; +endmodule + +module IBUFDS_DIFF_OUT_INTERMDISABLE (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + output OB; + input I; + input IB; + input IBUFDISABLE; + input INTERMDISABLE; +endmodule + +module IBUFDS_GTE2 (...); + parameter CLKCM_CFG = "TRUE"; + parameter CLKRCV_TRST = "TRUE"; + parameter CLKSWING_CFG = "TRUE"; + output O; + output ODIV2; + input CEB; + input I; + input IB; +endmodule + +module IBUFDS_IBUFDISABLE (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + input I; + input IB; + input IBUFDISABLE; +endmodule + +module IBUFDS_INTERMDISABLE (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + input I; + input IB; + input IBUFDISABLE; + input INTERMDISABLE; +endmodule + +module ICAPE2 (...); + parameter [31:0] DEVICE_ID = 32'h04244093; + parameter ICAP_WIDTH = "X32"; + parameter SIM_CFG_FILE_NAME = "NONE"; + output [31:0] O; + input CLK; + input CSIB; + input RDWRB; + input [31:0] I; +endmodule + +module IDDR (...); + parameter DDR_CLK_EDGE = "OPPOSITE_EDGE"; + parameter INIT_Q1 = 1'b0; + parameter INIT_Q2 = 1'b0; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_D_INVERTED = 1'b0; + parameter SRTYPE = "SYNC"; + parameter MSGON = "TRUE"; + parameter XON = "TRUE"; + output Q1; + output Q2; + input C; + input CE; + input D; + input R; + input S; +endmodule + +module IDDR_2CLK (...); + parameter DDR_CLK_EDGE = "OPPOSITE_EDGE"; + parameter INIT_Q1 = 1'b0; + parameter INIT_Q2 = 1'b0; + parameter [0:0] IS_CB_INVERTED = 1'b0; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_D_INVERTED = 1'b0; + parameter SRTYPE = "SYNC"; + output Q1; + output Q2; + input C; + input CB; + input CE; + input D; + input R; + input S; +endmodule + +module IDELAYCTRL (...); + parameter SIM_DEVICE = "7SERIES"; + output RDY; + input REFCLK; + input RST; +endmodule + +module IDELAYE2 (...); + parameter CINVCTRL_SEL = "FALSE"; + parameter DELAY_SRC = "IDATAIN"; + parameter HIGH_PERFORMANCE_MODE = "FALSE"; + parameter IDELAY_TYPE = "FIXED"; + parameter integer IDELAY_VALUE = 0; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_DATAIN_INVERTED = 1'b0; + parameter [0:0] IS_IDATAIN_INVERTED = 1'b0; + parameter PIPE_SEL = "FALSE"; + parameter real REFCLK_FREQUENCY = 200.0; + parameter SIGNAL_PATTERN = "DATA"; + parameter integer SIM_DELAY_D = 0; + output [4:0] CNTVALUEOUT; + output DATAOUT; + input C; + input CE; + input CINVCTRL; + input [4:0] CNTVALUEIN; + input DATAIN; + input IDATAIN; + input INC; + input LD; + input LDPIPEEN; + input REGRST; +endmodule + +module IN_FIFO (...); + parameter integer ALMOST_EMPTY_VALUE = 1; + parameter integer ALMOST_FULL_VALUE = 1; + parameter ARRAY_MODE = "ARRAY_MODE_4_X_8"; + parameter SYNCHRONOUS_MODE = "FALSE"; + output ALMOSTEMPTY; + output ALMOSTFULL; + output EMPTY; + output FULL; + output [7:0] Q0; + output [7:0] Q1; + output [7:0] Q2; + output [7:0] Q3; + output [7:0] Q4; + output [7:0] Q5; + output [7:0] Q6; + output [7:0] Q7; + output [7:0] Q8; + output [7:0] Q9; + input RDCLK; + input RDEN; + input RESET; + input WRCLK; + input WREN; + input [3:0] D0; + input [3:0] D1; + input [3:0] D2; + input [3:0] D3; + input [3:0] D4; + input [3:0] D7; + input [3:0] D8; + input [3:0] D9; + input [7:0] D5; + input [7:0] D6; +endmodule + +module IOBUF (...); + parameter integer DRIVE = 12; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SLEW = "SLOW"; + output O; + input I, T; +endmodule + +module IOBUF_DCIEN (...); + parameter integer DRIVE = 12; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter SLEW = "SLOW"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + input DCITERMDISABLE; + input I; + input IBUFDISABLE; + input T; +endmodule + +module IOBUF_INTERMDISABLE (...); + parameter integer DRIVE = 12; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter SLEW = "SLOW"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + input I; + input IBUFDISABLE; + input INTERMDISABLE; + input T; +endmodule + +module IOBUFDS (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SLEW = "SLOW"; + output O; + input I, T; +endmodule + +module IOBUFDS_DCIEN (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter SLEW = "SLOW"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + input DCITERMDISABLE; + input I; + input IBUFDISABLE; + input T; +endmodule + +module IOBUFDS_DIFF_OUT (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + output O; + output OB; + input I; + input TM; + input TS; +endmodule + +module IOBUFDS_DIFF_OUT_DCIEN (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + output OB; + input DCITERMDISABLE; + input I; + input IBUFDISABLE; + input TM; + input TS; +endmodule + +module IOBUFDS_DIFF_OUT_INTERMDISABLE (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + output OB; + input I; + input IBUFDISABLE; + input INTERMDISABLE; + input TM; + input TS; +endmodule + +module ISERDESE2 (...); + parameter DATA_RATE = "DDR"; + parameter integer DATA_WIDTH = 4; + parameter DYN_CLKDIV_INV_EN = "FALSE"; + parameter DYN_CLK_INV_EN = "FALSE"; + parameter [0:0] INIT_Q1 = 1'b0; + parameter [0:0] INIT_Q2 = 1'b0; + parameter [0:0] INIT_Q3 = 1'b0; + parameter [0:0] INIT_Q4 = 1'b0; + parameter INTERFACE_TYPE = "MEMORY"; + parameter IOBDELAY = "NONE"; + parameter [0:0] IS_CLKB_INVERTED = 1'b0; + parameter [0:0] IS_CLKDIVP_INVERTED = 1'b0; + parameter [0:0] IS_CLKDIV_INVERTED = 1'b0; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + parameter [0:0] IS_D_INVERTED = 1'b0; + parameter [0:0] IS_OCLKB_INVERTED = 1'b0; + parameter [0:0] IS_OCLK_INVERTED = 1'b0; + parameter integer NUM_CE = 2; + parameter OFB_USED = "FALSE"; + parameter SERDES_MODE = "MASTER"; + parameter [0:0] SRVAL_Q1 = 1'b0; + parameter [0:0] SRVAL_Q2 = 1'b0; + parameter [0:0] SRVAL_Q3 = 1'b0; + parameter [0:0] SRVAL_Q4 = 1'b0; + output O; + output Q1; + output Q2; + output Q3; + output Q4; + output Q5; + output Q6; + output Q7; + output Q8; + output SHIFTOUT1; + output SHIFTOUT2; + input BITSLIP; + input CE1; + input CE2; + input CLK; + input CLKB; + input CLKDIV; + input CLKDIVP; + input D; + input DDLY; + input DYNCLKDIVSEL; + input DYNCLKSEL; + input OCLK; + input OCLKB; + input OFB; + input RST; + input SHIFTIN1; + input SHIFTIN2; +endmodule + +module KEEPER (...); +endmodule + +module LDCE (...); + parameter [0:0] INIT = 1'b0; + parameter [0:0] IS_CLR_INVERTED = 1'b0; + parameter [0:0] IS_G_INVERTED = 1'b0; + parameter MSGON = "TRUE"; + parameter XON = "TRUE"; + output Q; + input CLR, D, G, GE; +endmodule + +module LDPE (...); + parameter [0:0] INIT = 1'b1; + parameter [0:0] IS_G_INVERTED = 1'b0; + parameter [0:0] IS_PRE_INVERTED = 1'b0; + parameter MSGON = "TRUE"; + parameter XON = "TRUE"; + output Q; + input D, G, GE, PRE; +endmodule + +module LUT6_2 (...); + parameter [63:0] INIT = 64'h0000000000000000; + input I0, I1, I2, I3, I4, I5; + output O5, O6; +endmodule + +module MMCME2_ADV (...); + parameter BANDWIDTH = "OPTIMIZED"; + parameter real CLKFBOUT_MULT_F = 5.000; + parameter real CLKFBOUT_PHASE = 0.000; + parameter CLKFBOUT_USE_FINE_PS = "FALSE"; + parameter real CLKIN1_PERIOD = 0.000; + parameter real CLKIN2_PERIOD = 0.000; + parameter real CLKIN_FREQ_MAX = 1066.000; + parameter real CLKIN_FREQ_MIN = 10.000; + parameter real CLKOUT0_DIVIDE_F = 1.000; + parameter real CLKOUT0_DUTY_CYCLE = 0.500; + parameter real CLKOUT0_PHASE = 0.000; + parameter CLKOUT0_USE_FINE_PS = "FALSE"; + parameter integer CLKOUT1_DIVIDE = 1; + parameter real CLKOUT1_DUTY_CYCLE = 0.500; + parameter real CLKOUT1_PHASE = 0.000; + parameter CLKOUT1_USE_FINE_PS = "FALSE"; + parameter integer CLKOUT2_DIVIDE = 1; + parameter real CLKOUT2_DUTY_CYCLE = 0.500; + parameter real CLKOUT2_PHASE = 0.000; + parameter CLKOUT2_USE_FINE_PS = "FALSE"; + parameter integer CLKOUT3_DIVIDE = 1; + parameter real CLKOUT3_DUTY_CYCLE = 0.500; + parameter real CLKOUT3_PHASE = 0.000; + parameter CLKOUT3_USE_FINE_PS = "FALSE"; + parameter CLKOUT4_CASCADE = "FALSE"; + parameter integer CLKOUT4_DIVIDE = 1; + parameter real CLKOUT4_DUTY_CYCLE = 0.500; + parameter real CLKOUT4_PHASE = 0.000; + parameter CLKOUT4_USE_FINE_PS = "FALSE"; + parameter integer CLKOUT5_DIVIDE = 1; + parameter real CLKOUT5_DUTY_CYCLE = 0.500; + parameter real CLKOUT5_PHASE = 0.000; + parameter CLKOUT5_USE_FINE_PS = "FALSE"; + parameter integer CLKOUT6_DIVIDE = 1; + parameter real CLKOUT6_DUTY_CYCLE = 0.500; + parameter real CLKOUT6_PHASE = 0.000; + parameter CLKOUT6_USE_FINE_PS = "FALSE"; + parameter real CLKPFD_FREQ_MAX = 550.000; + parameter real CLKPFD_FREQ_MIN = 10.000; + parameter COMPENSATION = "ZHOLD"; + parameter integer DIVCLK_DIVIDE = 1; + parameter [0:0] IS_CLKINSEL_INVERTED = 1'b0; + parameter [0:0] IS_PSEN_INVERTED = 1'b0; + parameter [0:0] IS_PSINCDEC_INVERTED = 1'b0; + parameter [0:0] IS_PWRDWN_INVERTED = 1'b0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter real REF_JITTER1 = 0.010; + parameter real REF_JITTER2 = 0.010; + parameter SS_EN = "FALSE"; + parameter SS_MODE = "CENTER_HIGH"; + parameter integer SS_MOD_PERIOD = 10000; + parameter STARTUP_WAIT = "FALSE"; + parameter real VCOCLK_FREQ_MAX = 1600.000; + parameter real VCOCLK_FREQ_MIN = 600.000; + parameter STARTUP_WAIT = "FALSE"; + output CLKFBOUT; + output CLKFBOUTB; + output CLKFBSTOPPED; + output CLKINSTOPPED; + output CLKOUT0; + output CLKOUT0B; + output CLKOUT1; + output CLKOUT1B; + output CLKOUT2; + output CLKOUT2B; + output CLKOUT3; + output CLKOUT3B; + output CLKOUT4; + output CLKOUT5; + output CLKOUT6; + output [15:0] DO; + output DRDY; + output LOCKED; + output PSDONE; + input CLKFBIN; + input CLKIN1; + input CLKIN2; + input CLKINSEL; + input [6:0] DADDR; + input DCLK; + input DEN; + input [15:0] DI; + input DWE; + input PSCLK; + input PSEN; + input PSINCDEC; + input PWRDWN; + input RST; +endmodule + +module MMCME2_BASE (...); + parameter BANDWIDTH = "OPTIMIZED"; + parameter real CLKFBOUT_MULT_F = 5.000; + parameter real CLKFBOUT_PHASE = 0.000; + parameter real CLKIN1_PERIOD = 0.000; + parameter real CLKOUT0_DIVIDE_F = 1.000; + parameter real CLKOUT0_DUTY_CYCLE = 0.500; + parameter real CLKOUT0_PHASE = 0.000; + parameter integer CLKOUT1_DIVIDE = 1; + parameter real CLKOUT1_DUTY_CYCLE = 0.500; + parameter real CLKOUT1_PHASE = 0.000; + parameter integer CLKOUT2_DIVIDE = 1; + parameter real CLKOUT2_DUTY_CYCLE = 0.500; + parameter real CLKOUT2_PHASE = 0.000; + parameter integer CLKOUT3_DIVIDE = 1; + parameter real CLKOUT3_DUTY_CYCLE = 0.500; + parameter real CLKOUT3_PHASE = 0.000; + parameter CLKOUT4_CASCADE = "FALSE"; + parameter integer CLKOUT4_DIVIDE = 1; + parameter real CLKOUT4_DUTY_CYCLE = 0.500; + parameter real CLKOUT4_PHASE = 0.000; + parameter integer CLKOUT5_DIVIDE = 1; + parameter real CLKOUT5_DUTY_CYCLE = 0.500; + parameter real CLKOUT5_PHASE = 0.000; + parameter integer CLKOUT6_DIVIDE = 1; + parameter real CLKOUT6_DUTY_CYCLE = 0.500; + parameter real CLKOUT6_PHASE = 0.000; + parameter integer DIVCLK_DIVIDE = 1; + parameter real REF_JITTER1 = 0.010; + parameter STARTUP_WAIT = "FALSE"; + output CLKFBOUT; + output CLKFBOUTB; + output CLKOUT0; + output CLKOUT0B; + output CLKOUT1; + output CLKOUT1B; + output CLKOUT2; + output CLKOUT2B; + output CLKOUT3; + output CLKOUT3B; + output CLKOUT4; + output CLKOUT5; + output CLKOUT6; + output LOCKED; + input CLKFBIN; + input CLKIN1; + input PWRDWN; + input RST; +endmodule + +module OBUFDS (...); + parameter CAPACITANCE = "DONT_CARE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SLEW = "SLOW"; + output O, OB; + input I; +endmodule + +module OBUFT (...); + parameter CAPACITANCE = "DONT_CARE"; + parameter integer DRIVE = 12; + parameter IOSTANDARD = "DEFAULT"; + parameter SLEW = "SLOW"; + output O; + input I, T; +endmodule + +module OBUFTDS (...); + parameter CAPACITANCE = "DONT_CARE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SLEW = "SLOW"; + output O, OB; + input I, T; +endmodule + +module ODDR (...); + output Q; + input C; + input CE; + input D1; + input D2; + input R; + input S; + parameter DDR_CLK_EDGE = "OPPOSITE_EDGE"; + parameter INIT = 1'b0; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_D1_INVERTED = 1'b0; + parameter [0:0] IS_D2_INVERTED = 1'b0; + parameter SRTYPE = "SYNC"; + parameter MSGON = "TRUE"; + parameter XON = "TRUE"; +endmodule + +module ODELAYE2 (...); + parameter CINVCTRL_SEL = "FALSE"; + parameter DELAY_SRC = "ODATAIN"; + parameter HIGH_PERFORMANCE_MODE = "FALSE"; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_ODATAIN_INVERTED = 1'b0; + parameter ODELAY_TYPE = "FIXED"; + parameter integer ODELAY_VALUE = 0; + parameter PIPE_SEL = "FALSE"; + parameter real REFCLK_FREQUENCY = 200.0; + parameter SIGNAL_PATTERN = "DATA"; + parameter integer SIM_DELAY_D = 0; + output [4:0] CNTVALUEOUT; + output DATAOUT; + input C; + input CE; + input CINVCTRL; + input CLKIN; + input [4:0] CNTVALUEIN; + input INC; + input LD; + input LDPIPEEN; + input ODATAIN; + input REGRST; +endmodule + +module OSERDESE2 (...); + parameter DATA_RATE_OQ = "DDR"; + parameter DATA_RATE_TQ = "DDR"; + parameter integer DATA_WIDTH = 4; + parameter [0:0] INIT_OQ = 1'b0; + parameter [0:0] INIT_TQ = 1'b0; + parameter [0:0] IS_CLKDIV_INVERTED = 1'b0; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + parameter [0:0] IS_D1_INVERTED = 1'b0; + parameter [0:0] IS_D2_INVERTED = 1'b0; + parameter [0:0] IS_D3_INVERTED = 1'b0; + parameter [0:0] IS_D4_INVERTED = 1'b0; + parameter [0:0] IS_D5_INVERTED = 1'b0; + parameter [0:0] IS_D6_INVERTED = 1'b0; + parameter [0:0] IS_D7_INVERTED = 1'b0; + parameter [0:0] IS_D8_INVERTED = 1'b0; + parameter [0:0] IS_T1_INVERTED = 1'b0; + parameter [0:0] IS_T2_INVERTED = 1'b0; + parameter [0:0] IS_T3_INVERTED = 1'b0; + parameter [0:0] IS_T4_INVERTED = 1'b0; + parameter SERDES_MODE = "MASTER"; + parameter [0:0] SRVAL_OQ = 1'b0; + parameter [0:0] SRVAL_TQ = 1'b0; + parameter TBYTE_CTL = "FALSE"; + parameter TBYTE_SRC = "FALSE"; + parameter integer TRISTATE_WIDTH = 4; + output OFB; + output OQ; + output SHIFTOUT1; + output SHIFTOUT2; + output TBYTEOUT; + output TFB; + output TQ; + input CLK; + input CLKDIV; + input D1; + input D2; + input D3; + input D4; + input D5; + input D6; + input D7; + input D8; + input OCE; + input RST; + input SHIFTIN1; + input SHIFTIN2; + input T1; + input T2; + input T3; + input T4; + input TBYTEIN; + input TCE; +endmodule + +module OUT_FIFO (...); + parameter integer ALMOST_EMPTY_VALUE = 1; + parameter integer ALMOST_FULL_VALUE = 1; + parameter ARRAY_MODE = "ARRAY_MODE_8_X_4"; + parameter OUTPUT_DISABLE = "FALSE"; + parameter SYNCHRONOUS_MODE = "FALSE"; + output ALMOSTEMPTY; + output ALMOSTFULL; + output EMPTY; + output FULL; + output [3:0] Q0; + output [3:0] Q1; + output [3:0] Q2; + output [3:0] Q3; + output [3:0] Q4; + output [3:0] Q7; + output [3:0] Q8; + output [3:0] Q9; + output [7:0] Q5; + output [7:0] Q6; + input RDCLK; + input RDEN; + input RESET; + input WRCLK; + input WREN; + input [7:0] D0; + input [7:0] D1; + input [7:0] D2; + input [7:0] D3; + input [7:0] D4; + input [7:0] D5; + input [7:0] D6; + input [7:0] D7; + input [7:0] D8; + input [7:0] D9; +endmodule + +module PHASER_IN (...); + parameter integer CLKOUT_DIV = 4; + parameter DQS_BIAS_MODE = "FALSE"; + parameter EN_ISERDES_RST = "FALSE"; + parameter integer FINE_DELAY = 0; + parameter FREQ_REF_DIV = "NONE"; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter real MEMREFCLK_PERIOD = 0.000; + parameter OUTPUT_CLK_SRC = "PHASE_REF"; + parameter real PHASEREFCLK_PERIOD = 0.000; + parameter real REFCLK_PERIOD = 0.000; + parameter integer SEL_CLK_OFFSET = 5; + parameter SYNC_IN_DIV_RST = "FALSE"; + output FINEOVERFLOW; + output ICLK; + output ICLKDIV; + output ISERDESRST; + output RCLK; + output [5:0] COUNTERREADVAL; + input COUNTERLOADEN; + input COUNTERREADEN; + input DIVIDERST; + input EDGEADV; + input FINEENABLE; + input FINEINC; + input FREQREFCLK; + input MEMREFCLK; + input PHASEREFCLK; + input RST; + input SYNCIN; + input SYSCLK; + input [1:0] RANKSEL; + input [5:0] COUNTERLOADVAL; +endmodule + +module PHASER_IN_PHY (...); + parameter BURST_MODE = "FALSE"; + parameter integer CLKOUT_DIV = 4; + parameter [0:0] DQS_AUTO_RECAL = 1'b1; + parameter DQS_BIAS_MODE = "FALSE"; + parameter [2:0] DQS_FIND_PATTERN = 3'b001; + parameter integer FINE_DELAY = 0; + parameter FREQ_REF_DIV = "NONE"; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter real MEMREFCLK_PERIOD = 0.000; + parameter OUTPUT_CLK_SRC = "PHASE_REF"; + parameter real PHASEREFCLK_PERIOD = 0.000; + parameter real REFCLK_PERIOD = 0.000; + parameter integer SEL_CLK_OFFSET = 5; + parameter SYNC_IN_DIV_RST = "FALSE"; + parameter WR_CYCLES = "FALSE"; + output DQSFOUND; + output DQSOUTOFRANGE; + output FINEOVERFLOW; + output ICLK; + output ICLKDIV; + output ISERDESRST; + output PHASELOCKED; + output RCLK; + output WRENABLE; + output [5:0] COUNTERREADVAL; + input BURSTPENDINGPHY; + input COUNTERLOADEN; + input COUNTERREADEN; + input FINEENABLE; + input FINEINC; + input FREQREFCLK; + input MEMREFCLK; + input PHASEREFCLK; + input RST; + input RSTDQSFIND; + input SYNCIN; + input SYSCLK; + input [1:0] ENCALIBPHY; + input [1:0] RANKSELPHY; + input [5:0] COUNTERLOADVAL; +endmodule + +module PHASER_OUT (...); + parameter integer CLKOUT_DIV = 4; + parameter COARSE_BYPASS = "FALSE"; + parameter integer COARSE_DELAY = 0; + parameter EN_OSERDES_RST = "FALSE"; + parameter integer FINE_DELAY = 0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter real MEMREFCLK_PERIOD = 0.000; + parameter OCLKDELAY_INV = "FALSE"; + parameter integer OCLK_DELAY = 0; + parameter OUTPUT_CLK_SRC = "PHASE_REF"; + parameter real PHASEREFCLK_PERIOD = 0.000; + parameter [2:0] PO = 3'b000; + parameter real REFCLK_PERIOD = 0.000; + parameter SYNC_IN_DIV_RST = "FALSE"; + output COARSEOVERFLOW; + output FINEOVERFLOW; + output OCLK; + output OCLKDELAYED; + output OCLKDIV; + output OSERDESRST; + output [8:0] COUNTERREADVAL; + input COARSEENABLE; + input COARSEINC; + input COUNTERLOADEN; + input COUNTERREADEN; + input DIVIDERST; + input EDGEADV; + input FINEENABLE; + input FINEINC; + input FREQREFCLK; + input MEMREFCLK; + input PHASEREFCLK; + input RST; + input SELFINEOCLKDELAY; + input SYNCIN; + input SYSCLK; + input [8:0] COUNTERLOADVAL; +endmodule + +module PHASER_OUT_PHY (...); + parameter integer CLKOUT_DIV = 4; + parameter COARSE_BYPASS = "FALSE"; + parameter integer COARSE_DELAY = 0; + parameter DATA_CTL_N = "FALSE"; + parameter DATA_RD_CYCLES = "FALSE"; + parameter integer FINE_DELAY = 0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter real MEMREFCLK_PERIOD = 0.000; + parameter OCLKDELAY_INV = "FALSE"; + parameter integer OCLK_DELAY = 0; + parameter OUTPUT_CLK_SRC = "PHASE_REF"; + parameter real PHASEREFCLK_PERIOD = 0.000; + parameter [2:0] PO = 3'b000; + parameter real REFCLK_PERIOD = 0.000; + parameter SYNC_IN_DIV_RST = "FALSE"; + output COARSEOVERFLOW; + output FINEOVERFLOW; + output OCLK; + output OCLKDELAYED; + output OCLKDIV; + output OSERDESRST; + output RDENABLE; + output [1:0] CTSBUS; + output [1:0] DQSBUS; + output [1:0] DTSBUS; + output [8:0] COUNTERREADVAL; + input BURSTPENDINGPHY; + input COARSEENABLE; + input COARSEINC; + input COUNTERLOADEN; + input COUNTERREADEN; + input FINEENABLE; + input FINEINC; + input FREQREFCLK; + input MEMREFCLK; + input PHASEREFCLK; + input RST; + input SELFINEOCLKDELAY; + input SYNCIN; + input SYSCLK; + input [1:0] ENCALIBPHY; + input [8:0] COUNTERLOADVAL; +endmodule + +module PHASER_REF (...); + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter [0:0] IS_PWRDWN_INVERTED = 1'b0; + output LOCKED; + input CLKIN; + input PWRDWN; + input RST; +endmodule + +module PHY_CONTROL (...); + parameter integer AO_TOGGLE = 0; + parameter [3:0] AO_WRLVL_EN = 4'b0000; + parameter BURST_MODE = "FALSE"; + parameter integer CLK_RATIO = 1; + parameter integer CMD_OFFSET = 0; + parameter integer CO_DURATION = 0; + parameter DATA_CTL_A_N = "FALSE"; + parameter DATA_CTL_B_N = "FALSE"; + parameter DATA_CTL_C_N = "FALSE"; + parameter DATA_CTL_D_N = "FALSE"; + parameter DISABLE_SEQ_MATCH = "TRUE"; + parameter integer DI_DURATION = 0; + parameter integer DO_DURATION = 0; + parameter integer EVENTS_DELAY = 63; + parameter integer FOUR_WINDOW_CLOCKS = 63; + parameter MULTI_REGION = "FALSE"; + parameter PHY_COUNT_ENABLE = "FALSE"; + parameter integer RD_CMD_OFFSET_0 = 0; + parameter integer RD_CMD_OFFSET_1 = 00; + parameter integer RD_CMD_OFFSET_2 = 0; + parameter integer RD_CMD_OFFSET_3 = 0; + parameter integer RD_DURATION_0 = 0; + parameter integer RD_DURATION_1 = 0; + parameter integer RD_DURATION_2 = 0; + parameter integer RD_DURATION_3 = 0; + parameter SYNC_MODE = "FALSE"; + parameter integer WR_CMD_OFFSET_0 = 0; + parameter integer WR_CMD_OFFSET_1 = 0; + parameter integer WR_CMD_OFFSET_2 = 0; + parameter integer WR_CMD_OFFSET_3 = 0; + parameter integer WR_DURATION_0 = 0; + parameter integer WR_DURATION_1 = 0; + parameter integer WR_DURATION_2 = 0; + parameter integer WR_DURATION_3 = 0; + output PHYCTLALMOSTFULL; + output PHYCTLEMPTY; + output PHYCTLFULL; + output PHYCTLREADY; + output [1:0] INRANKA; + output [1:0] INRANKB; + output [1:0] INRANKC; + output [1:0] INRANKD; + output [1:0] PCENABLECALIB; + output [3:0] AUXOUTPUT; + output [3:0] INBURSTPENDING; + output [3:0] OUTBURSTPENDING; + input MEMREFCLK; + input PHYCLK; + input PHYCTLMSTREMPTY; + input PHYCTLWRENABLE; + input PLLLOCK; + input READCALIBENABLE; + input REFDLLLOCK; + input RESET; + input SYNCIN; + input WRITECALIBENABLE; + input [31:0] PHYCTLWD; +endmodule + +module PLLE2_ADV (...); + parameter BANDWIDTH = "OPTIMIZED"; + parameter COMPENSATION = "ZHOLD"; + parameter STARTUP_WAIT = "FALSE"; + parameter integer CLKOUT0_DIVIDE = 1; + parameter integer CLKOUT1_DIVIDE = 1; + parameter integer CLKOUT2_DIVIDE = 1; + parameter integer CLKOUT3_DIVIDE = 1; + parameter integer CLKOUT4_DIVIDE = 1; + parameter integer CLKOUT5_DIVIDE = 1; + parameter integer DIVCLK_DIVIDE = 1; + parameter integer CLKFBOUT_MULT = 5; + parameter real CLKFBOUT_PHASE = 0.000; + parameter real CLKIN1_PERIOD = 0.000; + parameter real CLKIN2_PERIOD = 0.000; + parameter real CLKOUT0_DUTY_CYCLE = 0.500; + parameter real CLKOUT0_PHASE = 0.000; + parameter real CLKOUT1_DUTY_CYCLE = 0.500; + parameter real CLKOUT1_PHASE = 0.000; + parameter real CLKOUT2_DUTY_CYCLE = 0.500; + parameter real CLKOUT2_PHASE = 0.000; + parameter real CLKOUT3_DUTY_CYCLE = 0.500; + parameter real CLKOUT3_PHASE = 0.000; + parameter real CLKOUT4_DUTY_CYCLE = 0.500; + parameter real CLKOUT4_PHASE = 0.000; + parameter real CLKOUT5_DUTY_CYCLE = 0.500; + parameter real CLKOUT5_PHASE = 0.000; + parameter [0:0] IS_CLKINSEL_INVERTED = 1'b0; + parameter [0:0] IS_PWRDWN_INVERTED = 1'b0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter real REF_JITTER1 = 0.010; + parameter real REF_JITTER2 = 0.010; + parameter real VCOCLK_FREQ_MAX = 2133.000; + parameter real VCOCLK_FREQ_MIN = 800.000; + parameter real CLKIN_FREQ_MAX = 1066.000; + parameter real CLKIN_FREQ_MIN = 19.000; + parameter real CLKPFD_FREQ_MAX = 550.0; + parameter real CLKPFD_FREQ_MIN = 19.0; + output CLKFBOUT; + output CLKOUT0; + output CLKOUT1; + output CLKOUT2; + output CLKOUT3; + output CLKOUT4; + output CLKOUT5; + output DRDY; + output LOCKED; + output [15:0] DO; + input CLKFBIN; + input CLKIN1; + input CLKIN2; + input CLKINSEL; + input DCLK; + input DEN; + input DWE; + input PWRDWN; + input RST; + input [15:0] DI; + input [6:0] DADDR; +endmodule + +module PLLE2_BASE (...); + parameter BANDWIDTH = "OPTIMIZED"; + parameter integer CLKFBOUT_MULT = 5; + parameter real CLKFBOUT_PHASE = 0.000; + parameter real CLKIN1_PERIOD = 0.000; + parameter integer CLKOUT0_DIVIDE = 1; + parameter real CLKOUT0_DUTY_CYCLE = 0.500; + parameter real CLKOUT0_PHASE = 0.000; + parameter integer CLKOUT1_DIVIDE = 1; + parameter real CLKOUT1_DUTY_CYCLE = 0.500; + parameter real CLKOUT1_PHASE = 0.000; + parameter integer CLKOUT2_DIVIDE = 1; + parameter real CLKOUT2_DUTY_CYCLE = 0.500; + parameter real CLKOUT2_PHASE = 0.000; + parameter integer CLKOUT3_DIVIDE = 1; + parameter real CLKOUT3_DUTY_CYCLE = 0.500; + parameter real CLKOUT3_PHASE = 0.000; + parameter integer CLKOUT4_DIVIDE = 1; + parameter real CLKOUT4_DUTY_CYCLE = 0.500; + parameter real CLKOUT4_PHASE = 0.000; + parameter integer CLKOUT5_DIVIDE = 1; + parameter real CLKOUT5_DUTY_CYCLE = 0.500; + parameter real CLKOUT5_PHASE = 0.000; + parameter integer DIVCLK_DIVIDE = 1; + parameter real REF_JITTER1 = 0.010; + parameter STARTUP_WAIT = "FALSE"; + output CLKFBOUT; + output CLKOUT0; + output CLKOUT1; + output CLKOUT2; + output CLKOUT3; + output CLKOUT4; + output CLKOUT5; + output LOCKED; + input CLKFBIN; + input CLKIN1; + input PWRDWN; + input RST; +endmodule + +module PULLDOWN (...); + output O; +endmodule + +module PULLUP (...); + output O; +endmodule + +module RAM128X1S (...); + parameter [127:0] INIT = 128'h00000000000000000000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input A0, A1, A2, A3, A4, A5, A6, D, WCLK, WE; +endmodule + +module RAM256X1S (...); + parameter [255:0] INIT = 256'h0; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input [7:0] A; + input D; + input WCLK; + input WE; +endmodule + +module RAM32M (...); + parameter [63:0] INIT_A = 64'h0000000000000000; + parameter [63:0] INIT_B = 64'h0000000000000000; + parameter [63:0] INIT_C = 64'h0000000000000000; + parameter [63:0] INIT_D = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output [1:0] DOA; + output [1:0] DOB; + output [1:0] DOC; + output [1:0] DOD; + input [4:0] ADDRA; + input [4:0] ADDRB; + input [4:0] ADDRC; + input [4:0] ADDRD; + input [1:0] DIA; + input [1:0] DIB; + input [1:0] DIC; + input [1:0] DID; + input WCLK; + input WE; +endmodule + +module RAM32X1D (...); + parameter [31:0] INIT = 32'h00000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output DPO, SPO; + input A0, A1, A2, A3, A4, D, DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, WCLK, WE; +endmodule + +module RAM32X1S (...); + parameter [31:0] INIT = 32'h00000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input A0, A1, A2, A3, A4, D, WCLK, WE; +endmodule + +module RAM32X1S_1 (...); + parameter [31:0] INIT = 32'h00000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input A0, A1, A2, A3, A4, D, WCLK, WE; +endmodule + +module RAM32X2S (...); + parameter [31:0] INIT_00 = 32'h00000000; + parameter [31:0] INIT_01 = 32'h00000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O0, O1; + input A0, A1, A2, A3, A4, D0, D1, WCLK, WE; +endmodule + +module RAM64M (...); + parameter [63:0] INIT_A = 64'h0000000000000000; + parameter [63:0] INIT_B = 64'h0000000000000000; + parameter [63:0] INIT_C = 64'h0000000000000000; + parameter [63:0] INIT_D = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output DOA; + output DOB; + output DOC; + output DOD; + input [5:0] ADDRA; + input [5:0] ADDRB; + input [5:0] ADDRC; + input [5:0] ADDRD; + input DIA; + input DIB; + input DIC; + input DID; + input WCLK; + input WE; +endmodule + +module RAM64X1S (...); + parameter [63:0] INIT = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input A0, A1, A2, A3, A4, A5, D, WCLK, WE; +endmodule + +module RAM64X1S_1 (...); + parameter [63:0] INIT = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input A0, A1, A2, A3, A4, A5, D, WCLK, WE; +endmodule + +module RAM64X2S (...); + parameter [63:0] INIT_00 = 64'h0000000000000000; + parameter [63:0] INIT_01 = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O0, O1; + input A0, A1, A2, A3, A4, A5, D0, D1, WCLK, WE; +endmodule + +module ROM128X1 (...); + parameter [127:0] INIT = 128'h00000000000000000000000000000000; + output O; + input A0, A1, A2, A3, A4, A5, A6; +endmodule + +module ROM256X1 (...); + parameter [255:0] INIT = 256'h0000000000000000000000000000000000000000000000000000000000000000; + output O; + input A0, A1, A2, A3, A4, A5, A6, A7; +endmodule + +module ROM32X1 (...); + parameter [31:0] INIT = 32'h00000000; + output O; + input A0, A1, A2, A3, A4; +endmodule + +module ROM64X1 (...); + parameter [63:0] INIT = 64'h0000000000000000; + output O; + input A0, A1, A2, A3, A4, A5; +endmodule + +module SRL16E (...); + parameter [15:0] INIT = 16'h0000; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + output Q; + input A0, A1, A2, A3, CE, CLK, D; +endmodule + +module SRLC32E (...); + parameter [31:0] INIT = 32'h00000000; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + output Q; + output Q31; + input [4:0] A; + input CE, CLK, D; +endmodule + +module STARTUPE2 (...); + parameter PROG_USR = "FALSE"; + parameter real SIM_CCLK_FREQ = 0.0; + output CFGCLK; + output CFGMCLK; + output EOS; + output PREQ; + input CLK; + input GSR; + input GTS; + input KEYCLEARB; + input PACK; + input USRCCLKO; + input USRCCLKTS; + input USRDONEO; + input USRDONETS; +endmodule + +module USR_ACCESSE2 (...); + output CFGCLK; + output DATAVALID; + output [31:0] DATA; +endmodule + +module XADC (...); + output BUSY; + output DRDY; + output EOC; + output EOS; + output JTAGBUSY; + output JTAGLOCKED; + output JTAGMODIFIED; + output OT; + output [15:0] DO; + output [7:0] ALM; + output [4:0] CHANNEL; + output [4:0] MUXADDR; + input CONVST; + input CONVSTCLK; + input DCLK; + input DEN; + input DWE; + input RESET; + input VN; + input VP; + input [15:0] DI; + input [15:0] VAUXN; + input [15:0] VAUXP; + input [6:0] DADDR; + parameter [15:0] INIT_40 = 16'h0; + parameter [15:0] INIT_41 = 16'h0; + parameter [15:0] INIT_42 = 16'h0800; + parameter [15:0] INIT_43 = 16'h0; + parameter [15:0] INIT_44 = 16'h0; + parameter [15:0] INIT_45 = 16'h0; + parameter [15:0] INIT_46 = 16'h0; + parameter [15:0] INIT_47 = 16'h0; + parameter [15:0] INIT_48 = 16'h0; + parameter [15:0] INIT_49 = 16'h0; + parameter [15:0] INIT_4A = 16'h0; + parameter [15:0] INIT_4B = 16'h0; + parameter [15:0] INIT_4C = 16'h0; + parameter [15:0] INIT_4D = 16'h0; + parameter [15:0] INIT_4E = 16'h0; + parameter [15:0] INIT_4F = 16'h0; + parameter [15:0] INIT_50 = 16'h0; + parameter [15:0] INIT_51 = 16'h0; + parameter [15:0] INIT_52 = 16'h0; + parameter [15:0] INIT_53 = 16'h0; + parameter [15:0] INIT_54 = 16'h0; + parameter [15:0] INIT_55 = 16'h0; + parameter [15:0] INIT_56 = 16'h0; + parameter [15:0] INIT_57 = 16'h0; + parameter [15:0] INIT_58 = 16'h0; + parameter [15:0] INIT_59 = 16'h0; + parameter [15:0] INIT_5A = 16'h0; + parameter [15:0] INIT_5B = 16'h0; + parameter [15:0] INIT_5C = 16'h0; + parameter [15:0] INIT_5D = 16'h0; + parameter [15:0] INIT_5E = 16'h0; + parameter [15:0] INIT_5F = 16'h0; + parameter IS_CONVSTCLK_INVERTED = 1'b0; + parameter IS_DCLK_INVERTED = 1'b0; + parameter SIM_DEVICE = "7SERIES"; + parameter SIM_MONITOR_FILE = "design.txt"; +endmodule + diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 21d1fb1e..e7ec1e6e 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -69,6 +69,7 @@ struct SynthXilinxPass : public Pass { log("\n"); log(" begin:\n"); log(" read_verilog -lib +/xilinx/cells_sim.v\n"); + log(" read_verilog -lib +/xilinx/cells_xtra.v\n"); log(" read_verilog -lib +/xilinx/brams_bb.v\n"); log(" read_verilog -lib +/xilinx/drams_bb.v\n"); log(" hierarchy -check -top <top>\n"); @@ -159,12 +160,13 @@ struct SynthXilinxPass : public Pass { bool active = run_from.empty(); - log_header("Executing SYNTH_XILINX pass.\n"); + log_header(design, "Executing SYNTH_XILINX pass.\n"); log_push(); if (check_label(active, run_from, run_to, "begin")) { Pass::call(design, "read_verilog -lib +/xilinx/cells_sim.v"); + Pass::call(design, "read_verilog -lib +/xilinx/cells_xtra.v"); Pass::call(design, "read_verilog -lib +/xilinx/brams_bb.v"); Pass::call(design, "read_verilog -lib +/xilinx/drams_bb.v"); Pass::call(design, stringf("hierarchy -check %s", top_opt.c_str())); diff --git a/tests/asicworld/code_hdl_models_arbiter_tb.v b/tests/asicworld/code_hdl_models_arbiter_tb.v index 5e7bf46b..78d1168e 100644 --- a/tests/asicworld/code_hdl_models_arbiter_tb.v +++ b/tests/asicworld/code_hdl_models_arbiter_tb.v @@ -1,11 +1,11 @@ module testbench (); -reg clk; -reg rst; -reg req3; -reg req2; -reg req1; -reg req0; +reg clk = 0; +reg rst = 1; +reg req3 = 0; +reg req2 = 0; +reg req1 = 0; +reg req0 = 0; wire gnt3; wire gnt2; wire gnt1; @@ -13,17 +13,15 @@ wire gnt0; // Clock generator always #1 clk = ~clk; +integer file; + +always @(posedge clk) + $fdisplay(file, "%b", {gnt3, gnt2, gnt1, gnt0}); initial begin - $dumpfile ("arbiter.vcd"); - $dumpvars(); - clk = 0; - rst = 1; - req0 = 0; - req1 = 0; - req2 = 0; - req3 = 0; - #10 rst = 0; + file = $fopen(`outfile); + repeat (5) @ (posedge clk); + rst <= 0; repeat (1) @ (posedge clk); req0 <= 1; repeat (1) @ (posedge clk); diff --git a/tests/asicworld/code_verilog_tutorial_counter_tb.v b/tests/asicworld/code_verilog_tutorial_counter_tb.v index 50481454..33d54050 100644 --- a/tests/asicworld/code_verilog_tutorial_counter_tb.v +++ b/tests/asicworld/code_verilog_tutorial_counter_tb.v @@ -15,9 +15,10 @@ /////////////////////////////////////////////////////////////////////////// module testbench; -reg clk, reset, enable; +integer file; +reg clk = 0, reset = 0, enable = 0; wire [3:0] count; -reg dut_error; +reg dut_error = 0; counter U0 ( .clk (clk), @@ -30,34 +31,21 @@ event reset_enable; event terminate_sim; initial -begin - $display ("###################################################"); - clk = 0; - reset = 0; - enable = 0; - dut_error = 0; -end + file = $fopen(`outfile); always #5 clk = !clk; initial -begin - $dumpfile ("counter.vcd"); - $dumpvars; -end - - -initial @ (terminate_sim) begin - $display ("Terminating simulation"); + $fdisplay (file, "Terminating simulation"); if (dut_error == 0) begin - $display ("Simulation Result : PASSED"); + $fdisplay (file, "Simulation Result : PASSED"); end else begin - $display ("Simulation Result : FAILED"); + $fdisplay (file, "Simulation Result : FAILED"); end - $display ("###################################################"); + $fdisplay (file, "###################################################"); #1 $finish; end @@ -69,11 +57,11 @@ initial forever begin @ (reset_enable); @ (negedge clk) - $display ("Applying reset"); + $fdisplay (file, "Applying reset"); reset = 1; @ (negedge clk) reset = 0; - $display ("Came out of Reset"); + $fdisplay (file, "Came out of Reset"); -> reset_done; end @@ -103,8 +91,8 @@ else if ( enable == 1'b1) always @ (negedge clk) if (count_compare != count) begin - $display ("DUT ERROR AT TIME%d",$time); - $display ("Expected value %d, Got Value %d", count_compare, count); + $fdisplay (file, "DUT ERROR AT TIME%d",$time); + $fdisplay (file, "Expected value %d, Got Value %d", count_compare, count); dut_error = 1; #5 -> terminate_sim; end diff --git a/tests/asicworld/code_verilog_tutorial_first_counter_tb.v b/tests/asicworld/code_verilog_tutorial_first_counter_tb.v index f065732b..806e1773 100644 --- a/tests/asicworld/code_verilog_tutorial_first_counter_tb.v +++ b/tests/asicworld/code_verilog_tutorial_first_counter_tb.v @@ -1,16 +1,13 @@ module testbench(); // Declare inputs as regs and outputs as wires -reg clock, reset, enable; +reg clock = 1, reset = 0, enable = 0; wire [3:0] counter_out; +integer file; // Initialize all variables initial begin - $display ("time\t clk reset enable counter"); - $monitor ("%g\t %b %b %b %b", - $time, clock, reset, enable, counter_out); - clock = 1; // initial value of clock - reset = 0; // initial value of reset - enable = 0; // initial value of enable + file = $fopen(`outfile); + $fdisplay (file, "time\t clk reset enable counter"); #5 reset = 1; // Assert the reset #10 reset = 0; // De-assert the reset #10 enable = 1; // Assert enable @@ -18,6 +15,10 @@ initial begin #5 $finish; // Terminate simulation end +always @(negedge clock) + $fdisplay (file, "%g\t %b %b %b %b", + $time, clock, reset, enable, counter_out); + // Clock generator initial begin #1; diff --git a/tests/asicworld/code_verilog_tutorial_fsm_full_tb.v b/tests/asicworld/code_verilog_tutorial_fsm_full_tb.v index 2e944895..a8e15568 100644 --- a/tests/asicworld/code_verilog_tutorial_fsm_full_tb.v +++ b/tests/asicworld/code_verilog_tutorial_fsm_full_tb.v @@ -1,14 +1,14 @@ module testbench(); -reg clock , reset ; +reg clock = 0 , reset ; reg req_0 , req_1 , req_2 , req_3; wire gnt_0 , gnt_1 , gnt_2 , gnt_3 ; +integer file; initial begin // $dumpfile("testbench.vcd"); // $dumpvars(0, testbench); - $display("Time\t R0 R1 R2 R3 G0 G1 G2 G3"); - $monitor("%g\t %b %b %b %b %b %b %b %b", - $time, req_0, req_1, req_2, req_3, gnt_0, gnt_1, gnt_2, gnt_3); + file = $fopen(`outfile); + $fdisplay(file, "Time\t R0 R1 R2 R3 G0 G1 G2 G3"); clock = 0; reset = 1; req_0 = 0; @@ -28,6 +28,10 @@ initial begin #10 $finish; end +always @(negedge clock) + $fdisplay(file, "%g\t %b %b %b %b %b %b %b %b", + $time, req_0, req_1, req_2, req_3, gnt_0, gnt_1, gnt_2, gnt_3); + initial begin #1; forever diff --git a/tests/simple/constmuldivmod.v b/tests/simple/constmuldivmod.v new file mode 100644 index 00000000..d1d8be86 --- /dev/null +++ b/tests/simple/constmuldivmod.v @@ -0,0 +1,27 @@ +module constmuldivmod(input [7:0] A, input [2:0] mode, output reg [7:0] Y); + always @* begin + case (mode) + 0: Y = A / 8'd0; + 1: Y = A % 8'd0; + 2: Y = A * 8'd0; + + 3: Y = A / 8'd1; + 4: Y = A % 8'd1; + 5: Y = A * 8'd1; + + 6: Y = A / 8'd2; + 7: Y = A % 8'd2; + 8: Y = A * 8'd2; + + 9: Y = A / 8'd4; + 10: Y = A % 8'd4; + 11: Y = A * 8'd4; + + 12: Y = A / 8'd8; + 13: Y = A % 8'd8; + 14: Y = A * 8'd8; + + default: Y = 8'd16 * A; + endcase + end +endmodule diff --git a/tests/simple/mem2reg.v b/tests/simple/mem2reg.v index 40f490b7..9839fd4a 100644 --- a/tests/simple/mem2reg.v +++ b/tests/simple/mem2reg.v @@ -19,9 +19,9 @@ endmodule // ------------------------------------------------------ -module mem2reg_test2(clk, mode, addr, data); +module mem2reg_test2(clk, reset, mode, addr, data); -input clk, mode; +input clk, reset, mode; input [2:0] addr; output [3:0] data; @@ -33,6 +33,10 @@ assign data = mem[addr]; integer i; always @(posedge clk) begin + if (reset) begin + for (i=0; i<8; i=i+1) + mem[i] <= i; + end else if (mode) begin for (i=0; i<8; i=i+1) mem[i] <= mem[i]+1; @@ -55,3 +59,36 @@ always @(posedge clk) assign dout_b = dint_c[3]; endmodule +// ------------------------------------------------------ + +module mem2reg_test4(result1, result2, result3); + output signed [9:0] result1; + output signed [9:0] result2; + output signed [9:0] result3; + + wire signed [9:0] intermediate [0:3]; + + function integer depth2Index; + input integer depth; + depth2Index = depth; + endfunction + + assign intermediate[depth2Index(1)] = 1; + assign intermediate[depth2Index(2)] = 2; + assign intermediate[3] = 3; + assign result1 = intermediate[1]; + assign result2 = intermediate[depth2Index(2)]; + assign result3 = intermediate[depth2Index(3)]; +endmodule + +// ------------------------------------------------------ + +module mem2reg_test5(input ctrl, output out); + wire [0:0] foo[0:0]; + wire [0:0] bar[0:1]; + + assign foo[0] = ctrl; + assign bar[0] = 0, bar[1] = 1; + assign out = bar[foo[0]]; +endmodule + diff --git a/tests/simple/memory.v b/tests/simple/memory.v index d58ed9d1..f38bdafd 100644 --- a/tests/simple/memory.v +++ b/tests/simple/memory.v @@ -243,3 +243,67 @@ module memtest10(input clk, input [5:0] din, output [5:0] dout); assign dout = queue[3]; endmodule + +// ---------------------------------------------------------- + +module memtest11(clk, wen, waddr, raddr, wdata, rdata); + input clk, wen; + input [1:0] waddr, raddr; + input [7:0] wdata; + output [7:0] rdata; + + reg [7:0] mem [3:0]; + + assign rdata = mem[raddr]; + + always @(posedge clk) begin + if (wen) + mem[waddr] <= wdata; + else + mem[waddr] <= mem[waddr]; + end +endmodule + +// ---------------------------------------------------------- + +module memtest12 ( + input clk, + input [1:0] adr, + input [1:0] din, + output reg [1:0] q +); + reg [1:0] ram [3:0]; + always@(posedge clk) + {ram[adr], q} <= {din, ram[adr]}; +endmodule + +// ---------------------------------------------------------- + +module memtest13 ( + input clk, rst, + input [1:0] a1, a2, a3, a4, a5, a6, + input [3:0] off1, off2, + input [31:5] din1, + input [3:0] din2, din3, + output reg [3:0] dout1, dout2, + output reg [31:5] dout3 +); + reg [31:5] mem [0:3]; + + always @(posedge clk) begin + if (rst) begin + mem[0] <= 0; + mem[1] <= 0; + mem[2] <= 0; + mem[3] <= 0; + end else begin + mem[a1] <= din1; + mem[a2][14:11] <= din2; + mem[a3][5 + off1 +: 4] <= din3; + dout1 <= mem[a4][12:9]; + dout2 <= mem[a5][5 + off2 +: 4]; + dout3 <= mem[a6]; + end + end +endmodule + diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh index 76668bed..d0b0a89d 100755 --- a/tests/tools/autotest.sh +++ b/tests/tools/autotest.sh @@ -10,16 +10,19 @@ makejmode=false frontend="verilog" backend_opts="-noattr -noexpr" autotb_opts="" +include_opts="" +xinclude_opts="" +minclude_opts="" scriptfiles="" scriptopt="" toolsdir="$(cd $(dirname $0); pwd)" warn_iverilog_git=false if [ ! -f $toolsdir/cmp_tbdata -o $toolsdir/cmp_tbdata.c -nt $toolsdir/cmp_tbdata ]; then - ( set -ex; gcc -Wall -o $toolsdir/cmp_tbdata $toolsdir/cmp_tbdata.c; ) || exit 1 + ( set -ex; ${CC:-gcc} -Wall -o $toolsdir/cmp_tbdata $toolsdir/cmp_tbdata.c; ) || exit 1 fi -while getopts xmGl:wkjvref:s:p:n: opt; do +while getopts xmGl:wkjvref:s:p:n:S:I: opt; do case "$opt" in x) use_xsim=true ;; @@ -50,34 +53,32 @@ while getopts xmGl:wkjvref:s:p:n: opt; do scriptopt="$OPTARG" ;; n) autotb_opts="$autotb_opts -n $OPTARG" ;; + S) + autotb_opts="$autotb_opts -seed $OPTARG" ;; + I) + include_opts="$include_opts -I $OPTARG" + xinclude_opts="$xinclude_opts -i $OPTARG" + minclude_opts="$minclude_opts +incdir+$OPTARG" ;; *) - echo "Usage: $0 [-x|-m] [-w] [-k] [-j] [-v] [-r] [-e] [-l libs] [-f frontend] [-s script] [-p cmdstring] verilog-files\n" >&2 + echo "Usage: $0 [-x|-m] [-G] [-w] [-k] [-j] [-v] [-r] [-e] [-l libs] [-f frontend] [-s script] [-p cmdstring] [-n iters] [-S seed] [-I incdir] verilog-files\n" >&2 exit 1 esac done -create_ref() { - cp "$1" "$2.v" -} - compile_and_run() { exe="$1"; output="$2"; shift 2 if $use_modelsim; then altver=$( ls -v /opt/altera/ | grep '^[0-9]' | tail -n1; ) /opt/altera/$altver/modelsim_ase/bin/vlib work - /opt/altera/$altver/modelsim_ase/bin/vlog "$@" - /opt/altera/$altver/modelsim_ase/bin/vsim -c -do 'run -all; exit;' testbench | grep '#OUT#' > "$output" + /opt/altera/$altver/modelsim_ase/bin/vlog $minclude_opts +define+outfile=\"$output\" "$@" + /opt/altera/$altver/modelsim_ase/bin/vsim -c -do 'run -all; exit;' testbench elif $use_xsim; then - ( - set +x - files=( "$@" ) - xilver=$( ls -v /opt/Xilinx/Vivado/ | grep '^[0-9]' | tail -n1; ) - /opt/Xilinx/Vivado/$xilver/bin/xvlog "${files[@]}" - /opt/Xilinx/Vivado/$xilver/bin/xelab -R work.testbench | grep '#OUT#' > "$output" - ) + xilver=$( ls -v /opt/Xilinx/Vivado/ | grep '^[0-9]' | tail -n1; ) + /opt/Xilinx/Vivado/$xilver/bin/xvlog $xinclude_opts -d outfile=\"$output\" "$@" + /opt/Xilinx/Vivado/$xilver/bin/xelab -R work.testbench else - iverilog -s testbench -o "$exe" "$@" - vvp -n "$exe" > "$output" + iverilog $include_opts -Doutfile=\"$output\" -s testbench -o "$exe" "$@" + vvp -n "$exe" fi } @@ -108,15 +109,15 @@ do fn=$(basename $fn) bn=$(basename $bn) - cp ../$fn $fn + egrep -v '^\s*`timescale' ../$fn > ${bn}_ref.v + if [ ! -f ../${bn}_tb.v ]; then - "$toolsdir"/../../yosys -b "test_autotb $autotb_opts" -o ${bn}_tb.v $fn + "$toolsdir"/../../yosys -f "$frontend $include_opts" -b "test_autotb $autotb_opts" -o ${bn}_tb.v ${bn}_ref.v else cp ../${bn}_tb.v ${bn}_tb.v fi if $genvcd; then sed -i 's,// \$dump,$dump,g' ${bn}_tb.v; fi - create_ref $fn ${bn}_ref - compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.v $libs + compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.v $libs if $genvcd; then mv testbench.vcd ${bn}_ref.vcd; fi test_count=0 @@ -131,22 +132,22 @@ do test_count=$(( test_count + 1 )) } - if [ "$frontend" = "verific" -o "$frontend" = "verific_gates" ] && grep -q VERIFIC-SKIP $fn; then + if [ "$frontend" = "verific" -o "$frontend" = "verific_gates" ] && grep -q VERIFIC-SKIP ${bn}_ref.v; then touch ../${bn}.skip return fi if [ -n "$scriptfiles" ]; then - test_passes $fn $scriptfiles + test_passes -f "$frontend $include_opts" ${bn}_ref.v $scriptfiles elif [ -n "$scriptopt" ]; then - test_passes -f "$frontend" -p "$scriptopt" $fn + test_passes -f "$frontend $include_opts" -p "$scriptopt" ${bn}_ref.v elif [ "$frontend" = "verific" ]; then - test_passes -p "verific -vlog2k $fn; verific -import -all; opt; memory;;" + test_passes -p "verific -vlog2k ${bn}_ref.v; verific -import -all; opt; memory;;" elif [ "$frontend" = "verific_gates" ]; then - test_passes -p "verific -vlog2k $fn; verific -import -gates -all; opt; memory;;" + test_passes -p "verific -vlog2k ${bn}_ref.v; verific -import -gates -all; opt; memory;;" else - test_passes -f "$frontend" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" $fn - test_passes -f "$frontend" -p "hierarchy; synth -run coarse; techmap; opt; abc -dff" $fn + test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" ${bn}_ref.v + test_passes -f "$frontend $include_opts" -p "hierarchy; synth -run coarse; techmap; opt; abc -dff" ${bn}_ref.v fi touch ../${bn}.log } diff --git a/tests/tools/cmp_tbdata.c b/tests/tools/cmp_tbdata.c index b81ae1ca..c0b12cd9 100644 --- a/tests/tools/cmp_tbdata.c +++ b/tests/tools/cmp_tbdata.c @@ -4,8 +4,8 @@ #include <string.h> int line = 0; -char buffer1[1024]; -char buffer2[1024]; +char buffer1[8192]; +char buffer2[8192]; void check(bool ok) { |