Merge remote-tracking branch 'origin/master' into xaig

This commit is contained in:
Eddie Hung 2019-06-12 08:50:39 -07:00
commit f7a9769c14
140 changed files with 4698 additions and 1852 deletions

13
.clang-format Normal file
View File

@ -0,0 +1,13 @@
# Default Linux style
BasedOnStyle: LLVM
IndentWidth: 8
UseTab: Always
BreakBeforeBraces: Linux
AllowShortIfStatementsOnASingleLine: false
IndentCaseLabels: false
# From CodingReadme
TabWidth: 8
ContinuationIndentWidth: 2
ColumnLimit: 150
# BreakBeforeBraces: Linux

3
.gitignore vendored
View File

@ -4,6 +4,7 @@
*.gch *.gch
*.gcda *.gcda
*.gcno *.gcno
__pycache__
/.cproject /.cproject
/.project /.project
/.settings /.settings
@ -28,6 +29,8 @@
/yosys-smtbmc-script.py /yosys-smtbmc-script.py
/yosys-filterlib /yosys-filterlib
/yosys-filterlib.exe /yosys-filterlib.exe
/kernel/*.pyh
/kernel/python_wrappers.cc
/kernel/version_*.cc /kernel/version_*.cc
/share /share
/yosys-win32-mxebin-* /yosys-win32-mxebin-*

View File

@ -16,6 +16,7 @@ Yosys 0.8 .. Yosys 0.8-dev
- Added "gate2lut.v" techmap rule - Added "gate2lut.v" techmap rule
- Added "rename -src" - Added "rename -src"
- Added "equiv_opt" pass - Added "equiv_opt" pass
- Added "read_aiger" frontend
- "synth_xilinx" to now infer hard shift registers, using new "shregmap -tech xilinx" - "synth_xilinx" to now infer hard shift registers, using new "shregmap -tech xilinx"

View File

@ -2,6 +2,7 @@
CONFIG := clang CONFIG := clang
# CONFIG := gcc # CONFIG := gcc
# CONFIG := gcc-4.8 # CONFIG := gcc-4.8
# CONFIG := afl-gcc
# CONFIG := emcc # CONFIG := emcc
# CONFIG := mxe # CONFIG := mxe
# CONFIG := msys2 # CONFIG := msys2
@ -21,11 +22,6 @@ ENABLE_PROTOBUF := 0
# python wrappers # python wrappers
ENABLE_PYOSYS := 0 ENABLE_PYOSYS := 0
PYTHON_VERSION_TESTCODE := "import sys;t='{v[0]}.{v[1]}'.format(v=list(sys.version_info[:2]));print(t)"
PYTHON_EXECUTABLE := $(shell if python3 -c ""; then echo "python3"; else echo "python"; fi)
PYTHON_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"")
PYTHON_MAJOR_VERSION := $(shell echo $(PYTHON_VERSION) | cut -f1 -d.)
PYTHON_DESTDIR := `$(PYTHON_EXECUTABLE)-config --prefix`/lib/python$(PYTHON_VERSION)/dist-packages
# other configuration flags # other configuration flags
ENABLE_GCOV := 0 ENABLE_GCOV := 0
@ -50,6 +46,10 @@ OS := $(shell uname -s)
PREFIX ?= /usr/local PREFIX ?= /usr/local
INSTALL_SUDO := INSTALL_SUDO :=
ifneq ($(wildcard Makefile.conf),)
include Makefile.conf
endif
BINDIR := $(PREFIX)/bin BINDIR := $(PREFIX)/bin
LIBDIR := $(PREFIX)/lib LIBDIR := $(PREFIX)/lib
DATDIR := $(PREFIX)/share/yosys DATDIR := $(PREFIX)/share/yosys
@ -89,6 +89,9 @@ PLUGIN_LDFLAGS += -undefined dynamic_lookup
# homebrew search paths # homebrew search paths
ifneq ($(shell which brew),) ifneq ($(shell which brew),)
BREW_PREFIX := $(shell brew --prefix)/opt BREW_PREFIX := $(shell brew --prefix)/opt
$(info $$BREW_PREFIX is [${BREW_PREFIX}])
CXXFLAGS += -I$(BREW_PREFIX)/boost/include/boost
LDFLAGS += -L$(BREW_PREFIX)/boost/lib
CXXFLAGS += -I$(BREW_PREFIX)/readline/include CXXFLAGS += -I$(BREW_PREFIX)/readline/include
LDFLAGS += -L$(BREW_PREFIX)/readline/lib LDFLAGS += -L$(BREW_PREFIX)/readline/lib
PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH) PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH)
@ -138,6 +141,21 @@ $(info $(subst $$--$$,$(newline),$(shell sed 's,^,[Makefile.conf] ,; s,$$,$$--$$
include Makefile.conf include Makefile.conf
endif endif
ifeq ($(ENABLE_PYOSYS),1)
PYTHON_VERSION_TESTCODE := "import sys;t='{v[0]}.{v[1]}'.format(v=list(sys.version_info[:2]));print(t)"
PYTHON_EXECUTABLE := $(shell if python3 -c ""; then echo "python3"; else echo "python"; fi)
PYTHON_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"")
PYTHON_MAJOR_VERSION := $(shell echo $(PYTHON_VERSION) | cut -f1 -d.)
PYTHON_PREFIX := $(shell $(PYTHON_EXECUTABLE)-config --prefix)
PYTHON_DESTDIR := $(PYTHON_PREFIX)/lib/python$(PYTHON_VERSION)/site-packages
# Reload Makefile.conf to override python specific variables if defined
ifneq ($(wildcard Makefile.conf),)
include Makefile.conf
endif
endif
ifeq ($(CONFIG),clang) ifeq ($(CONFIG),clang)
CXX = clang CXX = clang
LD = clang++ LD = clang++
@ -185,6 +203,12 @@ LD = gcc-4.8
CXXFLAGS += -std=c++11 -Os CXXFLAGS += -std=c++11 -Os
ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H" ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
else ifeq ($(CONFIG),afl-gcc)
CXX = AFL_QUIET=1 AFL_HARDEN=1 afl-gcc
LD = AFL_QUIET=1 AFL_HARDEN=1 afl-gcc
CXXFLAGS += -std=c++11 -Os
ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
else ifeq ($(CONFIG),cygwin) else ifeq ($(CONFIG),cygwin)
CXX = gcc CXX = gcc
LD = gcc LD = gcc
@ -272,29 +296,50 @@ endif
ifeq ($(ENABLE_PYOSYS),1) ifeq ($(ENABLE_PYOSYS),1)
#Detect name of boost_python library. Some distros usbe boost_python-py<version>, other boost_python<version>, some only use the major version number, some a concatenation of major and minor version numbers #Detect name of boost_python library. Some distros usbe boost_python-py<version>, other boost_python<version>, some only use the major version number, some a concatenation of major and minor version numbers
ifeq ($(OS), Darwin)
BOOST_PYTHON_LIB ?= $(shell \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_EXECUTABLE)-config --ldflags) -lboost_python-py$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_VERSION))"; else \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_EXECUTABLE)-config --ldflags) -lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_EXECUTABLE)-config --ldflags) -lboost_python$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_VERSION))"; else \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_EXECUTABLE)-config --ldflags) -lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \
echo ""; fi; fi; fi; fi;)
else
BOOST_PYTHON_LIB ?= $(shell \ BOOST_PYTHON_LIB ?= $(shell \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python-py$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_VERSION))"; else \ if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python-py$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_VERSION))"; else \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \ if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_VERSION))"; else \ if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_VERSION))"; else \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \ if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \
echo ""; fi; fi; fi; fi;) echo ""; fi; fi; fi; fi;)
endif
ifeq ($(BOOST_PYTHON_LIB),) ifeq ($(BOOST_PYTHON_LIB),)
$(error BOOST_PYTHON_LIB could not be detected. Please define manualy) $(error BOOST_PYTHON_LIB could not be detected. Please define manualy)
endif endif
ifeq ($(OS), Darwin)
ifeq ($(PYTHON_MAJOR_VERSION),3) ifeq ($(PYTHON_MAJOR_VERSION),3)
LDLIBS += `$(PYTHON_EXECUTABLE)-config --libs` $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --ldflags) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
CXXFLAGS += `$(PYTHON_EXECUTABLE)-config --includes` -D WITH_PYTHON CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON
else else
LDLIBS += `$(PYTHON_EXECUTABLE)-config --libs` $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --ldflags) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
CXXFLAGS += `$(PYTHON_EXECUTABLE)-config --includes` -D WITH_PYTHON CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON
endif
else
ifeq ($(PYTHON_MAJOR_VERSION),3)
LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --libs) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON
else
LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --libs) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON
endif
endif endif
ifeq ($(ENABLE_PYOSYS),1)
PY_WRAPPER_FILE = kernel/python_wrappers PY_WRAPPER_FILE = kernel/python_wrappers
OBJS += $(PY_WRAPPER_FILE).o OBJS += $(PY_WRAPPER_FILE).o
PY_GEN_SCRIPT= py_wrap_generator PY_GEN_SCRIPT= py_wrap_generator
PY_WRAP_INCLUDES := $(shell python$(PYTHON_VERSION) -c "import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).print_includes()") PY_WRAP_INCLUDES := $(shell python$(PYTHON_VERSION) -c "from misc import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).print_includes()")
endif
endif endif
ifeq ($(ENABLE_READLINE),1) ifeq ($(ENABLE_READLINE),1)
@ -540,7 +585,11 @@ yosys$(EXE): $(OBJS)
$(P) $(LD) -o yosys$(EXE) $(LDFLAGS) $(OBJS) $(LDLIBS) $(P) $(LD) -o yosys$(EXE) $(LDFLAGS) $(OBJS) $(LDLIBS)
libyosys.so: $(filter-out kernel/driver.o,$(OBJS)) libyosys.so: $(filter-out kernel/driver.o,$(OBJS))
ifeq ($(OS), Darwin)
$(P) $(LD) -o libyosys.so -shared -Wl,-install_name,libyosys.so $(LDFLAGS) $^ $(LDLIBS)
else
$(P) $(LD) -o libyosys.so -shared -Wl,-soname,libyosys.so $(LDFLAGS) $^ $(LDLIBS) $(P) $(LD) -o libyosys.so -shared -Wl,-soname,libyosys.so $(LDFLAGS) $^ $(LDLIBS)
endif
%.o: %.cc %.o: %.cc
$(Q) mkdir -p $(dir $@) $(Q) mkdir -p $(dir $@)
@ -550,9 +599,11 @@ libyosys.so: $(filter-out kernel/driver.o,$(OBJS))
$(Q) mkdir -p $(dir $@) $(Q) mkdir -p $(dir $@)
$(P) cat $< | grep -E -v "#[ ]*(include|error)" | $(LD) -x c++ -o $@ -E -P - $(P) cat $< | grep -E -v "#[ ]*(include|error)" | $(LD) -x c++ -o $@ -E -P -
$(PY_WRAPPER_FILE).cc: $(PY_GEN_SCRIPT).py $(PY_WRAP_INCLUDES) ifeq ($(ENABLE_PYOSYS),1)
$(PY_WRAPPER_FILE).cc: misc/$(PY_GEN_SCRIPT).py $(PY_WRAP_INCLUDES)
$(Q) mkdir -p $(dir $@) $(Q) mkdir -p $(dir $@)
$(P) python$(PYTHON_VERSION) -c "import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).gen_wrappers(\"$(PY_WRAPPER_FILE).cc\")" $(P) python$(PYTHON_VERSION) -c "from misc import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).gen_wrappers(\"$(PY_WRAPPER_FILE).cc\")"
endif
%.o: %.cpp %.o: %.cpp
$(Q) mkdir -p $(dir $@) $(Q) mkdir -p $(dir $@)
@ -679,13 +730,13 @@ endif
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR) $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR)
$(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/. $(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/.
ifeq ($(ENABLE_LIBYOSYS),1) ifeq ($(ENABLE_LIBYOSYS),1)
$(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR) $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(LIBDIR)
$(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR)/
$(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(LIBDIR)/libyosys.so $(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(LIBDIR)/libyosys.so
$(INSTALL_SUDO) ldconfig
ifeq ($(ENABLE_PYOSYS),1) ifeq ($(ENABLE_PYOSYS),1)
$(INSTALL_SUDO) mkdir -p $(PYTHON_DESTDIR)/pyosys $(INSTALL_SUDO) mkdir -p $(PYTHON_DESTDIR)/pyosys
$(INSTALL_SUDO) cp libyosys.so $(PYTHON_DESTDIR)/pyosys $(INSTALL_SUDO) cp libyosys.so $(PYTHON_DESTDIR)/pyosys/
$(INSTALL_SUDO) cp __init__.py $(PYTHON_DESTDIR)/pyosys $(INSTALL_SUDO) cp misc/__init__.py $(PYTHON_DESTDIR)/pyosys/
endif endif
endif endif
@ -787,6 +838,9 @@ config-gcc-static: clean
config-gcc-4.8: clean config-gcc-4.8: clean
echo 'CONFIG := gcc-4.8' > Makefile.conf echo 'CONFIG := gcc-4.8' > Makefile.conf
config-afl-gcc: clean
echo 'CONFIG := afl-gcc' > Makefile.conf
config-emcc: clean config-emcc: clean
echo 'CONFIG := emcc' > Makefile.conf echo 'CONFIG := emcc' > Makefile.conf
echo 'ENABLE_TCL := 0' >> Makefile.conf echo 'ENABLE_TCL := 0' >> Makefile.conf
@ -833,5 +887,5 @@ echo-git-rev:
-include techlibs/*/*.d -include techlibs/*/*.d
.PHONY: all top-all abc test install install-abc manual clean mrproper qtcreator coverage vcxsrc mxebin .PHONY: all top-all abc test install install-abc manual clean mrproper qtcreator coverage vcxsrc mxebin
.PHONY: config-clean config-clang config-gcc config-gcc-static config-gcc-4.8 config-gprof config-sudo .PHONY: config-clean config-clang config-gcc config-gcc-static config-gcc-4.8 config-afl-gcc config-gprof config-sudo

View File

@ -257,13 +257,9 @@ for them:
- Non-synthesizable language features as defined in - Non-synthesizable language features as defined in
IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002 IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002
- The ``tri``, ``triand``, ``trior``, ``wand`` and ``wor`` net types - The ``tri``, ``triand`` and ``trior`` net types
- The ``config`` keyword and library map files - The ``config`` and ``disable`` keywords and library map files
- The ``disable``, ``primitive`` and ``specify`` statements
- Latched logic (is synthesized as logic with feedback loops)
Verilog Attributes and non-standard features Verilog Attributes and non-standard features
@ -370,7 +366,7 @@ Verilog Attributes and non-standard features
- When defining a macro with `define, all text between triple double quotes - When defining a macro with `define, all text between triple double quotes
is interpreted as macro body, even if it contains unescaped newlines. The is interpreted as macro body, even if it contains unescaped newlines. The
tipple double quotes are removed from the macro body. For example: triple double quotes are removed from the macro body. For example:
`define MY_MACRO(a, b) """ `define MY_MACRO(a, b) """
assign a = 23; assign a = 23;
@ -417,12 +413,18 @@ Verilog Attributes and non-standard features
$ yosys -p 'plugin -a foo -i /lib/libm.so; read_verilog dpitest.v' $ yosys -p 'plugin -a foo -i /lib/libm.so; read_verilog dpitest.v'
- Sized constants (the syntax ``<size>'s?[bodh]<value>``) support constant - Sized constants (the syntax ``<size>'s?[bodh]<value>``) support constant
expressions as <size>. If the expression is not a simple identifier, it expressions as ``<size>``. If the expression is not a simple identifier, it
must be put in parentheses. Examples: ``WIDTH'd42``, ``(4+2)'b101010`` must be put in parentheses. Examples: ``WIDTH'd42``, ``(4+2)'b101010``
- The system tasks ``$finish`` and ``$display`` are supported in initial blocks - The system tasks ``$finish``, ``$stop`` and ``$display`` are supported in
in an unconditional context (only if/case statements on parameters initial blocks in an unconditional context (only if/case statements on
and constant values). The intended use for this is synthesis-time DRC. expressions over parameters and constant values are allowed). The intended
use for this is synthesis-time DRC.
- There is limited support for converting specify .. endspecify statements to
special ``$specify2``, ``$specify3``, and ``$specrule`` cells, for use in
blackboxes and whiteboxes. Use ``read_verilog -specify`` to enable this
functionality. (By default specify .. endspecify blocks are ignored.)
Non-standard or SystemVerilog features for formal verification Non-standard or SystemVerilog features for formal verification
@ -457,7 +459,7 @@ Non-standard or SystemVerilog features for formal verification
supported in any clocked block. supported in any clocked block.
- The syntax ``@($global_clock)`` can be used to create FFs that have no - The syntax ``@($global_clock)`` can be used to create FFs that have no
explicit clock input ($ff cells). The same can be achieved by using explicit clock input (``$ff`` cells). The same can be achieved by using
``@(posedge <netname>)`` or ``@(negedge <netname>)`` when ``<netname>`` ``@(posedge <netname>)`` or ``@(negedge <netname>)`` when ``<netname>``
is marked with the ``(* gclk *)`` Verilog attribute. is marked with the ``(* gclk *)`` Verilog attribute.
@ -470,7 +472,7 @@ from SystemVerilog:
- The ``assert`` statement from SystemVerilog is supported in its most basic - The ``assert`` statement from SystemVerilog is supported in its most basic
form. In module context: ``assert property (<expression>);`` and within an form. In module context: ``assert property (<expression>);`` and within an
always block: ``assert(<expression>);``. It is transformed to a $assert cell. always block: ``assert(<expression>);``. It is transformed to an ``$assert`` cell.
- The ``assume``, ``restrict``, and ``cover`` statements from SystemVerilog are - The ``assume``, ``restrict``, and ``cover`` statements from SystemVerilog are
also supported. The same limitations as with the ``assert`` statement apply. also supported. The same limitations as with the ``assert`` statement apply.

View File

@ -409,12 +409,26 @@ struct BlifDumper
f << stringf(".%s %s", subckt_or_gate(cell->type.str()), cstr(cell->type)); f << stringf(".%s %s", subckt_or_gate(cell->type.str()), cstr(cell->type));
for (auto &conn : cell->connections()) for (auto &conn : cell->connections())
for (int i = 0; i < conn.second.size(); i++) { {
if (conn.second.size() == 1) if (conn.second.size() == 1) {
f << stringf(" %s", cstr(conn.first)); f << stringf(" %s=%s", cstr(conn.first), cstr(conn.second[0]));
else continue;
f << stringf(" %s[%d]", cstr(conn.first), i); }
f << stringf("=%s", cstr(conn.second.extract(i, 1)));
Module *m = design->module(cell->type);
Wire *w = m ? m->wire(conn.first) : nullptr;
if (w == nullptr) {
for (int i = 0; i < GetSize(conn.second); i++)
f << stringf(" %s[%d]=%s", cstr(conn.first), i, cstr(conn.second[i]));
} else {
for (int i = 0; i < std::min(GetSize(conn.second), GetSize(w)); i++) {
SigBit sig(w, i);
f << stringf(" %s[%d]=%s", cstr(conn.first), sig.wire->upto ?
sig.wire->start_offset+sig.wire->width-sig.offset-1 :
sig.wire->start_offset+sig.offset, cstr(conn.second[i]));
}
}
} }
f << stringf("\n"); f << stringf("\n");

View File

@ -129,7 +129,13 @@ struct BtorWorker
void export_cell(Cell *cell) void export_cell(Cell *cell)
{ {
log_assert(cell_recursion_guard.count(cell) == 0); if (cell_recursion_guard.count(cell)) {
string cell_list;
for (auto c : cell_recursion_guard)
cell_list += stringf("\n %s", log_id(c));
log_error("Found topological loop while processing cell %s. Active cells:%s\n", log_id(cell), cell_list.c_str());
}
cell_recursion_guard.insert(cell); cell_recursion_guard.insert(cell);
btorf_push(log_id(cell)); btorf_push(log_id(cell));

View File

@ -164,6 +164,7 @@ struct FirrtlWorker
}; };
/* Memories defined within this module. */ /* Memories defined within this module. */
struct memory { struct memory {
Cell *pCell; // for error reporting
string name; // memory name string name; // memory name
int abits; // number of address bits int abits; // number of address bits
int size; // size (in units) of the memory int size; // size (in units) of the memory
@ -174,8 +175,37 @@ struct FirrtlWorker
vector<write_port> write_ports; vector<write_port> write_ports;
std::string init_file; std::string init_file;
std::string init_file_srcFileSpec; std::string init_file_srcFileSpec;
memory(string name, int abits, int size, int width) : name(name), abits(abits), size(size), width(width), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec("") {} string srcLine;
memory() : read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){} memory(Cell *pCell, string name, int abits, int size, int width) : pCell(pCell), name(name), abits(abits), size(size), width(width), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec("") {
// Provide defaults for abits or size if one (but not the other) is specified.
if (this->abits == 0 && this->size != 0) {
this->abits = ceil_log2(this->size);
} else if (this->abits != 0 && this->size == 0) {
this->size = 1 << this->abits;
}
// Sanity-check this construction.
if (this->name == "") {
log_error("Nameless memory%s\n", this->atLine());
}
if (this->abits == 0 && this->size == 0) {
log_error("Memory %s has zero address bits and size%s\n", this->name.c_str(), this->atLine());
}
if (this->width == 0) {
log_error("Memory %s has zero width%s\n", this->name.c_str(), this->atLine());
}
}
// We need a default constructor for the dict insert.
memory() : pCell(0), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){}
const char *atLine() {
if (srcLine == "") {
if (pCell) {
auto p = pCell->attributes.find("\\src");
srcLine = " at " + p->second.decode_string();
}
}
return srcLine.c_str();
}
void add_memory_read_port(read_port &rp) { void add_memory_read_port(read_port &rp) {
read_ports.push_back(rp); read_ports.push_back(rp);
} }
@ -314,6 +344,7 @@ struct FirrtlWorker
switch (dir) { switch (dir) {
case FD_INOUT: case FD_INOUT:
log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second)); log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second));
/* FALLTHRU */
case FD_OUT: case FD_OUT:
sourceExpr = firstName; sourceExpr = firstName;
sinkExpr = secondExpr; sinkExpr = secondExpr;
@ -321,7 +352,7 @@ struct FirrtlWorker
break; break;
case FD_NODIRECTION: case FD_NODIRECTION:
log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second)); log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second));
/* FALL_THROUGH */ /* FALLTHRU */
case FD_IN: case FD_IN:
sourceExpr = secondExpr; sourceExpr = secondExpr;
sinkExpr = firstName; sinkExpr = firstName;
@ -418,8 +449,10 @@ struct FirrtlWorker
string primop; string primop;
bool always_uint = false; bool always_uint = false;
if (cell->type == "$not") primop = "not"; if (cell->type == "$not") primop = "not";
else if (cell->type == "$neg") primop = "neg"; else if (cell->type == "$neg") {
else if (cell->type == "$logic_not") { primop = "neg";
is_signed = true; // Result of "neg" is signed (an SInt).
} else if (cell->type == "$logic_not") {
primop = "eq"; primop = "eq";
a_expr = stringf("%s, UInt(0)", a_expr.c_str()); a_expr = stringf("%s, UInt(0)", a_expr.c_str());
} }
@ -531,6 +564,7 @@ struct FirrtlWorker
auto b_sig = cell->getPort("\\B"); auto b_sig = cell->getPort("\\B");
if (b_sig.is_fully_const()) { if (b_sig.is_fully_const()) {
primop = "shl"; primop = "shl";
b_expr = std::to_string(b_sig.as_int());
} else { } else {
primop = "dshl"; primop = "dshl";
// Convert from FIRRTL left shift semantics. // Convert from FIRRTL left shift semantics.
@ -544,6 +578,7 @@ struct FirrtlWorker
auto b_sig = cell->getPort("\\B"); auto b_sig = cell->getPort("\\B");
if (b_sig.is_fully_const()) { if (b_sig.is_fully_const()) {
primop = "shr"; primop = "shr";
b_expr = std::to_string(b_sig.as_int());
} else { } else {
primop = "dshr"; primop = "dshr";
} }
@ -604,7 +639,7 @@ struct FirrtlWorker
int abits = cell->parameters.at("\\ABITS").as_int(); int abits = cell->parameters.at("\\ABITS").as_int();
int width = cell->parameters.at("\\WIDTH").as_int(); int width = cell->parameters.at("\\WIDTH").as_int();
int size = cell->parameters.at("\\SIZE").as_int(); int size = cell->parameters.at("\\SIZE").as_int();
memory m(mem_id, abits, size, width); memory m(cell, mem_id, abits, size, width);
int rd_ports = cell->parameters.at("\\RD_PORTS").as_int(); int rd_ports = cell->parameters.at("\\RD_PORTS").as_int();
int wr_ports = cell->parameters.at("\\WR_PORTS").as_int(); int wr_ports = cell->parameters.at("\\WR_PORTS").as_int();
@ -681,6 +716,8 @@ struct FirrtlWorker
{ {
std::string cell_type = fid(cell->type); std::string cell_type = fid(cell->type);
std::string mem_id = make_id(cell->parameters["\\MEMID"].decode_string()); std::string mem_id = make_id(cell->parameters["\\MEMID"].decode_string());
int abits = cell->parameters.at("\\ABITS").as_int();
int width = cell->parameters.at("\\WIDTH").as_int();
memory *mp = nullptr; memory *mp = nullptr;
if (cell->type == "$meminit" ) { if (cell->type == "$meminit" ) {
log_error("$meminit (%s.%s.%s) currently unsupported\n", log_id(module), log_id(cell), mem_id.c_str()); log_error("$meminit (%s.%s.%s) currently unsupported\n", log_id(module), log_id(cell), mem_id.c_str());
@ -693,6 +730,11 @@ struct FirrtlWorker
Const clk_enable = cell->parameters.at("\\CLK_ENABLE"); Const clk_enable = cell->parameters.at("\\CLK_ENABLE");
Const clk_polarity = cell->parameters.at("\\CLK_POLARITY"); Const clk_polarity = cell->parameters.at("\\CLK_POLARITY");
// Do we already have an entry for this memory?
if (memories.count(mem_id) == 0) {
memory m(cell, mem_id, abits, 0, width);
register_memory(m);
}
mp = &memories.at(mem_id); mp = &memories.at(mem_id);
int portNum = 0; int portNum = 0;
bool transparency = false; bool transparency = false;
@ -890,7 +932,7 @@ struct FirrtlWorker
// If we have any memory definitions, output them. // If we have any memory definitions, output them.
for (auto kv : memories) { for (auto kv : memories) {
memory m = kv.second; memory &m = kv.second;
f << stringf(" mem %s:\n", m.name.c_str()); f << stringf(" mem %s:\n", m.name.c_str());
f << stringf(" data-type => UInt<%d>\n", m.width); f << stringf(" data-type => UInt<%d>\n", m.width);
f << stringf(" depth => %d\n", m.size); f << stringf(" depth => %d\n", m.size);

View File

@ -160,7 +160,10 @@ void ILANG_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::
} }
f << stringf("%s" "cell %s %s\n", indent.c_str(), cell->type.c_str(), cell->name.c_str()); f << stringf("%s" "cell %s %s\n", indent.c_str(), cell->type.c_str(), cell->name.c_str());
for (auto &it : cell->parameters) { for (auto &it : cell->parameters) {
f << stringf("%s parameter%s %s ", indent.c_str(), (it.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "", it.first.c_str()); f << stringf("%s parameter%s%s %s ", indent.c_str(),
(it.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "",
(it.second.flags & RTLIL::CONST_FLAG_REAL) != 0 ? " real" : "",
it.first.c_str());
dump_const(f, it.second); dump_const(f, it.second);
f << stringf("\n"); f << stringf("\n");
} }

View File

@ -183,8 +183,9 @@ bool is_reg_wire(RTLIL::SigSpec sig, std::string &reg_name)
return true; return true;
} }
void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool set_signed = false, bool escape_comment = false) void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool escape_comment = false)
{ {
bool set_signed = (data.flags & RTLIL::CONST_FLAG_SIGNED) != 0;
if (width < 0) if (width < 0)
width = data.bits.size() - offset; width = data.bits.size() - offset;
if (width == 0) { if (width == 0) {
@ -275,6 +276,7 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
} }
} }
} else { } else {
if ((data.flags & RTLIL::CONST_FLAG_REAL) == 0)
f << stringf("\""); f << stringf("\"");
std::string str = data.decode_string(); std::string str = data.decode_string();
for (size_t i = 0; i < str.size(); i++) { for (size_t i = 0; i < str.size(); i++) {
@ -293,6 +295,7 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
else else
f << str[i]; f << str[i];
} }
if ((data.flags & RTLIL::CONST_FLAG_REAL) == 0)
f << stringf("\""); f << stringf("\"");
} }
} }
@ -373,7 +376,7 @@ void dump_attributes(std::ostream &f, std::string indent, dict<RTLIL::IdString,
else if (modattr && (it->second == Const(1, 1) || it->second == Const(1))) else if (modattr && (it->second == Const(1, 1) || it->second == Const(1)))
f << stringf(" 1 "); f << stringf(" 1 ");
else else
dump_const(f, it->second, -1, 0, false, false, attr2comment); dump_const(f, it->second, -1, 0, false, attr2comment);
f << stringf(" %s%c", attr2comment ? "*/" : "*)", term); f << stringf(" %s%c", attr2comment ? "*/" : "*)", term);
} }
} }
@ -1242,6 +1245,118 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
return true; return true;
} }
if (cell->type.in("$assert", "$assume", "$cover"))
{
f << stringf("%s" "always @* if (", indent.c_str());
dump_sigspec(f, cell->getPort("\\EN"));
f << stringf(") %s(", cell->type.c_str()+1);
dump_sigspec(f, cell->getPort("\\A"));
f << stringf(");\n");
return true;
}
if (cell->type.in("$specify2", "$specify3"))
{
f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str());
SigSpec en = cell->getPort("\\EN");
if (en != State::S1) {
f << stringf("if (");
dump_sigspec(f, cell->getPort("\\EN"));
f << stringf(") ");
}
f << "(";
if (cell->type == "$specify3" && cell->getParam("\\EDGE_EN").as_bool())
f << (cell->getParam("\\EDGE_POL").as_bool() ? "posedge ": "negedge ");
dump_sigspec(f, cell->getPort("\\SRC"));
f << " ";
if (cell->getParam("\\SRC_DST_PEN").as_bool())
f << (cell->getParam("\\SRC_DST_POL").as_bool() ? "+": "-");
f << (cell->getParam("\\FULL").as_bool() ? "*> ": "=> ");
if (cell->type == "$specify3") {
f << "(";
dump_sigspec(f, cell->getPort("\\DST"));
f << " ";
if (cell->getParam("\\DAT_DST_PEN").as_bool())
f << (cell->getParam("\\DAT_DST_POL").as_bool() ? "+": "-");
f << ": ";
dump_sigspec(f, cell->getPort("\\DAT"));
f << ")";
} else {
dump_sigspec(f, cell->getPort("\\DST"));
}
bool bak_decimal = decimal;
decimal = 1;
f << ") = (";
dump_const(f, cell->getParam("\\T_RISE_MIN"));
f << ":";
dump_const(f, cell->getParam("\\T_RISE_TYP"));
f << ":";
dump_const(f, cell->getParam("\\T_RISE_MAX"));
f << ", ";
dump_const(f, cell->getParam("\\T_FALL_MIN"));
f << ":";
dump_const(f, cell->getParam("\\T_FALL_TYP"));
f << ":";
dump_const(f, cell->getParam("\\T_FALL_MAX"));
f << ");\n";
decimal = bak_decimal;
f << stringf("%s" "endspecify\n", indent.c_str());
return true;
}
if (cell->type == "$specrule")
{
f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str());
string spec_type = cell->getParam("\\TYPE").decode_string();
f << stringf("%s(", spec_type.c_str());
if (cell->getParam("\\SRC_PEN").as_bool())
f << (cell->getParam("\\SRC_POL").as_bool() ? "posedge ": "negedge ");
dump_sigspec(f, cell->getPort("\\SRC"));
if (cell->getPort("\\SRC_EN") != State::S1) {
f << " &&& ";
dump_sigspec(f, cell->getPort("\\SRC_EN"));
}
f << ", ";
if (cell->getParam("\\DST_PEN").as_bool())
f << (cell->getParam("\\DST_POL").as_bool() ? "posedge ": "negedge ");
dump_sigspec(f, cell->getPort("\\DST"));
if (cell->getPort("\\DST_EN") != State::S1) {
f << " &&& ";
dump_sigspec(f, cell->getPort("\\DST_EN"));
}
bool bak_decimal = decimal;
decimal = 1;
f << ", ";
dump_const(f, cell->getParam("\\T_LIMIT"));
if (spec_type == "$setuphold" || spec_type == "$recrem" || spec_type == "$fullskew") {
f << ", ";
dump_const(f, cell->getParam("\\T_LIMIT2"));
}
f << ");\n";
decimal = bak_decimal;
f << stringf("%s" "endspecify\n", indent.c_str());
return true;
}
// FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_ // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
// FIXME: $sr, $dlatch, $memrd, $memwr, $fsm // FIXME: $sr, $dlatch, $memrd, $memwr, $fsm
@ -1264,8 +1379,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
if (it != cell->parameters.begin()) if (it != cell->parameters.begin())
f << stringf(","); f << stringf(",");
f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str()); f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0; dump_const(f, it->second);
dump_const(f, it->second, -1, 0, false, is_signed);
f << stringf(")"); f << stringf(")");
} }
f << stringf("\n%s" ")", indent.c_str()); f << stringf("\n%s" ")", indent.c_str());
@ -1312,8 +1426,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
if (defparam && cell->parameters.size() > 0) { if (defparam && cell->parameters.size() > 0) {
for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) { 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()); 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);
dump_const(f, it->second, -1, 0, false, is_signed);
f << stringf(";\n"); f << stringf(";\n");
} }
} }
@ -1505,7 +1618,8 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
SigSpec sig = active_sigmap(wire); SigSpec sig = active_sigmap(wire);
Const val = wire->attributes.at("\\init"); Const val = wire->attributes.at("\\init");
for (int i = 0; i < GetSize(sig) && i < GetSize(val); i++) for (int i = 0; i < GetSize(sig) && i < GetSize(val); i++)
active_initdata[sig[i]] = val.bits.at(i); if (val[i] == State::S0 || val[i] == State::S1)
active_initdata[sig[i]] = val[i];
} }
if (!module->processes.empty()) if (!module->processes.empty())

View File

@ -57,11 +57,15 @@ void AigerReader::parse_aiger()
// Optional values // Optional values
B = C = J = F = 0; B = C = J = F = 0;
for (auto &i : std::array<std::reference_wrapper<unsigned>,4>{B, C, J, F}) { if (f.peek() != ' ') goto end_of_header;
if (f.peek() != ' ') break; if (!(f >> B)) log_error("Invalid AIGER header\n");
if (!(f >> i)) if (f.peek() != ' ') goto end_of_header;
log_error("Invalid AIGER header\n"); if (!(f >> C)) log_error("Invalid AIGER header\n");
} if (f.peek() != ' ') goto end_of_header;
if (!(f >> J)) log_error("Invalid AIGER header\n");
if (f.peek() != ' ') goto end_of_header;
if (!(f >> F)) log_error("Invalid AIGER header\n");
end_of_header:
std::string line; std::string line;
std::getline(f, line); // Ignore up to start of next line, as standard std::getline(f, line); // Ignore up to start of next line, as standard
@ -71,6 +75,8 @@ void AigerReader::parse_aiger()
log_debug("M=%u I=%u L=%u O=%u A=%u B=%u C=%u J=%u F=%u\n", M, I, L, O, A, B, C, J, F); log_debug("M=%u I=%u L=%u O=%u A=%u B=%u C=%u J=%u F=%u\n", M, I, L, O, A, B, C, J, F);
line_count = 1; line_count = 1;
piNum = 0;
flopNum = 0;
if (header == "aag") if (header == "aag")
parse_aiger_ascii(); parse_aiger_ascii();
@ -79,11 +85,15 @@ void AigerReader::parse_aiger()
else else
log_abort(); log_abort();
RTLIL::Wire* n0 = module->wire("\\__0__");
if (n0)
module->connect(n0, RTLIL::S0);
// Parse footer (symbol table, comments, etc.) // Parse footer (symbol table, comments, etc.)
unsigned l1; unsigned l1;
std::string s; std::string s;
for (int c = f.peek(); c != EOF; c = f.peek(), ++line_count) { for (int c = f.peek(); c != EOF; c = f.peek(), ++line_count) {
if (c == 'i' || c == 'l' || c == 'o') { if (c == 'i' || c == 'l' || c == 'o' || c == 'b') {
f.ignore(1); f.ignore(1);
if (!(f >> l1 >> s)) if (!(f >> l1 >> s))
log_error("Line %u cannot be interpreted as a symbol entry!\n", line_count); log_error("Line %u cannot be interpreted as a symbol entry!\n", line_count);
@ -95,11 +105,12 @@ void AigerReader::parse_aiger()
if (c == 'i') wire = inputs[l1]; if (c == 'i') wire = inputs[l1];
else if (c == 'l') wire = latches[l1]; else if (c == 'l') wire = latches[l1];
else if (c == 'o') wire = outputs[l1]; else if (c == 'o') wire = outputs[l1];
else if (c == 'b') wire = bad_properties[l1];
else log_abort(); else log_abort();
module->rename(wire, stringf("\\%s", s.c_str())); module->rename(wire, stringf("\\%s", s.c_str()));
} }
else if (c == 'b' || c == 'j' || c == 'f') { else if (c == 'j' || c == 'f') {
// TODO // TODO
} }
else if (c == 'c') { else if (c == 'c') {
@ -113,103 +124,7 @@ void AigerReader::parse_aiger()
std::getline(f, line); // Ignore up to start of next line std::getline(f, line); // Ignore up to start of next line
} }
dict<RTLIL::IdString, int> wideports_cache; post_process();
if (!map_filename.empty()) {
std::ifstream mf(map_filename);
std::string type, symbol;
int variable, index;
while (mf >> type >> variable >> index >> symbol) {
RTLIL::IdString escaped_symbol = RTLIL::escape_id(symbol);
if (type == "input") {
log_assert(static_cast<unsigned>(variable) < inputs.size());
RTLIL::Wire* wire = inputs[variable];
log_assert(wire);
log_assert(wire->port_input);
if (index == 0)
module->rename(wire, RTLIL::escape_id(symbol));
else if (index > 0) {
module->rename(wire, RTLIL::escape_id(stringf("%s[%d]", symbol.c_str(), index)));
if (wideports)
wideports_cache[escaped_symbol] = std::max(wideports_cache[escaped_symbol], index);
}
}
else if (type == "output") {
log_assert(static_cast<unsigned>(variable) < outputs.size());
RTLIL::Wire* wire = outputs[variable];
log_assert(wire);
// Ignore direct output -> input connections
if (!wire->port_output)
continue;
log_assert(wire->port_output);
if (index == 0)
module->rename(wire, RTLIL::escape_id(symbol));
else if (index > 0) {
module->rename(wire, RTLIL::escape_id(stringf("%s[%d]", symbol.c_str(), index)));
if (wideports)
wideports_cache[escaped_symbol] = std::max(wideports_cache[escaped_symbol], index);
}
}
else
log_error("Symbol type '%s' not recognised.\n", type.c_str());
}
}
for (auto &wp : wideports_cache) {
auto name = wp.first;
int width = wp.second + 1;
RTLIL::Wire *wire = module->wire(name);
if (wire)
module->rename(wire, RTLIL::escape_id(stringf("%s[%d]", name.c_str(), 0)));
// Do not make ports with a mix of input/output into
// wide ports
bool port_input = false, port_output = false;
for (int i = 0; i < width; i++) {
RTLIL::IdString other_name = name.str() + stringf("[%d]", i);
RTLIL::Wire *other_wire = module->wire(other_name);
if (other_wire) {
port_input = port_input || other_wire->port_input;
port_output = port_output || other_wire->port_output;
}
}
if ((port_input && port_output) || (!port_input && !port_output))
continue;
wire = module->addWire(name, width);
wire->port_input = port_input;
wire->port_output = port_output;
for (int i = 0; i < width; i++) {
RTLIL::IdString other_name = name.str() + stringf("[%d]", i);
RTLIL::Wire *other_wire = module->wire(other_name);
if (other_wire) {
other_wire->port_input = false;
other_wire->port_output = false;
if (wire->port_input)
module->connect(other_wire, SigSpec(wire, i));
else
module->connect(SigSpec(wire, i), other_wire);
}
}
}
module->fixup_ports();
design->add(module);
Pass::call(design, "clean");
for (auto cell : module->cells().to_vector()) {
if (cell->type != "$lut") continue;
auto y_port = cell->getPort("\\Y").as_bit();
if (y_port.wire->width == 1)
module->rename(cell, stringf("%s$lut", y_port.wire->name.c_str()));
else
module->rename(cell, stringf("%s[%d]$lut", y_port.wire->name.c_str(), y_port.offset));
}
} }
static uint32_t parse_xaiger_literal(std::istream &f) static uint32_t parse_xaiger_literal(std::istream &f)
@ -254,29 +169,6 @@ static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned litera
return wire; return wire;
} }
static std::pair<RTLIL::IdString, int> wideports_split(std::string name)
{
int pos = -1;
if (name.empty() || name.back() != ']')
goto failed;
for (int i = 0; i+1 < GetSize(name); i++) {
if (name[i] == '[')
pos = i;
else if (name[i] < '0' || name[i] > '9')
pos = -1;
else if (i == pos+1 && name[i] == '0' && name[i+1] != ']')
pos = -1;
}
if (pos >= 0)
return std::pair<RTLIL::IdString, int>(RTLIL::escape_id(name.substr(0, pos)), atoi(name.c_str() + pos+1));
failed:
return std::pair<RTLIL::IdString, int>(name, 0);
}
void AigerReader::parse_xaiger() void AigerReader::parse_xaiger()
{ {
std::string header; std::string header;
@ -299,6 +191,8 @@ void AigerReader::parse_xaiger()
log_debug("M=%u I=%u L=%u O=%u A=%u\n", M, I, L, O, A); log_debug("M=%u I=%u L=%u O=%u A=%u\n", M, I, L, O, A);
line_count = 1; line_count = 1;
piNum = 0;
flopNum = 0;
if (header == "aag") if (header == "aag")
parse_aiger_ascii(); parse_aiger_ascii();
@ -307,13 +201,23 @@ void AigerReader::parse_xaiger()
else else
log_abort(); log_abort();
RTLIL::Wire* n0 = module->wire("\\__0__");
if (n0)
module->connect(n0, RTLIL::S0);
dict<int,IdString> box_lookup;
for (auto m : design->modules()) {
auto it = m->attributes.find("\\abc_box_id");
if (it == m->attributes.end())
continue;
if (m->name[0] == '$') continue;
auto r = box_lookup.insert(std::make_pair(it->second.as_int(), m->name));
log_assert(r.second);
}
// Parse footer (symbol table, comments, etc.) // Parse footer (symbol table, comments, etc.)
unsigned l1;
std::string s; std::string s;
bool comment_seen = false; bool comment_seen = false;
std::vector<std::pair<RTLIL::Wire*,RTLIL::IdString>> deferred_renames;
std::vector<std::pair<RTLIL::Wire*,RTLIL::IdString>> deferred_inouts;
deferred_renames.reserve(inputs.size() + latches.size() + outputs.size());
for (int c = f.peek(); c != EOF; c = f.peek()) { for (int c = f.peek(); c != EOF; c = f.peek()) {
if (comment_seen || c == 'c') { if (comment_seen || c == 'c') {
if (!comment_seen) { if (!comment_seen) {
@ -361,29 +265,40 @@ void AigerReader::parse_xaiger()
} }
} }
else if (c == 'r') { else if (c == 'r') {
/*uint32_t dataSize =*/ parse_xaiger_literal(f); uint32_t dataSize = parse_xaiger_literal(f);
uint32_t flopNum = parse_xaiger_literal(f); flopNum = parse_xaiger_literal(f);
log_assert(dataSize == (flopNum+1) * sizeof(uint32_t));
f.ignore(flopNum * sizeof(uint32_t)); f.ignore(flopNum * sizeof(uint32_t));
log_assert(inputs.size() >= flopNum);
for (auto it = inputs.end() - flopNum; it != inputs.end(); ++it) {
log_assert((*it)->port_input);
(*it)->port_input = false;
}
inputs.erase(inputs.end() - flopNum, inputs.end());
log_assert(outputs.size() >= flopNum);
for (auto it = outputs.end() - flopNum; it != outputs.end(); ++it) {
log_assert((*it)->port_output);
(*it)->port_output = false;
}
outputs.erase(outputs.end() - flopNum, outputs.end());
module->fixup_ports();
} }
else if (c == 'n') { else if (c == 'n') {
parse_xaiger_literal(f); parse_xaiger_literal(f);
f >> s; f >> s;
log_debug("n: '%s'\n", s.c_str()); log_debug("n: '%s'\n", s.c_str());
} }
else if (c == 'a' || c == 'i' || c == 'o' || c == 'h') { else if (c == 'h') {
f.ignore(sizeof(uint32_t));
uint32_t version = parse_xaiger_literal(f);
log_assert(version == 1);
uint32_t ciNum = parse_xaiger_literal(f);
log_debug("ciNum = %u\n", ciNum);
uint32_t coNum = parse_xaiger_literal(f);
log_debug("coNum = %u\n", coNum);
piNum = parse_xaiger_literal(f);
log_debug("piNum = %u\n", piNum);
uint32_t poNum = parse_xaiger_literal(f);
log_debug("poNum = %u\n", poNum);
uint32_t boxNum = parse_xaiger_literal(f);
log_debug("boxNum = %u\n", poNum);
for (unsigned i = 0; i < boxNum; i++) {
f.ignore(2*sizeof(uint32_t));
uint32_t boxUniqueId = parse_xaiger_literal(f);
log_assert(boxUniqueId > 0);
uint32_t oldBoxNum = parse_xaiger_literal(f);
RTLIL::Cell* cell = module->addCell(stringf("$__box%u__", oldBoxNum), box_lookup.at(boxUniqueId));
boxes.emplace_back(cell);
}
}
else if (c == 'a' || c == 'i' || c == 'o') {
uint32_t dataSize = parse_xaiger_literal(f); uint32_t dataSize = parse_xaiger_literal(f);
f.ignore(dataSize); f.ignore(dataSize);
} }
@ -391,221 +306,11 @@ void AigerReader::parse_xaiger()
break; break;
} }
} }
else if (c == 'i' || c == 'l' || c == 'o') {
f.ignore(1);
if (!(f >> l1 >> s))
log_error("Line %u cannot be interpreted as a symbol entry!\n", line_count);
if ((c == 'i' && l1 > inputs.size()) || (c == 'l' && l1 > latches.size()) || (c == 'o' && l1 > outputs.size()))
log_error("Line %u has invalid symbol position!\n", line_count);
RTLIL::Wire* wire;
if (c == 'i') wire = inputs[l1];
else if (c == 'l') wire = latches[l1];
else if (c == 'o') wire = outputs[l1];
else log_abort();
RTLIL::IdString escaped_s = RTLIL::escape_id(s);
if (escaped_s.ends_with("$inout.out")) {
deferred_inouts.emplace_back(wire, escaped_s.substr(0, escaped_s.size()-10));
goto next_line;
}
else if (wideports && (wire->port_input || wire->port_output)) {
RTLIL::IdString wide_symbol;
int index;
std::tie(wide_symbol,index) = wideports_split(escaped_s.str());
if (wide_symbol.ends_with("$inout.out")) {
deferred_inouts.emplace_back(wire, stringf("%s[%d]", wide_symbol.substr(0, wide_symbol.size()-10).c_str(), index));
goto next_line;
}
}
deferred_renames.emplace_back(wire, escaped_s);
next_line:
std::getline(f, line); // Ignore up to start of next line
++line_count;
}
else else
log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c); log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c);
} }
dict<RTLIL::IdString, int> wideports_cache; post_process();
for (const auto &i : deferred_renames) {
RTLIL::Wire *wire = i.first;
module->rename(wire, i.second);
if (wideports && (wire->port_input || wire->port_output)) {
RTLIL::IdString escaped_symbol;
int index;
std::tie(escaped_symbol,index) = wideports_split(wire->name.str());
if (index > 0)
wideports_cache[escaped_symbol] = std::max(wideports_cache[escaped_symbol], index);
}
}
for (const auto &i : deferred_inouts) {
RTLIL::Wire *out_wire = i.first;
log_assert(out_wire->port_output);
out_wire->port_output = false;
RTLIL::Wire *wire = module->wire(i.second);
log_assert(wire);
log_assert(wire->port_input && !wire->port_output);
wire->port_output = true;
module->connect(wire, out_wire);
}
if (!map_filename.empty()) {
std::ifstream mf(map_filename);
std::string type, symbol;
int variable, index;
while (mf >> type >> variable >> index >> symbol) {
RTLIL::IdString escaped_s = RTLIL::escape_id(symbol);
if (type == "input") {
log_assert(static_cast<unsigned>(variable) < inputs.size());
RTLIL::Wire* wire = inputs[variable];
log_assert(wire);
log_assert(wire->port_input);
if (index == 0) {
// Cope with the fact that a CI might be identical
// to a PI (necessary due to ABC); in those cases
// simply connect the latter to the former
RTLIL::Wire* existing = module->wire(escaped_s);
if (!existing)
module->rename(wire, escaped_s);
else {
wire->port_input = false;
module->connect(wire, existing);
}
}
else if (index > 0) {
std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index);
RTLIL::Wire* existing = module->wire(indexed_name);
if (!existing) {
module->rename(wire, indexed_name);
if (wideports)
wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index);
}
else {
module->connect(wire, existing);
wire->port_input = false;
}
}
}
else if (type == "output") {
log_assert(static_cast<unsigned>(variable) < outputs.size());
RTLIL::Wire* wire = outputs[variable];
log_assert(wire);
log_assert(wire->port_output);
if (escaped_s.in("\\__dummy_o__", "\\__const0__", "\\__const1__")) {
wire->port_output = false;
continue;
}
if (index == 0) {
// Cope with the fact that a CO might be identical
// to a PO (necessary due to ABC); in those cases
// simply connect the latter to the former
RTLIL::Wire* existing = module->wire(escaped_s);
if (!existing) {
if (escaped_s.ends_with("$inout.out")) {
wire->port_output = false;
RTLIL::Wire *in_wire = module->wire(escaped_s.substr(0, escaped_s.size()-10));
log_assert(in_wire);
log_assert(in_wire->port_input && !in_wire->port_output);
in_wire->port_output = true;
module->connect(in_wire, wire);
}
else
module->rename(wire, escaped_s);
}
else {
wire->port_output = false;
module->connect(wire, existing);
}
}
else if (index > 0) {
std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index);
RTLIL::Wire* existing = module->wire(indexed_name);
if (!existing) {
if (escaped_s.ends_with("$inout.out")) {
wire->port_output = false;
RTLIL::Wire *in_wire = module->wire(stringf("%s[%d]", escaped_s.substr(0, escaped_s.size()-10).c_str(), index));
log_assert(in_wire);
log_assert(in_wire->port_input && !in_wire->port_output);
in_wire->port_output = true;
module->connect(in_wire, wire);
}
else {
module->rename(wire, indexed_name);
if (wideports)
wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index);
}
}
else {
module->connect(wire, existing);
wire->port_output = false;
}
}
}
else
log_error("Symbol type '%s' not recognised.\n", type.c_str());
}
}
for (auto &wp : wideports_cache) {
auto name = wp.first;
int width = wp.second + 1;
RTLIL::Wire *wire = module->wire(name);
if (wire)
module->rename(wire, RTLIL::escape_id(stringf("%s[%d]", name.c_str(), 0)));
// Do not make ports with a mix of input/output into
// wide ports
bool port_input = false, port_output = false;
for (int i = 0; i < width; i++) {
RTLIL::IdString other_name = name.str() + stringf("[%d]", i);
RTLIL::Wire *other_wire = module->wire(other_name);
if (other_wire) {
port_input = port_input || other_wire->port_input;
port_output = port_output || other_wire->port_output;
}
}
if ((port_input && port_output) || (!port_input && !port_output))
continue;
wire = module->addWire(name, width);
wire->port_input = port_input;
wire->port_output = port_output;
for (int i = 0; i < width; i++) {
RTLIL::IdString other_name = name.str() + stringf("[%d]", i);
RTLIL::Wire *other_wire = module->wire(other_name);
if (other_wire) {
other_wire->port_input = false;
other_wire->port_output = false;
if (wire->port_input)
module->connect(other_wire, SigSpec(wire, i));
else
module->connect(SigSpec(wire, i), other_wire);
}
}
}
module->fixup_ports();
design->add(module);
for (auto cell : module->cells().to_vector()) {
if (cell->type != "$lut") continue;
auto y_port = cell->getPort("\\Y").as_bit();
if (y_port.wire->width == 1)
module->rename(cell, stringf("%s$lut", y_port.wire->name.c_str()));
else
module->rename(cell, stringf("%s[%d]$lut", y_port.wire->name.c_str(), y_port.offset));
}
} }
void AigerReader::parse_aiger_ascii() void AigerReader::parse_aiger_ascii()
@ -616,7 +321,7 @@ void AigerReader::parse_aiger_ascii()
unsigned l1, l2, l3; unsigned l1, l2, l3;
// Parse inputs // Parse inputs
for (unsigned i = 0; i < I; ++i, ++line_count) { for (unsigned i = 1; i <= I; ++i, ++line_count) {
if (!(f >> l1)) if (!(f >> l1))
log_error("Line %u cannot be interpreted as an input!\n", line_count); log_error("Line %u cannot be interpreted as an input!\n", line_count);
log_debug("%d is an input\n", l1); log_debug("%d is an input\n", l1);
@ -652,17 +357,19 @@ void AigerReader::parse_aiger_ascii()
if (!(f >> l3)) if (!(f >> l3))
log_error("Line %u cannot be interpreted as a latch!\n", line_count); log_error("Line %u cannot be interpreted as a latch!\n", line_count);
if (l3 == 0 || l3 == 1) if (l3 == 0)
q_wire->attributes["\\init"] = RTLIL::Const(l3); q_wire->attributes["\\init"] = RTLIL::S0;
else if (l3 == 1)
q_wire->attributes["\\init"] = RTLIL::S1;
else if (l3 == l1) { else if (l3 == l1) {
//q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx); //q_wire->attributes["\\init"] = RTLIL::Sx;
} }
else else
log_error("Line %u has invalid reset literal for latch!\n", line_count); log_error("Line %u has invalid reset literal for latch!\n", line_count);
} }
else { else {
// AIGER latches are assumed to be initialized to zero // AIGER latches are assumed to be initialized to zero
q_wire->attributes["\\init"] = RTLIL::Const(0); q_wire->attributes["\\init"] = RTLIL::S0;
} }
latches.push_back(q_wire); latches.push_back(q_wire);
} }
@ -672,40 +379,32 @@ void AigerReader::parse_aiger_ascii()
if (!(f >> l1)) if (!(f >> l1))
log_error("Line %u cannot be interpreted as an output!\n", line_count); log_error("Line %u cannot be interpreted as an output!\n", line_count);
RTLIL::Wire *wire;
if (l1 == 0 || l1 == 1) {
wire = module->addWire(NEW_ID);
if (l1 == 0)
module->connect(wire, RTLIL::State::S0);
else if (l1 == 1)
module->connect(wire, RTLIL::State::S1);
else
log_abort();
}
else {
log_debug("%d is an output\n", l1); log_debug("%d is an output\n", l1);
const unsigned variable = l1 >> 1; const unsigned variable = l1 >> 1;
const bool invert = l1 & 1; const bool invert = l1 & 1;
RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "b" the right suffix? RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "b" the right suffix?
wire = module->wire(wire_name); RTLIL::Wire *wire = module->wire(wire_name);
if (!wire) if (!wire)
wire = createWireIfNotExists(module, l1); wire = createWireIfNotExists(module, l1);
else { else if (wire->port_input || wire->port_output) {
if (wire->port_input || wire->port_output) {
RTLIL::Wire *new_wire = module->addWire(NEW_ID); RTLIL::Wire *new_wire = module->addWire(NEW_ID);
module->connect(new_wire, wire); module->connect(new_wire, wire);
wire = new_wire; wire = new_wire;
} }
}
}
wire->port_output = true; wire->port_output = true;
outputs.push_back(wire); outputs.push_back(wire);
} }
std::getline(f, line); // Ignore up to start of next line
// TODO: Parse bad state properties // Parse bad properties
for (unsigned i = 0; i < B; ++i, ++line_count) for (unsigned i = 0; i < B; ++i, ++line_count) {
std::getline(f, line); // Ignore up to start of next line if (!(f >> l1))
log_error("Line %u cannot be interpreted as a bad state property!\n", line_count);
log_debug("%d is a bad state property\n", l1);
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
wire->port_output = true;
bad_properties.push_back(wire);
}
// TODO: Parse invariant constraints // TODO: Parse invariant constraints
for (unsigned i = 0; i < C; ++i, ++line_count) for (unsigned i = 0; i < C; ++i, ++line_count)
@ -783,17 +482,19 @@ void AigerReader::parse_aiger_binary()
if (!(f >> l3)) if (!(f >> l3))
log_error("Line %u cannot be interpreted as a latch!\n", line_count); log_error("Line %u cannot be interpreted as a latch!\n", line_count);
if (l3 == 0 || l3 == 1) if (l3 == 0)
q_wire->attributes["\\init"] = RTLIL::Const(l3); q_wire->attributes["\\init"] = RTLIL::S0;
else if (l3 == 1)
q_wire->attributes["\\init"] = RTLIL::S1;
else if (l3 == l1) { else if (l3 == l1) {
//q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx); //q_wire->attributes["\\init"] = RTLIL::Sx;
} }
else else
log_error("Line %u has invalid reset literal for latch!\n", line_count); log_error("Line %u has invalid reset literal for latch!\n", line_count);
} }
else { else {
// AIGER latches are assumed to be initialized to zero // AIGER latches are assumed to be initialized to zero
q_wire->attributes["\\init"] = RTLIL::Const(0); q_wire->attributes["\\init"] = RTLIL::S0;
} }
latches.push_back(q_wire); latches.push_back(q_wire);
} }
@ -803,39 +504,34 @@ void AigerReader::parse_aiger_binary()
if (!(f >> l1)) if (!(f >> l1))
log_error("Line %u cannot be interpreted as an output!\n", line_count); log_error("Line %u cannot be interpreted as an output!\n", line_count);
RTLIL::Wire *wire;
if (l1 == 0 || l1 == 1) {
wire = module->addWire(NEW_ID);
if (l1 == 0)
module->connect(wire, RTLIL::State::S0);
else if (l1 == 1)
module->connect(wire, RTLIL::State::S1);
else
log_abort();
}
else {
log_debug("%d is an output\n", l1); log_debug("%d is an output\n", l1);
const unsigned variable = l1 >> 1; const unsigned variable = l1 >> 1;
const bool invert = l1 & 1; const bool invert = l1 & 1;
RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "_inv" the right suffix? RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "_b" the right suffix?
wire = module->wire(wire_name); RTLIL::Wire *wire = module->wire(wire_name);
if (!wire) if (!wire)
wire = createWireIfNotExists(module, l1); wire = createWireIfNotExists(module, l1);
else { else if (wire->port_input || wire->port_output) {
if (wire->port_input || wire->port_output) {
RTLIL::Wire *new_wire = module->addWire(NEW_ID); RTLIL::Wire *new_wire = module->addWire(NEW_ID);
module->connect(new_wire, wire); module->connect(new_wire, wire);
wire = new_wire; wire = new_wire;
} }
}
}
wire->port_output = true; wire->port_output = true;
outputs.push_back(wire); outputs.push_back(wire);
} }
std::getline(f, line); // Ignore up to start of next line std::getline(f, line); // Ignore up to start of next line
// TODO: Parse bad state properties // Parse bad properties
for (unsigned i = 0; i < B; ++i, ++line_count) for (unsigned i = 0; i < B; ++i, ++line_count) {
if (!(f >> l1))
log_error("Line %u cannot be interpreted as a bad state property!\n", line_count);
log_debug("%d is a bad state property\n", l1);
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
wire->port_output = true;
bad_properties.push_back(wire);
}
if (B > 0)
std::getline(f, line); // Ignore up to start of next line std::getline(f, line); // Ignore up to start of next line
// TODO: Parse invariant constraints // TODO: Parse invariant constraints
@ -865,6 +561,284 @@ void AigerReader::parse_aiger_binary()
} }
} }
void AigerReader::post_process()
{
pool<RTLIL::Module*> abc_carry_modules;
unsigned ci_count = 0, co_count = 0, flop_count = 0;
for (auto cell : boxes) {
RTLIL::Module* box_module = design->module(cell->type);
log_assert(box_module);
if (box_module->attributes.count("\\abc_carry") && !abc_carry_modules.count(box_module)) {
RTLIL::Wire* carry_in = nullptr, *carry_out = nullptr;
RTLIL::Wire* last_in = nullptr, *last_out = nullptr;
for (const auto &port_name : box_module->ports) {
RTLIL::Wire* w = box_module->wire(port_name);
log_assert(w);
if (w->port_input) {
if (w->attributes.count("\\abc_carry_in")) {
log_assert(!carry_in);
carry_in = w;
}
log_assert(!last_in || last_in->port_id < w->port_id);
last_in = w;
}
if (w->port_output) {
if (w->attributes.count("\\abc_carry_out")) {
log_assert(!carry_out);
carry_out = w;
}
log_assert(!last_out || last_out->port_id < w->port_id);
last_out = w;
}
}
if (carry_in != last_in) {
std::swap(box_module->ports[carry_in->port_id], box_module->ports[last_in->port_id]);
std::swap(carry_in->port_id, last_in->port_id);
}
if (carry_out != last_out) {
log_assert(last_out);
std::swap(box_module->ports[carry_out->port_id], box_module->ports[last_out->port_id]);
std::swap(carry_out->port_id, last_out->port_id);
}
}
bool flop = box_module->attributes.count("\\abc_flop");
log_assert(!flop || flop_count < flopNum);
// NB: Assume box_module->ports are sorted alphabetically
// (as RTLIL::Module::fixup_ports() would do)
for (auto port_name : box_module->ports) {
RTLIL::Wire* w = box_module->wire(port_name);
log_assert(w);
RTLIL::SigSpec rhs;
RTLIL::Wire* wire = nullptr;
for (int i = 0; i < GetSize(w); i++) {
if (w->port_input) {
log_assert(co_count < outputs.size());
wire = outputs[co_count++];
log_assert(wire);
log_assert(wire->port_output);
wire->port_output = false;
if (flop && w->attributes.count("\\abc_flop_d")) {
RTLIL::Wire* d = outputs[outputs.size() - flopNum + flop_count];
log_assert(d);
log_assert(d->port_output);
d->port_output = false;
}
}
if (w->port_output) {
log_assert((piNum + ci_count) < inputs.size());
wire = inputs[piNum + ci_count++];
log_assert(wire);
log_assert(wire->port_input);
wire->port_input = false;
if (flop && w->attributes.count("\\abc_flop_q")) {
wire = inputs[piNum - flopNum + flop_count];
log_assert(wire);
log_assert(wire->port_input);
wire->port_input = false;
}
}
rhs.append(wire);
}
cell->setPort(port_name, rhs);
}
if (flop) flop_count++;
}
dict<RTLIL::IdString, int> wideports_cache;
if (!map_filename.empty()) {
std::ifstream mf(map_filename);
std::string type, symbol;
int variable, index;
while (mf >> type >> variable >> index >> symbol) {
RTLIL::IdString escaped_s = RTLIL::escape_id(symbol);
if (type == "input") {
log_assert(static_cast<unsigned>(variable) < inputs.size());
RTLIL::Wire* wire = inputs[variable];
log_assert(wire);
log_assert(wire->port_input);
if (index == 0) {
// Cope with the fact that a CI might be identical
// to a PI (necessary due to ABC); in those cases
// simply connect the latter to the former
RTLIL::Wire* existing = module->wire(escaped_s);
if (!existing)
module->rename(wire, escaped_s);
else {
wire->port_input = false;
module->connect(wire, existing);
}
}
else if (index > 0) {
std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index);
RTLIL::Wire* existing = module->wire(indexed_name);
if (!existing) {
module->rename(wire, indexed_name);
if (wideports)
wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index);
}
else {
module->connect(wire, existing);
wire->port_input = false;
}
}
}
else if (type == "output") {
log_assert(static_cast<unsigned>(variable + co_count) < outputs.size());
RTLIL::Wire* wire = outputs[variable + co_count];
log_assert(wire);
log_assert(wire->port_output);
if (escaped_s.in("\\__dummy_o__", "\\__const0__", "\\__const1__")) {
wire->port_output = false;
continue;
}
if (index == 0) {
// Cope with the fact that a CO might be identical
// to a PO (necessary due to ABC); in those cases
// simply connect the latter to the former
RTLIL::Wire* existing = module->wire(escaped_s);
if (!existing) {
if (escaped_s.ends_with("$inout.out")) {
wire->port_output = false;
RTLIL::Wire *in_wire = module->wire(escaped_s.substr(0, escaped_s.size()-10));
log_assert(in_wire);
log_assert(in_wire->port_input && !in_wire->port_output);
in_wire->port_output = true;
module->connect(in_wire, wire);
}
else
module->rename(wire, escaped_s);
}
else {
wire->port_output = false;
module->connect(wire, existing);
}
}
else if (index > 0) {
std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index);
RTLIL::Wire* existing = module->wire(indexed_name);
if (!existing) {
if (escaped_s.ends_with("$inout.out")) {
wire->port_output = false;
RTLIL::Wire *in_wire = module->wire(stringf("%s[%d]", escaped_s.substr(0, escaped_s.size()-10).c_str(), index));
log_assert(in_wire);
log_assert(in_wire->port_input && !in_wire->port_output);
in_wire->port_output = true;
module->connect(in_wire, wire);
}
else {
module->rename(wire, indexed_name);
if (wideports)
wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index);
}
}
else {
module->connect(wire, existing);
wire->port_output = false;
}
}
}
else if (type == "box") {
RTLIL::Cell* cell = module->cell(stringf("$__box%d__", variable));
if (cell) { // ABC could have optimised this box away
module->rename(cell, escaped_s);
RTLIL::Module* box_module = design->module(cell->type);
log_assert(box_module);
for (const auto &i : cell->connections()) {
RTLIL::IdString port_name = i.first;
RTLIL::SigSpec rhs = i.second;
int index = 0;
for (auto bit : rhs.bits()) {
RTLIL::Wire* wire = bit.wire;
RTLIL::IdString escaped_s = RTLIL::escape_id(stringf("%s.%s", log_id(cell), log_id(port_name)));
if (index == 0)
module->rename(wire, escaped_s);
else if (index > 0) {
module->rename(wire, stringf("%s[%d]", escaped_s.c_str(), index));
if (wideports)
wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index);
}
index++;
}
}
}
}
else
log_error("Symbol type '%s' not recognised.\n", type.c_str());
}
}
for (auto &wp : wideports_cache) {
auto name = wp.first;
int width = wp.second + 1;
RTLIL::Wire *wire = module->wire(name);
if (wire)
module->rename(wire, RTLIL::escape_id(stringf("%s[%d]", name.c_str(), 0)));
// Do not make ports with a mix of input/output into
// wide ports
bool port_input = false, port_output = false;
for (int i = 0; i < width; i++) {
RTLIL::IdString other_name = name.str() + stringf("[%d]", i);
RTLIL::Wire *other_wire = module->wire(other_name);
if (other_wire) {
port_input = port_input || other_wire->port_input;
port_output = port_output || other_wire->port_output;
}
}
if ((port_input && port_output) || (!port_input && !port_output))
continue;
wire = module->addWire(name, width);
wire->port_input = port_input;
wire->port_output = port_output;
for (int i = 0; i < width; i++) {
RTLIL::IdString other_name = name.str() + stringf("[%d]", i);
RTLIL::Wire *other_wire = module->wire(other_name);
if (other_wire) {
other_wire->port_input = false;
other_wire->port_output = false;
if (wire->port_input)
module->connect(other_wire, SigSpec(wire, i));
else
module->connect(SigSpec(wire, i), other_wire);
}
}
}
module->fixup_ports();
design->add(module);
design->selection_stack.emplace_back(false);
RTLIL::Selection& sel = design->selection_stack.back();
sel.select(module);
Pass::call(design, "clean");
design->selection_stack.pop_back();
for (auto cell : module->cells().to_vector()) {
if (cell->type != "$lut") continue;
auto y_port = cell->getPort("\\Y").as_bit();
if (y_port.wire->width == 1)
module->rename(cell, stringf("%s$lut", y_port.wire->name.c_str()));
else
module->rename(cell, stringf("%s[%d]$lut", y_port.wire->name.c_str(), y_port.offset));
}
}
struct AigerFrontend : public Frontend { struct AigerFrontend : public Frontend {
AigerFrontend() : Frontend("aiger", "read AIGER file") { } AigerFrontend() : Frontend("aiger", "read AIGER file") { }
void help() YS_OVERRIDE void help() YS_OVERRIDE

View File

@ -37,16 +37,20 @@ struct AigerReader
unsigned M, I, L, O, A; unsigned M, I, L, O, A;
unsigned B, C, J, F; // Optional in AIGER 1.9 unsigned B, C, J, F; // Optional in AIGER 1.9
unsigned line_count; unsigned line_count;
uint32_t piNum, flopNum;
std::vector<RTLIL::Wire*> inputs; std::vector<RTLIL::Wire*> inputs;
std::vector<RTLIL::Wire*> latches; std::vector<RTLIL::Wire*> latches;
std::vector<RTLIL::Wire*> outputs; std::vector<RTLIL::Wire*> outputs;
std::vector<RTLIL::Wire*> bad_properties;
std::vector<RTLIL::Cell*> boxes;
AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports); AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports);
void parse_aiger(); void parse_aiger();
void parse_xaiger(); void parse_xaiger();
void parse_aiger_ascii(); void parse_aiger_ascii();
void parse_aiger_binary(); void parse_aiger_binary();
void post_process();
}; };
YOSYS_NAMESPACE_END YOSYS_NAMESPACE_END

View File

@ -154,6 +154,7 @@ std::string AST::type2str(AstNodeType type)
X(AST_GENIF) X(AST_GENIF)
X(AST_GENCASE) X(AST_GENCASE)
X(AST_GENBLOCK) X(AST_GENBLOCK)
X(AST_TECALL)
X(AST_POSEDGE) X(AST_POSEDGE)
X(AST_NEGEDGE) X(AST_NEGEDGE)
X(AST_EDGE) X(AST_EDGE)
@ -194,6 +195,9 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch
is_logic = false; is_logic = false;
is_signed = false; is_signed = false;
is_string = false; is_string = false;
is_wand = false;
is_wor = false;
is_unsized = false;
was_checked = false; was_checked = false;
range_valid = false; range_valid = false;
range_swapped = false; range_swapped = false;
@ -722,7 +726,7 @@ AstNode *AstNode::mkconst_int(uint32_t v, bool is_signed, int width)
} }
// create an AST node for a constant (using a bit vector as value) // create an AST node for a constant (using a bit vector as value)
AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed) AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized)
{ {
AstNode *node = new AstNode(AST_CONSTANT); AstNode *node = new AstNode(AST_CONSTANT);
node->is_signed = is_signed; node->is_signed = is_signed;
@ -736,9 +740,15 @@ AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signe
node->range_valid = true; node->range_valid = true;
node->range_left = node->bits.size()-1; node->range_left = node->bits.size()-1;
node->range_right = 0; node->range_right = 0;
node->is_unsized = is_unsized;
return node; return node;
} }
AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed)
{
return mkconst_bits(v, is_signed, false);
}
// create an AST node for a constant (using a string in bit vector form as value) // create an AST node for a constant (using a string in bit vector form as value)
AstNode *AstNode::mkconst_str(const std::vector<RTLIL::State> &v) AstNode *AstNode::mkconst_str(const std::vector<RTLIL::State> &v)
{ {
@ -775,6 +785,14 @@ bool AstNode::bits_only_01() const
return true; return true;
} }
RTLIL::Const AstNode::bitsAsUnsizedConst(int width)
{
RTLIL::State extbit = bits.back();
while (width > int(bits.size()))
bits.push_back(extbit);
return RTLIL::Const(bits);
}
RTLIL::Const AstNode::bitsAsConst(int width, bool is_signed) RTLIL::Const AstNode::bitsAsConst(int width, bool is_signed)
{ {
std::vector<RTLIL::State> bits = this->bits; std::vector<RTLIL::State> bits = this->bits;
@ -951,6 +969,9 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
continue; continue;
if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM) if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
continue; continue;
if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE &&
(child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule"))
continue;
blackbox_module = false; blackbox_module = false;
break; break;
} }
@ -1035,6 +1056,9 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
child->delete_children(); child->delete_children();
child->children.push_back(AstNode::mkconst_int(0, false, 0)); child->children.push_back(AstNode::mkconst_int(0, false, 0));
new_children.push_back(child); new_children.push_back(child);
} else if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE &&
(child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule")) {
new_children.push_back(child);
} else { } else {
delete child; delete child;
} }

View File

@ -137,6 +137,7 @@ namespace AST
AST_GENIF, AST_GENIF,
AST_GENCASE, AST_GENCASE,
AST_GENBLOCK, AST_GENBLOCK,
AST_TECALL,
AST_POSEDGE, AST_POSEDGE,
AST_NEGEDGE, AST_NEGEDGE,
@ -173,7 +174,7 @@ namespace AST
// node content - most of it is unused in most node types // node content - most of it is unused in most node types
std::string str; std::string str;
std::vector<RTLIL::State> bits; std::vector<RTLIL::State> bits;
bool is_input, is_output, is_reg, is_logic, is_signed, is_string, range_valid, range_swapped, was_checked; bool is_input, is_output, is_reg, is_logic, is_signed, is_string, is_wand, is_wor, range_valid, range_swapped, was_checked, is_unsized;
int port_id, range_left, range_right; int port_id, range_left, range_right;
uint32_t integer; uint32_t integer;
double realvalue; double realvalue;
@ -262,6 +263,7 @@ namespace AST
// helper functions for creating AST nodes for constants // helper functions for creating AST nodes for constants
static AstNode *mkconst_int(uint32_t v, bool is_signed, int width = 32); static AstNode *mkconst_int(uint32_t v, bool is_signed, int width = 32);
static AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized);
static AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed); static AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed);
static AstNode *mkconst_str(const std::vector<RTLIL::State> &v); static AstNode *mkconst_str(const std::vector<RTLIL::State> &v);
static AstNode *mkconst_str(const std::string &str); static AstNode *mkconst_str(const std::string &str);
@ -269,6 +271,7 @@ namespace AST
// helper function for creating sign-extended const objects // helper function for creating sign-extended const objects
RTLIL::Const bitsAsConst(int width, bool is_signed); RTLIL::Const bitsAsConst(int width, bool is_signed);
RTLIL::Const bitsAsConst(int width = -1); RTLIL::Const bitsAsConst(int width = -1);
RTLIL::Const bitsAsUnsizedConst(int width);
RTLIL::Const asAttrConst(); RTLIL::Const asAttrConst();
RTLIL::Const asParaConst(); RTLIL::Const asParaConst();
uint64_t asInt(bool is_signed); uint64_t asInt(bool is_signed);

View File

@ -645,6 +645,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (!id_ast->children[0]->range_valid) if (!id_ast->children[0]->range_valid)
log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str()); log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str());
this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1; this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1;
if (children.size() > 1)
range = children[1];
} else } else
log_file_error(filename, linenum, "Failed to detect width for identifier %s!\n", str.c_str()); log_file_error(filename, linenum, "Failed to detect width for identifier %s!\n", str.c_str());
if (range) { if (range) {
@ -902,7 +904,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (!range_valid) if (!range_valid)
log_file_error(filename, linenum, "Signal `%s' with non-constant width!\n", str.c_str()); log_file_error(filename, linenum, "Signal `%s' with non-constant width!\n", str.c_str());
log_assert(range_left >= range_right || (range_left == -1 && range_right == 0)); if (!(range_left >= range_right || (range_left == -1 && range_right == 0)))
log_file_error(filename, linenum, "Signal `%s' with invalid width range %d!\n", str.c_str(), range_left - range_right + 1);
RTLIL::Wire *wire = current_module->addWire(str, range_left - range_right + 1); RTLIL::Wire *wire = current_module->addWire(str, range_left - range_right + 1);
wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
@ -917,6 +920,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
wire->attributes[attr.first] = attr.second->asAttrConst(); wire->attributes[attr.first] = attr.second->asAttrConst();
} }
if (is_wand) wire->set_bool_attribute("\\wand");
if (is_wor) wire->set_bool_attribute("\\wor");
} }
break; break;
@ -961,8 +967,13 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
detectSignWidth(width_hint, sign_hint); detectSignWidth(width_hint, sign_hint);
is_signed = sign_hint; is_signed = sign_hint;
if (type == AST_CONSTANT) if (type == AST_CONSTANT) {
if (is_unsized) {
return RTLIL::SigSpec(bitsAsUnsizedConst(width_hint));
} else {
return RTLIL::SigSpec(bitsAsConst()); return RTLIL::SigSpec(bitsAsConst());
}
}
RTLIL::SigSpec sig = realAsConst(width_hint); RTLIL::SigSpec sig = realAsConst(width_hint);
log_file_warning(filename, linenum, "converting real value %e to binary %s.\n", realvalue, log_signal(sig)); log_file_warning(filename, linenum, "converting real value %e to binary %s.\n", realvalue, log_signal(sig));
@ -1490,10 +1501,12 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
continue; continue;
} }
if (child->type == AST_PARASET) { if (child->type == AST_PARASET) {
int extra_const_flags = 0;
IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str; IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str;
if (child->children[0]->type == AST_REALVALUE) { if (child->children[0]->type == AST_REALVALUE) {
log_file_warning(filename, linenum, "Replacing floating point parameter %s.%s = %f with string.\n", log_file_warning(filename, linenum, "Replacing floating point parameter %s.%s = %f with string.\n",
log_id(cell), log_id(paraname), child->children[0]->realvalue); log_id(cell), log_id(paraname), child->children[0]->realvalue);
extra_const_flags = RTLIL::CONST_FLAG_REAL;
auto strnode = AstNode::mkconst_str(stringf("%f", child->children[0]->realvalue)); auto strnode = AstNode::mkconst_str(stringf("%f", child->children[0]->realvalue));
strnode->cloneInto(child->children[0]); strnode->cloneInto(child->children[0]);
delete strnode; delete strnode;
@ -1502,6 +1515,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
log_file_error(filename, linenum, "Parameter %s.%s with non-constant value!\n", log_file_error(filename, linenum, "Parameter %s.%s with non-constant value!\n",
log_id(cell), log_id(paraname)); log_id(cell), log_id(paraname));
cell->parameters[paraname] = child->children[0]->asParaConst(); cell->parameters[paraname] = child->children[0]->asParaConst();
cell->parameters[paraname].flags |= extra_const_flags;
continue; continue;
} }
if (child->type == AST_ARGUMENT) { if (child->type == AST_ARGUMENT) {
@ -1521,9 +1535,29 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
} }
for (auto &attr : attributes) { for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT) if (attr.second->type != AST_CONSTANT)
log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); log_file_error(filename, linenum, "Attribute `%s' with non-constant value.\n", attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst(); cell->attributes[attr.first] = attr.second->asAttrConst();
} }
if (cell->type.in("$specify2", "$specify3")) {
int src_width = GetSize(cell->getPort("\\SRC"));
int dst_width = GetSize(cell->getPort("\\DST"));
bool full = cell->getParam("\\FULL").as_bool();
if (!full && src_width != dst_width)
log_file_error(filename, linenum, "Parallel specify SRC width does not match DST width.\n");
if (cell->type == "$specify3") {
int dat_width = GetSize(cell->getPort("\\DAT"));
if (dat_width != dst_width)
log_file_error(filename, linenum, "Specify DAT width does not match DST width.\n");
}
cell->setParam("\\SRC_WIDTH", Const(src_width));
cell->setParam("\\DST_WIDTH", Const(dst_width));
}
if (cell->type == "$specrule") {
int src_width = GetSize(cell->getPort("\\SRC"));
int dst_width = GetSize(cell->getPort("\\DST"));
cell->setParam("\\SRC_WIDTH", Const(src_width));
cell->setParam("\\DST_WIDTH", Const(dst_width));
}
} }
break; break;
@ -1541,6 +1575,37 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
delete always; delete always;
} break; } break;
case AST_TECALL: {
int sz = children.size();
if (str == "$info") {
if (sz > 0)
log_file_info(filename, linenum, "%s.\n", children[0]->str.c_str());
else
log_file_info(filename, linenum, "\n");
} else if (str == "$warning") {
if (sz > 0)
log_file_warning(filename, linenum, "%s.\n", children[0]->str.c_str());
else
log_file_warning(filename, linenum, "\n");
} else if (str == "$error") {
if (sz > 0)
log_file_error(filename, linenum, "%s.\n", children[0]->str.c_str());
else
log_file_error(filename, linenum, "\n");
} else if (str == "$fatal") {
// TODO: 1st parameter, if exists, is 0,1 or 2, and passed to $finish()
// if no parameter is given, default value is 1
// dollar_finish(sz ? children[0] : 1);
// perhaps create & use log_file_fatal()
if (sz > 0)
log_file_error(filename, linenum, "FATAL: %s.\n", children[0]->str.c_str());
else
log_file_error(filename, linenum, "FATAL.\n");
} else {
log_file_error(filename, linenum, "Unknown elabortoon system task '%s'.\n", str.c_str());
}
} break;
case AST_FCALL: { case AST_FCALL: {
if (str == "\\$anyconst" || str == "\\$anyseq" || str == "\\$allconst" || str == "\\$allseq") if (str == "\\$anyconst" || str == "\\$anyseq" || str == "\\$allconst" || str == "\\$allseq")
{ {

View File

@ -1172,6 +1172,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
varbuf->children[0] = buf; varbuf->children[0] = buf;
} }
if (type == AST_FOR) {
AstNode *buf = next_ast->clone();
delete buf->children[1];
buf->children[1] = varbuf->children[0]->clone();
current_block->children.insert(current_block->children.begin() + current_block_idx++, buf);
}
current_scope[varbuf->str] = backup_scope_varbuf; current_scope[varbuf->str] = backup_scope_varbuf;
delete varbuf; delete varbuf;
delete_children(); delete_children();
@ -1598,6 +1605,7 @@ skip_dynamic_range_lvalue_expansion:;
current_scope[wire_tmp->str] = wire_tmp; current_scope[wire_tmp->str] = wire_tmp;
wire_tmp->attributes["\\nosync"] = AstNode::mkconst_int(1, false); wire_tmp->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
while (wire_tmp->simplify(true, false, false, 1, -1, false, false)) { } while (wire_tmp->simplify(true, false, false, 1, -1, false, false)) { }
wire_tmp->is_logic = true;
AstNode *wire_tmp_id = new AstNode(AST_IDENTIFIER); AstNode *wire_tmp_id = new AstNode(AST_IDENTIFIER);
wire_tmp_id->str = wire_tmp->str; wire_tmp_id->str = wire_tmp->str;

View File

@ -53,6 +53,7 @@ USING_YOSYS_NAMESPACE
"attribute" { return TOK_ATTRIBUTE; } "attribute" { return TOK_ATTRIBUTE; }
"parameter" { return TOK_PARAMETER; } "parameter" { return TOK_PARAMETER; }
"signed" { return TOK_SIGNED; } "signed" { return TOK_SIGNED; }
"real" { return TOK_REAL; }
"wire" { return TOK_WIRE; } "wire" { return TOK_WIRE; }
"memory" { return TOK_MEMORY; } "memory" { return TOK_MEMORY; }
"width" { return TOK_WIDTH; } "width" { return TOK_WIDTH; }

View File

@ -45,7 +45,16 @@ YOSYS_NAMESPACE_END
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
%} %}
%name-prefix "rtlil_frontend_ilang_yy" %define api.prefix {rtlil_frontend_ilang_yy}
/* The union is defined in the header, so we need to provide all the
* includes it requires
*/
%code requires {
#include <string>
#include <vector>
#include "frontends/ilang/ilang_frontend.h"
}
%union { %union {
char *string; char *string;
@ -61,7 +70,7 @@ USING_YOSYS_NAMESPACE
%token TOK_CELL TOK_CONNECT TOK_SWITCH TOK_CASE TOK_ASSIGN TOK_SYNC %token TOK_CELL TOK_CONNECT TOK_SWITCH TOK_CASE TOK_ASSIGN TOK_SYNC
%token TOK_LOW TOK_HIGH TOK_POSEDGE TOK_NEGEDGE TOK_EDGE TOK_ALWAYS TOK_GLOBAL TOK_INIT %token TOK_LOW TOK_HIGH TOK_POSEDGE TOK_NEGEDGE TOK_EDGE TOK_ALWAYS TOK_GLOBAL TOK_INIT
%token TOK_UPDATE TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET %token TOK_UPDATE TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET
%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_UPTO %token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_REAL TOK_UPTO
%type <rsigspec> sigspec_list_reversed %type <rsigspec> sigspec_list_reversed
%type <sigspec> sigspec sigspec_list %type <sigspec> sigspec sigspec_list
@ -241,6 +250,12 @@ cell_body:
free($4); free($4);
delete $5; delete $5;
} | } |
cell_body TOK_PARAMETER TOK_REAL TOK_ID constant EOL {
current_cell->parameters[$4] = *$5;
current_cell->parameters[$4].flags |= RTLIL::CONST_FLAG_REAL;
free($4);
delete $5;
} |
cell_body TOK_CONNECT TOK_ID sigspec EOL { cell_body TOK_CONNECT TOK_ID sigspec EOL {
if (current_cell->hasPort($3)) if (current_cell->hasPort($3))
rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell port %s.", $3).c_str()); rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell port %s.", $3).c_str());
@ -445,4 +460,3 @@ conn_stmt:
delete $2; delete $2;
delete $3; delete $3;
}; };

View File

@ -46,7 +46,15 @@ USING_YOSYS_NAMESPACE
#include "VeriModule.h" #include "VeriModule.h"
#include "VeriWrite.h" #include "VeriWrite.h"
#include "VhdlUnits.h" #include "VhdlUnits.h"
#include "Message.h" #include "VeriLibrary.h"
#ifndef SYMBIOTIC_VERIFIC_API_VERSION
# error "Only Symbiotic EDA flavored Verific is supported. Please contact office@symbioticeda.com for commercial support for Yosys+Verific."
#endif
#if SYMBIOTIC_VERIFIC_API_VERSION < 1
# error "Please update your version of Symbiotic EDA flavored Verific."
#endif
#ifdef __clang__ #ifdef __clang__
#pragma clang diagnostic pop #pragma clang diagnostic pop
@ -776,13 +784,14 @@ void VerificImporter::merge_past_ffs(pool<RTLIL::Cell*> &candidates)
void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*> &nl_todo) void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*> &nl_todo)
{ {
std::string module_name = nl->IsOperator() ? std::string("$verific$") + nl->Owner()->Name() : RTLIL::escape_id(nl->Owner()->Name()); std::string netlist_name = nl->GetAtt(" \\top") ? nl->CellBaseName() : nl->Owner()->Name();
std::string module_name = nl->IsOperator() ? "$verific$" + netlist_name : RTLIL::escape_id(netlist_name);
netlist = nl; netlist = nl;
if (design->has(module_name)) { if (design->has(module_name)) {
if (!nl->IsOperator() && !is_blackbox(nl)) if (!nl->IsOperator() && !is_blackbox(nl))
log_cmd_error("Re-definition of module `%s'.\n", nl->Owner()->Name()); log_cmd_error("Re-definition of module `%s'.\n", netlist_name.c_str());
return; return;
} }
@ -1752,31 +1761,63 @@ struct VerificExtNets
} }
}; };
void verific_import(Design *design, std::string top) void verific_import(Design *design, const std::map<std::string,std::string> &parameters, std::string top)
{ {
verific_sva_fsm_limit = 16; verific_sva_fsm_limit = 16;
std::set<Netlist*> nl_todo, nl_done; std::set<Netlist*> nl_todo, nl_done;
{
VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1); VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1);
VeriLibrary *veri_lib = veri_file::GetLibrary("work", 1); VeriLibrary *veri_lib = veri_file::GetLibrary("work", 1);
Array *netlists = NULL;
Array veri_libs, vhdl_libs; Array veri_libs, vhdl_libs;
if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib); if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib);
if (veri_lib) veri_libs.InsertLast(veri_lib); if (veri_lib) veri_libs.InsertLast(veri_lib);
Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs); Map verific_params(STRING_HASH);
for (const auto &i : parameters)
verific_params.Insert(i.first.c_str(), i.second.c_str());
if (top.empty()) {
netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, &verific_params);
}
else {
Array veri_modules, vhdl_units;
if (veri_lib) {
VeriModule *veri_module = veri_lib->GetModule(top.c_str(), 1);
if (veri_module) {
veri_modules.InsertLast(veri_module);
}
// Also elaborate all root modules since they may contain bind statements
MapIter mi;
FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) {
if (!veri_module->IsRootModule()) continue;
veri_modules.InsertLast(veri_module);
}
}
if (vhdl_lib) {
VhdlDesignUnit *vhdl_unit = vhdl_lib->GetPrimUnit(top.c_str());
if (vhdl_unit)
vhdl_units.InsertLast(vhdl_unit);
}
netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, &verific_params);
}
Netlist *nl; Netlist *nl;
int i; int i;
FOREACH_ARRAY_ITEM(netlists, i, nl) { FOREACH_ARRAY_ITEM(netlists, i, nl) {
if (top.empty() || nl->Owner()->Name() == top) if (top.empty() && nl->CellBaseName() != top)
continue;
nl->AddAtt(new Att(" \\top", NULL));
nl_todo.insert(nl); nl_todo.insert(nl);
} }
delete netlists; delete netlists;
}
if (!verific_error_msg.empty()) if (!verific_error_msg.empty())
log_error("%s\n", verific_error_msg.c_str()); log_error("%s\n", verific_error_msg.c_str());
@ -1983,6 +2024,9 @@ struct VerificPass : public Pass {
// WARNING: instantiating unknown module 'XYZ' (VERI-1063) // WARNING: instantiating unknown module 'XYZ' (VERI-1063)
Message::SetMessageType("VERI-1063", VERIFIC_ERROR); Message::SetMessageType("VERI-1063", VERIFIC_ERROR);
// https://github.com/YosysHQ/yosys/issues/1055
RuntimeFlags::SetVar("veri_elaborate_top_level_modules_having_interface_ports", 1) ;
#ifndef DB_PRESERVE_INITIAL_VALUE #ifndef DB_PRESERVE_INITIAL_VALUE
# warning Verific was built without DB_PRESERVE_INITIAL_VALUE. # warning Verific was built without DB_PRESERVE_INITIAL_VALUE.
#endif #endif
@ -2270,14 +2314,24 @@ struct VerificPass : public Pass {
for (; argidx < GetSize(args); argidx++) for (; argidx < GetSize(args); argidx++)
{ {
const char *name = args[argidx].c_str(); const char *name = args[argidx].c_str();
VeriLibrary* veri_lib = veri_file::GetLibrary(work.c_str(), 1);
VeriModule *veri_module = veri_file::GetModule(name); if (veri_lib) {
VeriModule *veri_module = veri_lib->GetModule(name, 1);
if (veri_module) { if (veri_module) {
log("Adding Verilog module '%s' to elaboration queue.\n", name); log("Adding Verilog module '%s' to elaboration queue.\n", name);
veri_modules.InsertLast(veri_module); veri_modules.InsertLast(veri_module);
continue; continue;
} }
// Also elaborate all root modules since they may contain bind statements
MapIter mi;
FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) {
if (!veri_module->IsRootModule()) continue;
veri_modules.InsertLast(veri_module);
}
}
VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1); VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1);
VhdlDesignUnit *vhdl_unit = vhdl_lib->GetPrimUnit(name); VhdlDesignUnit *vhdl_unit = vhdl_lib->GetPrimUnit(name);
if (vhdl_unit) { if (vhdl_unit) {
@ -2294,8 +2348,10 @@ struct VerificPass : public Pass {
Netlist *nl; Netlist *nl;
int i; int i;
FOREACH_ARRAY_ITEM(netlists, i, nl) FOREACH_ARRAY_ITEM(netlists, i, nl) {
nl->AddAtt(new Att(" \\top", NULL));
nl_todo.insert(nl); nl_todo.insert(nl);
}
delete netlists; delete netlists;
} }

View File

@ -26,7 +26,7 @@ YOSYS_NAMESPACE_BEGIN
extern int verific_verbose; extern int verific_verbose;
extern bool verific_import_pending; extern bool verific_import_pending;
extern void verific_import(Design *design, std::string top = std::string()); extern void verific_import(Design *design, const std::map<std::string,std::string> &parameters, std::string top = std::string());
extern pool<int> verific_sva_prims; extern pool<int> verific_sva_prims;

View File

@ -14,7 +14,7 @@ frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l
$(Q) mkdir -p $(dir $@) $(Q) mkdir -p $(dir $@)
$(P) flex -o frontends/verilog/verilog_lexer.cc $< $(P) flex -o frontends/verilog/verilog_lexer.cc $<
frontends/verilog/verilog_parser.tab.o: CXXFLAGS += -DYYMAXDEPTH=100000 frontends/verilog/verilog_parser.tab.o: CXXFLAGS += -DYYMAXDEPTH=10000000
OBJS += frontends/verilog/verilog_parser.tab.o OBJS += frontends/verilog/verilog_parser.tab.o
OBJS += frontends/verilog/verilog_lexer.o OBJS += frontends/verilog/verilog_lexer.o

View File

@ -71,7 +71,7 @@ static int my_ilog2(int x)
} }
// parse a binary, decimal, hexadecimal or octal number with support for special bits ('x', 'z' and '?') // parse a binary, decimal, hexadecimal or octal number with support for special bits ('x', 'z' and '?')
static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int len_in_bits, int base, char case_type) static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int len_in_bits, int base, char case_type, bool is_unsized)
{ {
// all digits in string (MSB at index 0) // all digits in string (MSB at index 0)
std::vector<uint8_t> digits; std::vector<uint8_t> digits;
@ -129,6 +129,9 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
return; return;
} }
if (is_unsized && (len > len_in_bits))
log_file_error(current_filename, get_line_num(), "Unsized constant must have width of 1 bit, but have %d bits!\n", len);
for (len = len - 1; len >= 0; len--) for (len = len - 1; len >= 0; len--)
if (data[len] == RTLIL::S1) if (data[len] == RTLIL::S1)
break; break;
@ -186,7 +189,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
// Simple base-10 integer // Simple base-10 integer
if (*endptr == 0) { if (*endptr == 0) {
std::vector<RTLIL::State> data; std::vector<RTLIL::State> data;
my_strtobin(data, str, -1, 10, case_type); my_strtobin(data, str, -1, 10, case_type, false);
if (data.back() == RTLIL::S1) if (data.back() == RTLIL::S1)
data.push_back(RTLIL::S0); data.push_back(RTLIL::S0);
return AstNode::mkconst_bits(data, true); return AstNode::mkconst_bits(data, true);
@ -201,6 +204,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
{ {
std::vector<RTLIL::State> data; std::vector<RTLIL::State> data;
bool is_signed = false; bool is_signed = false;
bool is_unsized = false;
if (*(endptr+1) == 's') { if (*(endptr+1) == 's') {
is_signed = true; is_signed = true;
endptr++; endptr++;
@ -209,28 +213,34 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
{ {
case 'b': case 'b':
case 'B': case 'B':
my_strtobin(data, endptr+2, len_in_bits, 2, case_type); my_strtobin(data, endptr+2, len_in_bits, 2, case_type, false);
break; break;
case 'o': case 'o':
case 'O': case 'O':
my_strtobin(data, endptr+2, len_in_bits, 8, case_type); my_strtobin(data, endptr+2, len_in_bits, 8, case_type, false);
break; break;
case 'd': case 'd':
case 'D': case 'D':
my_strtobin(data, endptr+2, len_in_bits, 10, case_type); my_strtobin(data, endptr+2, len_in_bits, 10, case_type, false);
break; break;
case 'h': case 'h':
case 'H': case 'H':
my_strtobin(data, endptr+2, len_in_bits, 16, case_type); my_strtobin(data, endptr+2, len_in_bits, 16, case_type, false);
break; break;
default: default:
char next_char = char(tolower(*(endptr+1)));
if (next_char == '0' || next_char == '1' || next_char == 'x' || next_char == 'z') {
my_strtobin(data, endptr+1, 1, 2, case_type, true);
is_unsized = true;
} else {
return NULL; return NULL;
} }
}
if (len_in_bits < 0) { if (len_in_bits < 0) {
if (is_signed && data.back() == RTLIL::S1) if (is_signed && data.back() == RTLIL::S1)
data.push_back(RTLIL::S0); data.push_back(RTLIL::S0);
} }
return AstNode::mkconst_bits(data, is_signed); return AstNode::mkconst_bits(data, is_signed, is_unsized);
} }
return NULL; return NULL;

View File

@ -158,6 +158,9 @@ struct VerilogFrontend : public Frontend {
log(" delete (* whitebox *) and (* lib_whitebox *) attributes from\n"); log(" delete (* whitebox *) and (* lib_whitebox *) attributes from\n");
log(" all modules.\n"); log(" all modules.\n");
log("\n"); log("\n");
log(" -specify\n");
log(" parse and import specify blocks\n");
log("\n");
log(" -noopt\n"); log(" -noopt\n");
log(" don't perform basic optimizations (such as const folding) in the\n"); log(" don't perform basic optimizations (such as const folding) in the\n");
log(" high-level front-end.\n"); log(" high-level front-end.\n");
@ -228,6 +231,8 @@ struct VerilogFrontend : public Frontend {
bool flag_nooverwrite = false; bool flag_nooverwrite = false;
bool flag_overwrite = false; bool flag_overwrite = false;
bool flag_defer = false; bool flag_defer = false;
bool flag_noblackbox = false;
bool flag_nowb = false;
std::map<std::string, std::string> defines_map; std::map<std::string, std::string> defines_map;
std::list<std::string> include_dirs; std::list<std::string> include_dirs;
std::list<std::string> attributes; std::list<std::string> attributes;
@ -237,13 +242,10 @@ struct VerilogFrontend : public Frontend {
formal_mode = false; formal_mode = false;
norestrict_mode = false; norestrict_mode = false;
assume_asserts_mode = false; assume_asserts_mode = false;
noblackbox_mode = false;
lib_mode = false; lib_mode = false;
nowb_mode = false; specify_mode = false;
default_nettype_wire = true; default_nettype_wire = true;
log_header(design, "Executing Verilog-2005 frontend.\n");
args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end()); args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end());
size_t argidx; size_t argidx;
@ -342,7 +344,7 @@ struct VerilogFrontend : public Frontend {
continue; continue;
} }
if (arg == "-noblackbox") { if (arg == "-noblackbox") {
noblackbox_mode = true; flag_noblackbox = true;
continue; continue;
} }
if (arg == "-lib") { if (arg == "-lib") {
@ -351,7 +353,11 @@ struct VerilogFrontend : public Frontend {
continue; continue;
} }
if (arg == "-nowb") { if (arg == "-nowb") {
nowb_mode = true; flag_nowb = true;
continue;
}
if (arg == "-specify") {
specify_mode = true;
continue; continue;
} }
if (arg == "-noopt") { if (arg == "-noopt") {
@ -415,6 +421,8 @@ struct VerilogFrontend : public Frontend {
} }
extra_args(f, filename, args, argidx); extra_args(f, filename, args, argidx);
log_header(design, "Executing Verilog-2005 frontend: %s\n", filename.c_str());
log("Parsing %s%s input from `%s' to AST representation.\n", log("Parsing %s%s input from `%s' to AST representation.\n",
formal_mode ? "formal " : "", sv_mode ? "SystemVerilog" : "Verilog", filename.c_str()); formal_mode ? "formal " : "", sv_mode ? "SystemVerilog" : "Verilog", filename.c_str());
@ -450,7 +458,7 @@ struct VerilogFrontend : public Frontend {
error_on_dpi_function(current_ast); error_on_dpi_function(current_ast);
AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches,
flag_nomeminit, flag_nomem2reg, flag_mem2reg, noblackbox_mode, lib_mode, nowb_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire); flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_noblackbox, lib_mode, flag_nowb, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
if (!flag_nopp) if (!flag_nopp)
delete lexin; delete lexin;

View File

@ -69,14 +69,11 @@ namespace VERILOG_FRONTEND
// running in -assert-assumes mode // running in -assert-assumes mode
extern bool assert_assumes_mode; extern bool assert_assumes_mode;
// running in -noblackbox mode
extern bool noblackbox_mode;
// running in -lib mode // running in -lib mode
extern bool lib_mode; extern bool lib_mode;
// running in -nowb mode // running in -specify mode
extern bool nowb_mode; extern bool specify_mode;
// lexer input stream // lexer input stream
extern std::istream *lexin; extern std::istream *lexin;

View File

@ -148,7 +148,7 @@ YOSYS_NAMESPACE_END
"endfunction" { return TOK_ENDFUNCTION; } "endfunction" { return TOK_ENDFUNCTION; }
"task" { return TOK_TASK; } "task" { return TOK_TASK; }
"endtask" { return TOK_ENDTASK; } "endtask" { return TOK_ENDTASK; }
"specify" { return TOK_SPECIFY; } "specify" { return specify_mode ? TOK_SPECIFY : TOK_IGNORED_SPECIFY; }
"endspecify" { return TOK_ENDSPECIFY; } "endspecify" { return TOK_ENDSPECIFY; }
"specparam" { return TOK_SPECPARAM; } "specparam" { return TOK_SPECPARAM; }
"package" { SV_KEYWORD(TOK_PACKAGE); } "package" { SV_KEYWORD(TOK_PACKAGE); }
@ -206,7 +206,9 @@ YOSYS_NAMESPACE_END
"const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); } "const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); }
"checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); } "checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); }
"endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); } "endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); }
"final" { SV_KEYWORD(TOK_FINAL); }
"logic" { SV_KEYWORD(TOK_LOGIC); } "logic" { SV_KEYWORD(TOK_LOGIC); }
"var" { SV_KEYWORD(TOK_VAR); }
"bit" { SV_KEYWORD(TOK_REG); } "bit" { SV_KEYWORD(TOK_REG); }
"eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); } "eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
@ -216,6 +218,8 @@ YOSYS_NAMESPACE_END
"output" { return TOK_OUTPUT; } "output" { return TOK_OUTPUT; }
"inout" { return TOK_INOUT; } "inout" { return TOK_INOUT; }
"wire" { return TOK_WIRE; } "wire" { return TOK_WIRE; }
"wor" { return TOK_WOR; }
"wand" { return TOK_WAND; }
"reg" { return TOK_REG; } "reg" { return TOK_REG; }
"integer" { return TOK_INTEGER; } "integer" { return TOK_INTEGER; }
"signed" { return TOK_SIGNED; } "signed" { return TOK_SIGNED; }
@ -230,7 +234,7 @@ YOSYS_NAMESPACE_END
return TOK_CONSTVAL; return TOK_CONSTVAL;
} }
[0-9]*[ \t]*\'s?[bodhBODH][ \t\r\n]*[0-9a-fA-FzxZX?_]+ { [0-9]*[ \t]*\'s?[bodhBODH]*[ \t\r\n]*[0-9a-fA-FzxZX?_]+ {
frontend_verilog_yylval.string = new std::string(yytext); frontend_verilog_yylval.string = new std::string(yytext);
return TOK_CONSTVAL; return TOK_CONSTVAL;
} }
@ -301,6 +305,17 @@ supply1 { return TOK_SUPPLY1; }
return TOK_ID; return TOK_ID;
} }
"$"(setup|hold|setuphold|removal|recovery|recrem|skew|timeskew|fullskew|nochange) {
if (!specify_mode) REJECT;
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_ID;
}
"$"(info|warning|error|fatal) {
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_ELAB_TASK;
}
"$signed" { return TOK_TO_SIGNED; } "$signed" { return TOK_TO_SIGNED; }
"$unsigned" { return TOK_TO_UNSIGNED; } "$unsigned" { return TOK_TO_UNSIGNED; }
@ -411,6 +426,17 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
"+:" { return TOK_POS_INDEXED; } "+:" { return TOK_POS_INDEXED; }
"-:" { return TOK_NEG_INDEXED; } "-:" { return TOK_NEG_INDEXED; }
[-+]?[=*]> {
if (!specify_mode) REJECT;
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_SPECIFY_OPER;
}
"&&&" {
if (!specify_mode) REJECT;
return TOK_SPECIFY_AND;
}
"/*" { BEGIN(COMMENT); } "/*" { BEGIN(COMMENT); }
<COMMENT>. /* ignore comment body */ <COMMENT>. /* ignore comment body */
<COMMENT>\n /* ignore comment body */ <COMMENT>\n /* ignore comment body */

View File

@ -59,7 +59,7 @@ namespace VERILOG_FRONTEND {
std::vector<char> case_type_stack; std::vector<char> case_type_stack;
bool do_not_require_port_stubs; bool do_not_require_port_stubs;
bool default_nettype_wire; bool default_nettype_wire;
bool sv_mode, formal_mode, noblackbox_mode, lib_mode, nowb_mode; bool sv_mode, formal_mode, lib_mode, specify_mode;
bool noassert_mode, noassume_mode, norestrict_mode; bool noassert_mode, noassume_mode, norestrict_mode;
bool assume_asserts_mode, assert_assumes_mode; bool assume_asserts_mode, assert_assumes_mode;
bool current_wire_rand, current_wire_const; bool current_wire_rand, current_wire_const;
@ -94,29 +94,58 @@ static void free_attr(std::map<std::string, AstNode*> *al)
delete al; delete al;
} }
struct specify_target {
char polarity_op;
AstNode *dst, *dat;
};
struct specify_triple {
AstNode *t_min, *t_avg, *t_max;
};
struct specify_rise_fall {
specify_triple rise;
specify_triple fall;
};
%} %}
%name-prefix "frontend_verilog_yy" %define api.prefix {frontend_verilog_yy}
/* The union is defined in the header, so we need to provide all the
* includes it requires
*/
%code requires {
#include <map>
#include <string>
#include "frontends/verilog/verilog_frontend.h"
}
%union { %union {
std::string *string; std::string *string;
struct YOSYS_NAMESPACE_PREFIX AST::AstNode *ast; struct YOSYS_NAMESPACE_PREFIX AST::AstNode *ast;
std::map<std::string, YOSYS_NAMESPACE_PREFIX AST::AstNode*> *al; std::map<std::string, YOSYS_NAMESPACE_PREFIX AST::AstNode*> *al;
struct specify_target *specify_target_ptr;
struct specify_triple *specify_triple_ptr;
struct specify_rise_fall *specify_rise_fall_ptr;
bool boolean; bool boolean;
char ch;
} }
%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE TOK_SVA_LABEL %token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE
%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER %token <string> TOK_SVA_LABEL TOK_SPECIFY_OPER TOK_ELAB_TASK
%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER TOK_FINAL
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END %token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP %token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT %token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR
%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG TOK_LOGIC %token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_WAND TOK_WOR TOK_REG TOK_LOGIC
%token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL %token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL
%token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT %token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT
%token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC %token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC
%token TOK_CASE TOK_CASEX TOK_CASEZ TOK_ENDCASE TOK_DEFAULT %token TOK_CASE TOK_CASEX TOK_CASEZ TOK_ENDCASE TOK_DEFAULT
%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM %token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY
%token TOK_IGNORED_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM TOK_SPECIFY_AND
%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL %token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE %token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED %token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
@ -130,6 +159,12 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%type <boolean> opt_signed opt_property unique_case_attr %type <boolean> opt_signed opt_property unique_case_attr
%type <al> attr case_attr %type <al> attr case_attr
%type <specify_target_ptr> specify_target
%type <specify_triple_ptr> specify_triple
%type <specify_rise_fall_ptr> specify_rise_fall
%type <ast> specify_if specify_condition specify_opt_arg
%type <ch> specify_edge
// operator precedence from low to high // operator precedence from low to high
%left OP_LOR %left OP_LOR
%left OP_LAND %left OP_LAND
@ -450,12 +485,21 @@ wire_type_token_io:
wire_type_token: wire_type_token:
TOK_WIRE { TOK_WIRE {
} | } |
TOK_WOR {
astbuf3->is_wor = true;
} |
TOK_WAND {
astbuf3->is_wand = true;
} |
TOK_REG { TOK_REG {
astbuf3->is_reg = true; astbuf3->is_reg = true;
} | } |
TOK_LOGIC { TOK_LOGIC {
astbuf3->is_logic = true; astbuf3->is_logic = true;
} | } |
TOK_VAR {
astbuf3->is_logic = true;
} |
TOK_INTEGER { TOK_INTEGER {
astbuf3->is_reg = true; astbuf3->is_reg = true;
astbuf3->range_left = 31; astbuf3->range_left = 31;
@ -539,7 +583,7 @@ module_body:
module_body_stmt: module_body_stmt:
task_func_decl | specify_block |param_decl | localparam_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt | task_func_decl | specify_block |param_decl | localparam_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt |
always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl; always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block;
checker_decl: checker_decl:
TOK_CHECKER TOK_ID ';' { TOK_CHECKER TOK_ID ';' {
@ -697,15 +741,254 @@ task_func_body:
task_func_body behavioral_stmt | task_func_body behavioral_stmt |
/* empty */; /* empty */;
specify_block: /*************************** specify parser ***************************/
TOK_SPECIFY specify_item_opt TOK_ENDSPECIFY |
TOK_SPECIFY TOK_ENDSPECIFY ;
specify_item_opt: specify_block:
specify_item_opt specify_item | TOK_SPECIFY specify_item_list TOK_ENDSPECIFY;
specify_item ;
specify_item_list:
specify_item specify_item_list |
/* empty */;
specify_item: specify_item:
specify_if '(' specify_edge expr TOK_SPECIFY_OPER specify_target ')' '=' specify_rise_fall ';' {
AstNode *en_expr = $1;
char specify_edge = $3;
AstNode *src_expr = $4;
string *oper = $5;
specify_target *target = $6;
specify_rise_fall *timing = $9;
if (specify_edge != 0 && target->dat == nullptr)
frontend_verilog_yyerror("Found specify edge but no data spec.\n");
AstNode *cell = new AstNode(AST_CELL);
ast_stack.back()->children.push_back(cell);
cell->str = stringf("$specify$%d", autoidx++);
cell->children.push_back(new AstNode(AST_CELLTYPE));
cell->children.back()->str = target->dat ? "$specify3" : "$specify2";
char oper_polarity = 0;
char oper_type = oper->at(0);
if (oper->size() == 3) {
oper_polarity = oper->at(0);
oper_type = oper->at(1);
}
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_type == '*', false, 1)));
cell->children.back()->str = "\\FULL";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity != 0, false, 1)));
cell->children.back()->str = "\\SRC_DST_PEN";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity == '+', false, 1)));
cell->children.back()->str = "\\SRC_DST_POL";
cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_min));
cell->children.back()->str = "\\T_RISE_MIN";
cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_avg));
cell->children.back()->str = "\\T_RISE_TYP";
cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_max));
cell->children.back()->str = "\\T_RISE_MAX";
cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_min));
cell->children.back()->str = "\\T_FALL_MIN";
cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_avg));
cell->children.back()->str = "\\T_FALL_TYP";
cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_max));
cell->children.back()->str = "\\T_FALL_MAX";
cell->children.push_back(new AstNode(AST_ARGUMENT, en_expr ? en_expr : AstNode::mkconst_int(1, false, 1)));
cell->children.back()->str = "\\EN";
cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr));
cell->children.back()->str = "\\SRC";
cell->children.push_back(new AstNode(AST_ARGUMENT, target->dst));
cell->children.back()->str = "\\DST";
if (target->dat)
{
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge != 0, false, 1)));
cell->children.back()->str = "\\EDGE_EN";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge == 'p', false, 1)));
cell->children.back()->str = "\\EDGE_POL";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op != 0, false, 1)));
cell->children.back()->str = "\\DAT_DST_PEN";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op == '+', false, 1)));
cell->children.back()->str = "\\DAT_DST_POL";
cell->children.push_back(new AstNode(AST_ARGUMENT, target->dat));
cell->children.back()->str = "\\DAT";
}
delete oper;
delete target;
delete timing;
} |
TOK_ID '(' specify_edge expr specify_condition ',' specify_edge expr specify_condition ',' expr specify_opt_arg ')' ';' {
if (*$1 != "$setup" && *$1 != "$hold" && *$1 != "$setuphold" && *$1 != "$removal" && *$1 != "$recovery" &&
*$1 != "$recrem" && *$1 != "$skew" && *$1 != "$timeskew" && *$1 != "$fullskew" && *$1 != "$nochange")
frontend_verilog_yyerror("Unsupported specify rule type: %s\n", $1->c_str());
AstNode *src_pen = AstNode::mkconst_int($3 != 0, false, 1);
AstNode *src_pol = AstNode::mkconst_int($3 == 'p', false, 1);
AstNode *src_expr = $4, *src_en = $5 ? $5 : AstNode::mkconst_int(1, false, 1);
AstNode *dst_pen = AstNode::mkconst_int($7 != 0, false, 1);
AstNode *dst_pol = AstNode::mkconst_int($7 == 'p', false, 1);
AstNode *dst_expr = $8, *dst_en = $9 ? $9 : AstNode::mkconst_int(1, false, 1);
AstNode *limit = $11;
AstNode *limit2 = $12;
AstNode *cell = new AstNode(AST_CELL);
ast_stack.back()->children.push_back(cell);
cell->str = stringf("$specify$%d", autoidx++);
cell->children.push_back(new AstNode(AST_CELLTYPE));
cell->children.back()->str = "$specrule";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_str(*$1)));
cell->children.back()->str = "\\TYPE";
cell->children.push_back(new AstNode(AST_PARASET, limit));
cell->children.back()->str = "\\T_LIMIT";
cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2 : AstNode::mkconst_int(0, true)));
cell->children.back()->str = "\\T_LIMIT2";
cell->children.push_back(new AstNode(AST_PARASET, src_pen));
cell->children.back()->str = "\\SRC_PEN";
cell->children.push_back(new AstNode(AST_PARASET, src_pol));
cell->children.back()->str = "\\SRC_POL";
cell->children.push_back(new AstNode(AST_PARASET, dst_pen));
cell->children.back()->str = "\\DST_PEN";
cell->children.push_back(new AstNode(AST_PARASET, dst_pol));
cell->children.back()->str = "\\DST_POL";
cell->children.push_back(new AstNode(AST_ARGUMENT, src_en));
cell->children.back()->str = "\\SRC_EN";
cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr));
cell->children.back()->str = "\\SRC";
cell->children.push_back(new AstNode(AST_ARGUMENT, dst_en));
cell->children.back()->str = "\\DST_EN";
cell->children.push_back(new AstNode(AST_ARGUMENT, dst_expr));
cell->children.back()->str = "\\DST";
delete $1;
};
specify_opt_arg:
',' expr {
$$ = $2;
} |
/* empty */ {
$$ = nullptr;
};
specify_if:
TOK_IF '(' expr ')' {
$$ = $3;
} |
/* empty */ {
$$ = nullptr;
};
specify_condition:
TOK_SPECIFY_AND expr {
$$ = $2;
} |
/* empty */ {
$$ = nullptr;
};
specify_target:
expr {
$$ = new specify_target;
$$->polarity_op = 0;
$$->dst = $1;
$$->dat = nullptr;
} |
'(' expr ':' expr ')'{
$$ = new specify_target;
$$->polarity_op = 0;
$$->dst = $2;
$$->dat = $4;
} |
'(' expr TOK_NEG_INDEXED expr ')'{
$$ = new specify_target;
$$->polarity_op = '-';
$$->dst = $2;
$$->dat = $4;
} |
'(' expr TOK_POS_INDEXED expr ')'{
$$ = new specify_target;
$$->polarity_op = '+';
$$->dst = $2;
$$->dat = $4;
};
specify_edge:
TOK_POSEDGE { $$ = 'p'; } |
TOK_NEGEDGE { $$ = 'n'; } |
{ $$ = 0; };
specify_rise_fall:
specify_triple {
$$ = new specify_rise_fall;
$$->rise = *$1;
$$->fall.t_min = $1->t_min->clone();
$$->fall.t_avg = $1->t_avg->clone();
$$->fall.t_max = $1->t_max->clone();
delete $1;
} |
'(' specify_triple ',' specify_triple ')' {
$$ = new specify_rise_fall;
$$->rise = *$2;
$$->fall = *$4;
delete $2;
delete $4;
};
specify_triple:
expr {
$$ = new specify_triple;
$$->t_min = $1;
$$->t_avg = $1->clone();
$$->t_max = $1->clone();
} |
expr ':' expr ':' expr {
$$ = new specify_triple;
$$->t_min = $1;
$$->t_avg = $3;
$$->t_max = $5;
};
/******************** ignored specify parser **************************/
ignored_specify_block:
TOK_IGNORED_SPECIFY ignored_specify_item_opt TOK_ENDSPECIFY |
TOK_IGNORED_SPECIFY TOK_ENDSPECIFY ;
ignored_specify_item_opt:
ignored_specify_item_opt ignored_specify_item |
ignored_specify_item ;
ignored_specify_item:
specparam_declaration specparam_declaration
// | pulsestyle_declaration // | pulsestyle_declaration
// | showcancelled_declaration // | showcancelled_declaration
@ -721,13 +1004,13 @@ specparam_declaration:
// and the 'non_opt_range' rule allows index ranges not allowed by 1364-2005 // and the 'non_opt_range' rule allows index ranges not allowed by 1364-2005
// exxxxtending this for SV specparam would change this anyhow // exxxxtending this for SV specparam would change this anyhow
specparam_range: specparam_range:
'[' constant_expression ':' constant_expression ']' ; '[' ignspec_constant_expression ':' ignspec_constant_expression ']' ;
list_of_specparam_assignments: list_of_specparam_assignments:
specparam_assignment | list_of_specparam_assignments ',' specparam_assignment; specparam_assignment | list_of_specparam_assignments ',' specparam_assignment;
specparam_assignment: specparam_assignment:
TOK_ID '=' constant_mintypmax_expression ; ignspec_id '=' constant_mintypmax_expression ;
/* /*
pulsestyle_declaration : pulsestyle_declaration :
@ -802,19 +1085,19 @@ opt_polarity_operator :
// Good enough for the time being // Good enough for the time being
specify_input_terminal_descriptor : specify_input_terminal_descriptor :
TOK_ID ; ignspec_id ;
// Good enough for the time being // Good enough for the time being
specify_output_terminal_descriptor : specify_output_terminal_descriptor :
TOK_ID ; ignspec_id ;
system_timing_declaration : system_timing_declaration :
TOK_ID '(' system_timing_args ')' ';' ; ignspec_id '(' system_timing_args ')' ';' ;
system_timing_arg : system_timing_arg :
TOK_POSEDGE TOK_ID | TOK_POSEDGE ignspec_id |
TOK_NEGEDGE TOK_ID | TOK_NEGEDGE ignspec_id |
expr ; ignspec_expr ;
system_timing_args : system_timing_args :
system_timing_arg | system_timing_arg |
@ -871,19 +1154,27 @@ tzx_path_delay_expression :
*/ */
path_delay_expression : path_delay_expression :
constant_expression; ignspec_constant_expression;
constant_mintypmax_expression : constant_mintypmax_expression :
constant_expression ignspec_constant_expression
| constant_expression ':' constant_expression ':' constant_expression | ignspec_constant_expression ':' ignspec_constant_expression ':' ignspec_constant_expression
; ;
// for the time being this is OK, but we may write our own expr here. // for the time being this is OK, but we may write our own expr here.
// as I'm not sure it is legal to use a full expr here (probably not) // as I'm not sure it is legal to use a full expr here (probably not)
// On the other hand, other rules requiring constant expressions also use 'expr' // On the other hand, other rules requiring constant expressions also use 'expr'
// (such as param assignment), so we may leave this as-is, perhaps adding runtime checks for constant-ness // (such as param assignment), so we may leave this as-is, perhaps adding runtime checks for constant-ness
constant_expression: ignspec_constant_expression:
expr ; expr { delete $1; };
ignspec_expr:
expr { delete $1; };
ignspec_id:
TOK_ID { delete $1; };
/**********************************************************************/
param_signed: param_signed:
TOK_SIGNED { TOK_SIGNED {
@ -917,7 +1208,7 @@ param_range:
}; };
param_decl: param_decl:
TOK_PARAMETER { attr TOK_PARAMETER {
astbuf1 = new AstNode(AST_PARAMETER); astbuf1 = new AstNode(AST_PARAMETER);
astbuf1->children.push_back(AstNode::mkconst_int(0, true)); astbuf1->children.push_back(AstNode::mkconst_int(0, true));
} param_signed param_integer param_real param_range param_decl_list ';' { } param_signed param_integer param_real param_range param_decl_list ';' {
@ -925,7 +1216,7 @@ param_decl:
}; };
localparam_decl: localparam_decl:
TOK_LOCALPARAM { attr TOK_LOCALPARAM {
astbuf1 = new AstNode(AST_LOCALPARAM); astbuf1 = new AstNode(AST_LOCALPARAM);
astbuf1->children.push_back(AstNode::mkconst_int(0, true)); astbuf1->children.push_back(AstNode::mkconst_int(0, true));
} param_signed param_integer param_real param_range param_decl_list ';' { } param_signed param_integer param_real param_range param_decl_list ';' {
@ -1241,27 +1532,40 @@ cell_port_list_rules:
cell_port | cell_port_list_rules ',' cell_port; cell_port | cell_port_list_rules ',' cell_port;
cell_port: cell_port:
/* empty */ { attr {
AstNode *node = new AstNode(AST_ARGUMENT); AstNode *node = new AstNode(AST_ARGUMENT);
astbuf2->children.push_back(node); astbuf2->children.push_back(node);
free_attr($1);
} | } |
expr { attr expr {
AstNode *node = new AstNode(AST_ARGUMENT); AstNode *node = new AstNode(AST_ARGUMENT);
astbuf2->children.push_back(node); astbuf2->children.push_back(node);
node->children.push_back($1); node->children.push_back($2);
free_attr($1);
} | } |
'.' TOK_ID '(' expr ')' { attr '.' TOK_ID '(' expr ')' {
AstNode *node = new AstNode(AST_ARGUMENT); AstNode *node = new AstNode(AST_ARGUMENT);
node->str = *$2; node->str = *$3;
astbuf2->children.push_back(node); astbuf2->children.push_back(node);
node->children.push_back($4); node->children.push_back($5);
delete $2; delete $3;
free_attr($1);
} | } |
'.' TOK_ID '(' ')' { attr '.' TOK_ID '(' ')' {
AstNode *node = new AstNode(AST_ARGUMENT); AstNode *node = new AstNode(AST_ARGUMENT);
node->str = *$2; node->str = *$3;
astbuf2->children.push_back(node); astbuf2->children.push_back(node);
delete $2; delete $3;
free_attr($1);
} |
attr '.' TOK_ID {
AstNode *node = new AstNode(AST_ARGUMENT);
node->str = *$3;
astbuf2->children.push_back(node);
node->children.push_back(new AstNode(AST_IDENTIFIER));
node->children.back()->str = *$3;
delete $3;
free_attr($1);
}; };
always_stmt: always_stmt:
@ -1341,6 +1645,9 @@ opt_property:
TOK_PROPERTY { TOK_PROPERTY {
$$ = true; $$ = true;
} | } |
TOK_FINAL {
$$ = false;
} |
/* empty */ { /* empty */ {
$$ = false; $$ = false;
}; };
@ -1869,6 +2176,15 @@ gen_stmt:
if ($6 != NULL) if ($6 != NULL)
delete $6; delete $6;
ast_stack.pop_back(); ast_stack.pop_back();
} |
TOK_ELAB_TASK {
AstNode *node = new AstNode(AST_TECALL);
node->str = *$1;
delete $1;
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
} opt_arg_list ';'{
ast_stack.pop_back();
}; };
gen_stmt_block: gen_stmt_block:
@ -2139,4 +2455,3 @@ concat_list:
$$ = $3; $$ = $3;
$$->children.push_back($1); $$->children.push_back($1);
}; };

View File

@ -453,7 +453,7 @@ Aig::Aig(Cell *cell)
int B = mk.inport("\\B"); int B = mk.inport("\\B");
int C = mk.inport("\\C"); int C = mk.inport("\\C");
int D = mk.inport("\\D"); int D = mk.inport("\\D");
int Y = mk.nand_gate(mk.nor_gate(A, B), mk.nor_gate(C, D)); int Y = mk.nand_gate(mk.or_gate(A, B), mk.or_gate(C, D));
mk.outport(Y, "\\Y"); mk.outport(Y, "\\Y");
goto optimize; goto optimize;
} }

View File

@ -85,6 +85,8 @@ struct CellTypes
setup_internals_eval(); setup_internals_eval();
IdString A = "\\A", B = "\\B", EN = "\\EN", Y = "\\Y"; IdString A = "\\A", B = "\\B", EN = "\\EN", Y = "\\Y";
IdString SRC = "\\SRC", DST = "\\DST", DAT = "\\DAT";
IdString EN_SRC = "\\EN_SRC", EN_DST = "\\EN_DST";
setup_type("$tribuf", {A, EN}, {Y}, true); setup_type("$tribuf", {A, EN}, {Y}, true);
@ -99,6 +101,9 @@ struct CellTypes
setup_type("$allconst", pool<RTLIL::IdString>(), {Y}, true); setup_type("$allconst", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$allseq", pool<RTLIL::IdString>(), {Y}, true); setup_type("$allseq", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$equiv", {A, B}, {Y}, true); setup_type("$equiv", {A, B}, {Y}, true);
setup_type("$specify2", {EN, SRC, DST}, pool<RTLIL::IdString>(), true);
setup_type("$specify3", {EN, SRC, DST, DAT}, pool<RTLIL::IdString>(), true);
setup_type("$specrule", {EN_SRC, EN_DST, SRC, DST}, pool<RTLIL::IdString>(), true);
} }
void setup_internals_eval() void setup_internals_eval()
@ -464,7 +469,7 @@ struct CellTypes
if (cell->type == "$_AOI4_") if (cell->type == "$_AOI4_")
return eval_not(const_or(const_and(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1)); return eval_not(const_or(const_and(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1));
if (cell->type == "$_OAI4_") if (cell->type == "$_OAI4_")
return eval_not(const_and(const_or(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1)); return eval_not(const_and(const_or(arg1, arg2, false, false, 1), const_or(arg3, arg4, false, false, 1), false, false, 1));
log_assert(arg4.bits.size() == 0); log_assert(arg4.bits.size() == 0);
return eval(cell, arg1, arg2, arg3, errp); return eval(cell, arg1, arg2, arg3, errp);

View File

@ -529,13 +529,13 @@ int main(int argc, char **argv)
log_error("Can't open dependencies file for writing: %s\n", strerror(errno)); log_error("Can't open dependencies file for writing: %s\n", strerror(errno));
bool first = true; bool first = true;
for (auto fn : yosys_output_files) { for (auto fn : yosys_output_files) {
fprintf(f, "%s%s", first ? "" : " ", fn.c_str()); fprintf(f, "%s%s", first ? "" : " ", escape_filename_spaces(fn).c_str());
first = false; first = false;
} }
fprintf(f, ":"); fprintf(f, ":");
for (auto fn : yosys_input_files) { for (auto fn : yosys_input_files) {
if (yosys_output_files.count(fn) == 0) if (yosys_output_files.count(fn) == 0)
fprintf(f, " %s", fn.c_str()); fprintf(f, " %s", escape_filename_spaces(fn).c_str());
} }
fprintf(f, "\n"); fprintf(f, "\n");
} }

View File

@ -230,6 +230,9 @@ static void logv_warning_with_prefix(const char *prefix,
} }
else else
{ {
int bak_log_make_debug = log_make_debug;
log_make_debug = 0;
for (auto &re : log_werror_regexes) for (auto &re : log_werror_regexes)
if (std::regex_search(message, re)) if (std::regex_search(message, re))
log_error("%s", message.c_str()); log_error("%s", message.c_str());
@ -254,6 +257,7 @@ static void logv_warning_with_prefix(const char *prefix,
} }
log_warnings_count++; log_warnings_count++;
log_make_debug = bak_log_make_debug;
} }
} }
@ -278,6 +282,17 @@ void log_file_warning(const std::string &filename, int lineno,
va_end(ap); va_end(ap);
} }
void log_file_info(const std::string &filename, int lineno,
const char *format, ...)
{
va_list ap;
va_start(ap, format);
std::string fmt = stringf("%s:%d: Info: %s",
filename.c_str(), lineno, format);
logv(fmt.c_str(), ap);
va_end(ap);
}
YS_ATTRIBUTE(noreturn) YS_ATTRIBUTE(noreturn)
static void logv_error_with_prefix(const char *prefix, static void logv_error_with_prefix(const char *prefix,
const char *format, va_list ap) const char *format, va_list ap)
@ -285,6 +300,9 @@ static void logv_error_with_prefix(const char *prefix,
#ifdef EMSCRIPTEN #ifdef EMSCRIPTEN
auto backup_log_files = log_files; auto backup_log_files = log_files;
#endif #endif
int bak_log_make_debug = log_make_debug;
log_make_debug = 0;
log_suppressed();
if (log_errfile != NULL) if (log_errfile != NULL)
log_files.push_back(log_errfile); log_files.push_back(log_errfile);
@ -298,6 +316,8 @@ static void logv_error_with_prefix(const char *prefix,
log("%s%s", prefix, log_last_error.c_str()); log("%s%s", prefix, log_last_error.c_str());
log_flush(); log_flush();
log_make_debug = bak_log_make_debug;
if (log_error_atexit) if (log_error_atexit)
log_error_atexit(); log_error_atexit();

View File

@ -80,6 +80,7 @@ void log_warning(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
// Log with filename to report a problem in a source file. // Log with filename to report a problem in a source file.
void log_file_warning(const std::string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4)); void log_file_warning(const std::string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4));
void log_file_info(const std::string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4));
void log_warning_noprefix(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); void log_warning_noprefix(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
YS_NORETURN void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn); YS_NORETURN void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn);

View File

@ -218,15 +218,19 @@ void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id, bool value)
{ {
if (value) if (value)
attributes[id] = RTLIL::Const(1); attributes[id] = RTLIL::Const(1);
else if (attributes.count(id)) else {
attributes.erase(id); const auto it = attributes.find(id);
if (it != attributes.end())
attributes.erase(it);
}
} }
bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const
{ {
if (attributes.count(id) == 0) const auto it = attributes.find(id);
if (it == attributes.end())
return false; return false;
return attributes.at(id).as_bool(); return it->second.as_bool();
} }
void RTLIL::AttrObject::set_strpool_attribute(RTLIL::IdString id, const pool<string> &data) void RTLIL::AttrObject::set_strpool_attribute(RTLIL::IdString id, const pool<string> &data)
@ -1194,6 +1198,46 @@ namespace {
return; return;
} }
if (cell->type.in("$specify2", "$specify3")) {
param_bool("\\FULL");
param_bool("\\SRC_DST_PEN");
param_bool("\\SRC_DST_POL");
param("\\T_RISE_MIN");
param("\\T_RISE_TYP");
param("\\T_RISE_MAX");
param("\\T_FALL_MIN");
param("\\T_FALL_TYP");
param("\\T_FALL_MAX");
port("\\EN", 1);
port("\\SRC", param("\\SRC_WIDTH"));
port("\\DST", param("\\DST_WIDTH"));
if (cell->type == "$specify3") {
param_bool("\\EDGE_EN");
param_bool("\\EDGE_POL");
param_bool("\\DAT_DST_PEN");
param_bool("\\DAT_DST_POL");
port("\\DAT", param("\\DST_WIDTH"));
}
check_expected();
return;
}
if (cell->type == "$specrule") {
param("\\TYPE");
param_bool("\\SRC_PEN");
param_bool("\\SRC_POL");
param_bool("\\DST_PEN");
param_bool("\\DST_POL");
param("\\T_LIMIT");
param("\\T_LIMIT2");
port("\\SRC_EN", 1);
port("\\DST_EN", 1);
port("\\SRC", param("\\SRC_WIDTH"));
port("\\DST", param("\\DST_WIDTH"));
check_expected();
return;
}
if (cell->type == "$_BUF_") { check_gate("AY"); return; } if (cell->type == "$_BUF_") { check_gate("AY"); return; }
if (cell->type == "$_NOT_") { check_gate("AY"); return; } if (cell->type == "$_NOT_") { check_gate("AY"); return; }
if (cell->type == "$_AND_") { check_gate("ABY"); return; } if (cell->type == "$_AND_") { check_gate("ABY"); return; }
@ -1470,7 +1514,10 @@ void RTLIL::Module::add(RTLIL::Cell *cell)
cell->module = this; cell->module = this;
} }
namespace { void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires)
{
log_assert(refcount_wires_ == 0);
struct DeleteWireWorker struct DeleteWireWorker
{ {
RTLIL::Module *module; RTLIL::Module *module;
@ -1485,17 +1532,29 @@ namespace {
} }
sig = chunks; sig = chunks;
} }
};
}
void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires) void operator()(RTLIL::SigSpec &lhs, RTLIL::SigSpec &rhs) {
{ log_assert(GetSize(lhs) == GetSize(rhs));
log_assert(refcount_wires_ == 0); RTLIL::SigSpec new_lhs, new_rhs;
for (int i = 0; i < GetSize(lhs); i++) {
RTLIL::SigBit lhs_bit = lhs[i];
if (lhs_bit.wire != nullptr && wires_p->count(lhs_bit.wire))
continue;
RTLIL::SigBit rhs_bit = rhs[i];
if (rhs_bit.wire != nullptr && wires_p->count(rhs_bit.wire))
continue;
new_lhs.append(lhs_bit);
new_rhs.append(rhs_bit);
}
lhs = new_lhs;
rhs = new_rhs;
}
};
DeleteWireWorker delete_wire_worker; DeleteWireWorker delete_wire_worker;
delete_wire_worker.module = this; delete_wire_worker.module = this;
delete_wire_worker.wires_p = &wires; delete_wire_worker.wires_p = &wires;
rewrite_sigspecs(delete_wire_worker); rewrite_sigspecs2(delete_wire_worker);
for (auto &it : wires) { for (auto &it : wires) {
log_assert(wires_.count(it->name) != 0); log_assert(wires_.count(it->name) != 0);
@ -3456,7 +3515,7 @@ bool RTLIL::SigSpec::operator ==(const RTLIL::SigSpec &other) const
pack(); pack();
other.pack(); other.pack();
if (chunks_.size() != chunks_.size()) if (chunks_.size() != other.chunks_.size())
return false; return false;
updhash(); updhash();

View File

@ -50,7 +50,7 @@ namespace RTLIL
CONST_FLAG_NONE = 0, CONST_FLAG_NONE = 0,
CONST_FLAG_STRING = 1, CONST_FLAG_STRING = 1,
CONST_FLAG_SIGNED = 2, // only used for parameters CONST_FLAG_SIGNED = 2, // only used for parameters
CONST_FLAG_REAL = 4 // unused -- to be used for parameters CONST_FLAG_REAL = 4 // only used for parameters
}; };
struct Const; struct Const;
@ -524,6 +524,7 @@ struct RTLIL::Const
Const(const std::vector<RTLIL::State> &bits) : bits(bits) { flags = CONST_FLAG_NONE; } Const(const std::vector<RTLIL::State> &bits) : bits(bits) { flags = CONST_FLAG_NONE; }
Const(const std::vector<bool> &bits); Const(const std::vector<bool> &bits);
Const(const RTLIL::Const &c); Const(const RTLIL::Const &c);
RTLIL::Const &operator =(const RTLIL::Const &other) = default;
bool operator <(const RTLIL::Const &other) const; bool operator <(const RTLIL::Const &other) const;
bool operator ==(const RTLIL::Const &other) const; bool operator ==(const RTLIL::Const &other) const;
@ -603,8 +604,10 @@ struct RTLIL::SigChunk
SigChunk(RTLIL::State bit, int width = 1); SigChunk(RTLIL::State bit, int width = 1);
SigChunk(RTLIL::SigBit bit); SigChunk(RTLIL::SigBit bit);
SigChunk(const RTLIL::SigChunk &sigchunk); SigChunk(const RTLIL::SigChunk &sigchunk);
RTLIL::SigChunk &operator =(const RTLIL::SigChunk &other) = default;
RTLIL::SigChunk extract(int offset, int length) const; RTLIL::SigChunk extract(int offset, int length) const;
inline int size() const { return width; }
bool operator <(const RTLIL::SigChunk &other) const; bool operator <(const RTLIL::SigChunk &other) const;
bool operator ==(const RTLIL::SigChunk &other) const; bool operator ==(const RTLIL::SigChunk &other) const;
@ -628,6 +631,7 @@ struct RTLIL::SigBit
SigBit(const RTLIL::SigChunk &chunk, int index); SigBit(const RTLIL::SigChunk &chunk, int index);
SigBit(const RTLIL::SigSpec &sig); SigBit(const RTLIL::SigSpec &sig);
SigBit(const RTLIL::SigBit &sigbit); SigBit(const RTLIL::SigBit &sigbit);
RTLIL::SigBit &operator =(const RTLIL::SigBit &other) = default;
bool operator <(const RTLIL::SigBit &other) const; bool operator <(const RTLIL::SigBit &other) const;
bool operator ==(const RTLIL::SigBit &other) const; bool operator ==(const RTLIL::SigBit &other) const;
@ -1004,6 +1008,7 @@ public:
void fixup_ports(); void fixup_ports();
template<typename T> void rewrite_sigspecs(T &functor); template<typename T> void rewrite_sigspecs(T &functor);
template<typename T> void rewrite_sigspecs2(T &functor);
void cloneInto(RTLIL::Module *new_mod) const; void cloneInto(RTLIL::Module *new_mod) const;
virtual RTLIL::Module *clone() const; virtual RTLIL::Module *clone() const;
@ -1309,6 +1314,7 @@ public:
} }
template<typename T> void rewrite_sigspecs(T &functor); template<typename T> void rewrite_sigspecs(T &functor);
template<typename T> void rewrite_sigspecs2(T &functor);
#ifdef WITH_PYTHON #ifdef WITH_PYTHON
static std::map<unsigned int, RTLIL::Cell*> *get_all_cells(void); static std::map<unsigned int, RTLIL::Cell*> *get_all_cells(void);
@ -1327,6 +1333,7 @@ struct RTLIL::CaseRule
bool empty() const; bool empty() const;
template<typename T> void rewrite_sigspecs(T &functor); template<typename T> void rewrite_sigspecs(T &functor);
template<typename T> void rewrite_sigspecs2(T &functor);
RTLIL::CaseRule *clone() const; RTLIL::CaseRule *clone() const;
}; };
@ -1340,6 +1347,7 @@ struct RTLIL::SwitchRule : public RTLIL::AttrObject
bool empty() const; bool empty() const;
template<typename T> void rewrite_sigspecs(T &functor); template<typename T> void rewrite_sigspecs(T &functor);
template<typename T> void rewrite_sigspecs2(T &functor);
RTLIL::SwitchRule *clone() const; RTLIL::SwitchRule *clone() const;
}; };
@ -1350,6 +1358,7 @@ struct RTLIL::SyncRule
std::vector<RTLIL::SigSig> actions; std::vector<RTLIL::SigSig> actions;
template<typename T> void rewrite_sigspecs(T &functor); template<typename T> void rewrite_sigspecs(T &functor);
template<typename T> void rewrite_sigspecs2(T &functor);
RTLIL::SyncRule *clone() const; RTLIL::SyncRule *clone() const;
}; };
@ -1362,6 +1371,7 @@ struct RTLIL::Process : public RTLIL::AttrObject
~Process(); ~Process();
template<typename T> void rewrite_sigspecs(T &functor); template<typename T> void rewrite_sigspecs(T &functor);
template<typename T> void rewrite_sigspecs2(T &functor);
RTLIL::Process *clone() const; RTLIL::Process *clone() const;
}; };
@ -1423,12 +1433,30 @@ void RTLIL::Module::rewrite_sigspecs(T &functor)
} }
} }
template<typename T>
void RTLIL::Module::rewrite_sigspecs2(T &functor)
{
for (auto &it : cells_)
it.second->rewrite_sigspecs2(functor);
for (auto &it : processes)
it.second->rewrite_sigspecs2(functor);
for (auto &it : connections_) {
functor(it.first, it.second);
}
}
template<typename T> template<typename T>
void RTLIL::Cell::rewrite_sigspecs(T &functor) { void RTLIL::Cell::rewrite_sigspecs(T &functor) {
for (auto &it : connections_) for (auto &it : connections_)
functor(it.second); functor(it.second);
} }
template<typename T>
void RTLIL::Cell::rewrite_sigspecs2(T &functor) {
for (auto &it : connections_)
functor(it.second);
}
template<typename T> template<typename T>
void RTLIL::CaseRule::rewrite_sigspecs(T &functor) { void RTLIL::CaseRule::rewrite_sigspecs(T &functor) {
for (auto &it : compare) for (auto &it : compare)
@ -1441,6 +1469,17 @@ void RTLIL::CaseRule::rewrite_sigspecs(T &functor) {
it->rewrite_sigspecs(functor); it->rewrite_sigspecs(functor);
} }
template<typename T>
void RTLIL::CaseRule::rewrite_sigspecs2(T &functor) {
for (auto &it : compare)
functor(it);
for (auto &it : actions) {
functor(it.first, it.second);
}
for (auto it : switches)
it->rewrite_sigspecs2(functor);
}
template<typename T> template<typename T>
void RTLIL::SwitchRule::rewrite_sigspecs(T &functor) void RTLIL::SwitchRule::rewrite_sigspecs(T &functor)
{ {
@ -1449,6 +1488,14 @@ void RTLIL::SwitchRule::rewrite_sigspecs(T &functor)
it->rewrite_sigspecs(functor); it->rewrite_sigspecs(functor);
} }
template<typename T>
void RTLIL::SwitchRule::rewrite_sigspecs2(T &functor)
{
functor(signal);
for (auto it : cases)
it->rewrite_sigspecs2(functor);
}
template<typename T> template<typename T>
void RTLIL::SyncRule::rewrite_sigspecs(T &functor) void RTLIL::SyncRule::rewrite_sigspecs(T &functor)
{ {
@ -1459,6 +1506,15 @@ void RTLIL::SyncRule::rewrite_sigspecs(T &functor)
} }
} }
template<typename T>
void RTLIL::SyncRule::rewrite_sigspecs2(T &functor)
{
functor(signal);
for (auto &it : actions) {
functor(it.first, it.second);
}
}
template<typename T> template<typename T>
void RTLIL::Process::rewrite_sigspecs(T &functor) void RTLIL::Process::rewrite_sigspecs(T &functor)
{ {
@ -1467,6 +1523,14 @@ void RTLIL::Process::rewrite_sigspecs(T &functor)
it->rewrite_sigspecs(functor); it->rewrite_sigspecs(functor);
} }
template<typename T>
void RTLIL::Process::rewrite_sigspecs2(T &functor)
{
root_case.rewrite_sigspecs2(functor);
for (auto it : syncs)
it->rewrite_sigspecs2(functor);
}
YOSYS_NAMESPACE_END YOSYS_NAMESPACE_END
#endif #endif

View File

@ -151,14 +151,16 @@ void yosys_banner()
int ceil_log2(int x) int ceil_log2(int x)
{ {
#if defined(__GNUC__)
return x > 1 ? (8*sizeof(int)) - __builtin_clz(x-1) : 0;
#else
if (x <= 0) if (x <= 0)
return 0; return 0;
for (int i = 0; i < 32; i++) for (int i = 0; i < 32; i++)
if (((x-1) >> i) == 0) if (((x-1) >> i) == 0)
return i; return i;
log_abort(); log_abort();
#endif
} }
std::string stringf(const char *fmt, ...) std::string stringf(const char *fmt, ...)
@ -482,6 +484,20 @@ void remove_directory(std::string dirname)
#endif #endif
} }
std::string escape_filename_spaces(const std::string& filename)
{
std::string out;
out.reserve(filename.size());
for (auto c : filename)
{
if (c == ' ')
out += "\\ ";
else
out.push_back(c);
}
return out;
}
int GetSize(RTLIL::Wire *wire) int GetSize(RTLIL::Wire *wire)
{ {
return wire->width; return wire->width;

View File

@ -244,7 +244,7 @@ extern bool memhasher_active;
inline void memhasher() { if (memhasher_active) memhasher_do(); } inline void memhasher() { if (memhasher_active) memhasher_do(); }
void yosys_banner(); void yosys_banner();
int ceil_log2(int x); int ceil_log2(int x) YS_ATTRIBUTE(const);
std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2)); std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2));
std::string vstringf(const char *fmt, va_list ap); std::string vstringf(const char *fmt, va_list ap);
int readsome(std::istream &f, char *s, int n); int readsome(std::istream &f, char *s, int n);
@ -257,6 +257,7 @@ std::string make_temp_dir(std::string template_str = "/tmp/yosys_XXXXXX");
bool check_file_exists(std::string filename, bool is_exec = false); bool check_file_exists(std::string filename, bool is_exec = false);
bool is_absolute_path(std::string filename); bool is_absolute_path(std::string filename);
void remove_directory(std::string dirname); void remove_directory(std::string dirname);
std::string escape_filename_spaces(const std::string& filename);
template<typename T> int GetSize(const T &obj) { return obj.size(); } template<typename T> int GetSize(const T &obj) { return obj.size(); }
int GetSize(RTLIL::Wire *wire); int GetSize(RTLIL::Wire *wire);

View File

@ -320,12 +320,10 @@ class SubCircuit::SolverWorker
static int numberOfPermutations(const std::vector<std::string> &list) static int numberOfPermutations(const std::vector<std::string> &list)
{ {
int numPermutations = 1; constexpr size_t mappedPermutationsSize = 10;
for (int i = 0; i < int(list.size()); i++) { constexpr int mappedPermutations[mappedPermutationsSize] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
assert(numPermutations < maxPermutationsLimit); assert(list.size() < mappedPermutationsSize);
numPermutations *= i+1; return mappedPermutations[list.size()];
}
return numPermutations;
} }
static void permutateVectorToMap(std::map<std::string, std::string> &map, const std::vector<std::string> &list, int idx) static void permutateVectorToMap(std::map<std::string, std::string> &map, const std::vector<std::string> &list, int idx)

View File

@ -465,6 +465,10 @@ Add information about {\tt \$assert}, {\tt \$assume}, {\tt \$live}, {\tt \$fair}
{\tt \$initstate}, {\tt \$anyconst}, {\tt \$anyseq}, {\tt \$allconst}, {\tt \$allseq} cells. {\tt \$initstate}, {\tt \$anyconst}, {\tt \$anyseq}, {\tt \$allconst}, {\tt \$allseq} cells.
\end{fixme} \end{fixme}
\begin{fixme}
Add information about {\tt \$specify2}, {\tt \$specify3}, and {\tt \$specrule} cells.
\end{fixme}
\begin{fixme} \begin{fixme}
Add information about {\tt \$slice} and {\tt \$concat} cells. Add information about {\tt \$slice} and {\tt \$concat} cells.
\end{fixme} \end{fixme}

View File

@ -2026,7 +2026,6 @@ def gen_wrappers(filename, debug_level_ = 0):
#include <boost/python/wrapper.hpp> #include <boost/python/wrapper.hpp>
#include <boost/python/call.hpp> #include <boost/python/call.hpp>
#include <boost/python.hpp> #include <boost/python.hpp>
#include <boost/log/exceptions.hpp>
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
@ -2060,7 +2059,6 @@ namespace YOSYS_PYTHON {
Yosys::log_streams.push_back(&std::cout); Yosys::log_streams.push_back(&std::cout);
Yosys::log_error_stderr = true; Yosys::log_error_stderr = true;
Yosys::yosys_setup(); Yosys::yosys_setup();
Yosys::yosys_banner();
} }
} }

View File

@ -281,6 +281,9 @@ struct BugpointPass : public Pass {
} }
extra_args(args, argidx, design); extra_args(args, argidx, design);
if (script.empty())
log_cmd_error("Missing -script option.\n");
if (!has_part) if (!has_part)
{ {
modules = true; modules = true;
@ -298,7 +301,7 @@ struct BugpointPass : public Pass {
if (!check_logfile(grep)) if (!check_logfile(grep))
log_cmd_error("The provided grep string is not found in the log file!\n"); log_cmd_error("The provided grep string is not found in the log file!\n");
int seed = 0, crashing_seed = seed; int seed = 0;
bool found_something = false, stage2 = false; bool found_something = false, stage2 = false;
while (true) while (true)
{ {
@ -324,7 +327,6 @@ struct BugpointPass : public Pass {
if (crashing_design != design) if (crashing_design != design)
delete crashing_design; delete crashing_design;
crashing_design = simplified; crashing_design = simplified;
crashing_seed = seed;
found_something = true; found_something = true;
} }
else else

View File

@ -98,21 +98,23 @@ struct CoverPass : public Pass {
} }
if ((args[argidx] == "-o" || args[argidx] == "-a" || args[argidx] == "-d") && argidx+1 < args.size()) { if ((args[argidx] == "-o" || args[argidx] == "-a" || args[argidx] == "-d") && argidx+1 < args.size()) {
const char *open_mode = args[argidx] == "-a" ? "a+" : "w"; const char *open_mode = args[argidx] == "-a" ? "a+" : "w";
std::string filename = args[++argidx]; const std::string &filename = args[++argidx];
FILE *f = nullptr;
if (args[argidx-1] == "-d") { if (args[argidx-1] == "-d") {
#ifdef _WIN32 #ifdef _WIN32
log_cmd_error("The 'cover -d' option is not supported on win32.\n"); log_cmd_error("The 'cover -d' option is not supported on win32.\n");
#else #else
char filename_buffer[4096]; char filename_buffer[4096];
snprintf(filename_buffer, 4096, "%s/yosys_cover_%d_XXXXXX.txt", filename.c_str(), getpid()); snprintf(filename_buffer, 4096, "%s/yosys_cover_%d_XXXXXX.txt", filename.c_str(), getpid());
filename = mkstemps(filename_buffer, 4); f = fdopen(mkstemps(filename_buffer, 4), "w");
#endif #endif
} else {
f = fopen(filename.c_str(), open_mode);
} }
FILE *f = fopen(filename.c_str(), open_mode);
if (f == NULL) { if (f == NULL) {
for (auto f : out_files) for (auto f : out_files)
fclose(f); fclose(f);
log_cmd_error("Can't create file %s.\n", args[argidx].c_str()); log_cmd_error("Can't create file %s%s.\n", args[argidx-1] == "-d" ? "in directory " : "", args[argidx].c_str());
} }
out_files.push_back(f); out_files.push_back(f);
continue; continue;

View File

@ -291,7 +291,7 @@ struct QwpWorker
// gaussian elimination // gaussian elimination
for (int i = 0; i < N; i++) for (int i = 0; i < N; i++)
{ {
if (config.verbose && ((i+1) % (N/15)) == 0) if (config.verbose && N > 15 && ((i+1) % (N/15)) == 0)
log("> Solved %d%%: %d/%d\n", (100*(i+1))/N, i+1, N); log("> Solved %d%%: %d/%d\n", (100*(i+1))/N, i+1, N);
// find best row // find best row

View File

@ -393,46 +393,114 @@ struct SetundefPass : public Pass {
ffbits.insert(bit); ffbits.insert(bit);
} }
auto process_initwires = [&]()
{
dict<Wire*, int> wire_weights;
for (auto wire : initwires)
{
int weight = 0;
for (auto bit : sigmap(wire))
weight += ffbits.count(bit) ? +1 : -1;
wire_weights[wire] = weight;
}
initwires.sort([&](Wire *a, Wire *b) { return wire_weights.at(a) > wire_weights.at(b); });
for (auto wire : initwires)
{
Const &initval = wire->attributes["\\init"];
initval.bits.resize(GetSize(wire), State::Sx);
for (int i = 0; i < GetSize(wire); i++) {
SigBit bit = sigmap(SigBit(wire, i));
if (initval[i] == State::Sx && ffbits.count(bit)) {
initval[i] = worker.next_bit();
ffbits.erase(bit);
}
}
if (initval.is_fully_undef())
wire->attributes.erase("\\init");
}
initwires.clear();
};
for (int wire_types = 0; wire_types < 2; wire_types++)
{
// prioritize wires that already have an init attribute
if (!ffbits.empty())
{
for (auto wire : module->wires()) for (auto wire : module->wires())
{ {
if (wire->name[0] == (wire_types ? '\\' : '$'))
continue;
if (!wire->attributes.count("\\init")) if (!wire->attributes.count("\\init"))
continue; continue;
for (auto bit : sigmap(wire)) Const &initval = wire->attributes["\\init"];
ffbits.erase(bit); initval.bits.resize(GetSize(wire), State::Sx);
if (initval.is_fully_undef()) {
wire->attributes.erase("\\init");
continue;
}
for (int i = 0; i < GetSize(wire); i++)
if (initval[i] != State::Sx)
ffbits.erase(sigmap(SigBit(wire, i)));
initwires.insert(wire); initwires.insert(wire);
} }
for (int wire_types = 0; wire_types < 2; wire_types++) process_initwires();
}
// next consider wires that completely contain bits to be initialized
if (!ffbits.empty())
{
for (auto wire : module->wires()) for (auto wire : module->wires())
{ {
if (wire->name[0] == (wire_types ? '\\' : '$')) if (wire->name[0] == (wire_types ? '\\' : '$'))
next_wire:
continue; continue;
for (auto bit : sigmap(wire)) for (auto bit : sigmap(wire))
if (!ffbits.count(bit)) if (!ffbits.count(bit))
goto next_wire; goto next_wire;
for (auto bit : sigmap(wire)) initwires.insert(wire);
ffbits.erase(bit);
next_wire:
continue;
}
process_initwires();
}
// finally use whatever wire we can find.
if (!ffbits.empty())
{
for (auto wire : module->wires())
{
if (wire->name[0] == (wire_types ? '\\' : '$'))
continue;
for (auto bit : sigmap(wire))
if (ffbits.count(bit))
initwires.insert(wire); initwires.insert(wire);
} }
for (auto wire : initwires) process_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();
} }
} }
log_assert(ffbits.empty());
}
module->rewrite_sigspecs(worker); module->rewrite_sigspecs(worker);
if (worker.next_bit_mode == MODE_ANYSEQ || worker.next_bit_mode == MODE_ANYCONST) if (worker.next_bit_mode == MODE_ANYSEQ || worker.next_bit_mode == MODE_ANYCONST)

View File

@ -37,7 +37,9 @@ struct statdata_t
STAT_INT_MEMBERS STAT_INT_MEMBERS
#undef X #undef X
double area; double area;
string tech;
std::map<RTLIL::IdString, int> techinfo;
std::map<RTLIL::IdString, int, RTLIL::sort_by_id_str> num_cells_by_type; std::map<RTLIL::IdString, int, RTLIL::sort_by_id_str> num_cells_by_type;
std::set<RTLIL::IdString> unknown_cell_area; std::set<RTLIL::IdString> unknown_cell_area;
@ -70,8 +72,10 @@ struct statdata_t
#undef X #undef X
} }
statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode, const dict<IdString, double> &cell_area) statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode, const dict<IdString, double> &cell_area, string techname)
{ {
tech = techname;
#define X(_name) _name = 0; #define X(_name) _name = 0;
STAT_NUMERIC_MEMBERS STAT_NUMERIC_MEMBERS
#undef X #undef X
@ -153,6 +157,7 @@ struct statdata_t
log(" Number of processes: %6d\n", num_processes); log(" Number of processes: %6d\n", num_processes);
log(" Number of cells: %6d\n", num_cells); log(" Number of cells: %6d\n", num_cells);
for (auto &it : num_cells_by_type) for (auto &it : num_cells_by_type)
if (it.second)
log(" %-26s %6d\n", RTLIL::id2cstr(it.first), it.second); log(" %-26s %6d\n", RTLIL::id2cstr(it.first), it.second);
if (!unknown_cell_area.empty()) { if (!unknown_cell_area.empty()) {
@ -165,6 +170,59 @@ struct statdata_t
log("\n"); log("\n");
log(" Chip area for %smodule '%s': %f\n", (top_mod) ? "top " : "", mod_name.c_str(), area); log(" Chip area for %smodule '%s': %f\n", (top_mod) ? "top " : "", mod_name.c_str(), area);
} }
if (tech == "xilinx")
{
int lut6_cnt = num_cells_by_type["\\LUT6"];
int lut5_cnt = num_cells_by_type["\\LUT5"];
int lut4_cnt = num_cells_by_type["\\LUT4"];
int lut3_cnt = num_cells_by_type["\\LUT3"];
int lut2_cnt = num_cells_by_type["\\LUT2"];
int lut1_cnt = num_cells_by_type["\\LUT1"];
int lc_cnt = 0;
lc_cnt += lut6_cnt;
lc_cnt += lut5_cnt;
if (lut1_cnt) {
int cnt = std::min(lut5_cnt, lut1_cnt);
lut5_cnt -= cnt;
lut1_cnt -= cnt;
}
lc_cnt += lut4_cnt;
if (lut1_cnt) {
int cnt = std::min(lut4_cnt, lut1_cnt);
lut4_cnt -= cnt;
lut1_cnt -= cnt;
}
if (lut2_cnt) {
int cnt = std::min(lut4_cnt, lut2_cnt);
lut4_cnt -= cnt;
lut2_cnt -= cnt;
}
lc_cnt += lut3_cnt;
if (lut1_cnt) {
int cnt = std::min(lut3_cnt, lut1_cnt);
lut3_cnt -= cnt;
lut1_cnt -= cnt;
}
if (lut2_cnt) {
int cnt = std::min(lut3_cnt, lut2_cnt);
lut3_cnt -= cnt;
lut2_cnt -= cnt;
}
if (lut3_cnt) {
int cnt = (lut3_cnt + 1) / 2;
lut3_cnt -= cnt;
}
lc_cnt += (lut2_cnt + lut1_cnt + 1) / 2;
log("\n");
log(" Estimated number of LCs: %10d\n", lc_cnt);
}
} }
}; };
@ -226,6 +284,10 @@ struct StatPass : public Pass {
log(" -liberty <liberty_file>\n"); log(" -liberty <liberty_file>\n");
log(" use cell area information from the provided liberty file\n"); log(" use cell area information from the provided liberty file\n");
log("\n"); log("\n");
log(" -tech <technology>\n");
log(" print area estemate for the specified technology. Corrently supported\n");
log(" calues for <technology>: xilinx\n");
log("\n");
log(" -width\n"); log(" -width\n");
log(" annotate internal cell types with their word width.\n"); log(" annotate internal cell types with their word width.\n");
log(" e.g. $add_8 for an 8 bit wide $add cell.\n"); log(" e.g. $add_8 for an 8 bit wide $add cell.\n");
@ -239,6 +301,7 @@ struct StatPass : public Pass {
RTLIL::Module *top_mod = NULL; RTLIL::Module *top_mod = NULL;
std::map<RTLIL::IdString, statdata_t> mod_stat; std::map<RTLIL::IdString, statdata_t> mod_stat;
dict<IdString, double> cell_area; dict<IdString, double> cell_area;
string techname;
size_t argidx; size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) for (argidx = 1; argidx < args.size(); argidx++)
@ -253,6 +316,10 @@ struct StatPass : public Pass {
read_liberty_cellarea(cell_area, liberty_file); read_liberty_cellarea(cell_area, liberty_file);
continue; continue;
} }
if (args[argidx] == "-tech" && argidx+1 < args.size()) {
techname = args[++argidx];
continue;
}
if (args[argidx] == "-top" && argidx+1 < args.size()) { if (args[argidx] == "-top" && argidx+1 < args.size()) {
if (design->modules_.count(RTLIL::escape_id(args[argidx+1])) == 0) if (design->modules_.count(RTLIL::escape_id(args[argidx+1])) == 0)
log_cmd_error("Can't find module %s.\n", args[argidx+1].c_str()); log_cmd_error("Can't find module %s.\n", args[argidx+1].c_str());
@ -263,13 +330,16 @@ struct StatPass : public Pass {
} }
extra_args(args, argidx, design); extra_args(args, argidx, design);
if (techname != "" && techname != "xilinx")
log_cmd_error("Unsupported technology: '%s'\n", techname.c_str());
for (auto mod : design->selected_modules()) for (auto mod : design->selected_modules())
{ {
if (!top_mod && design->full_selection()) if (!top_mod && design->full_selection())
if (mod->get_bool_attribute("\\top")) if (mod->get_bool_attribute("\\top"))
top_mod = mod; top_mod = mod;
statdata_t data(design, mod, width_mode, cell_area); statdata_t data(design, mod, width_mode, cell_area, techname);
mod_stat[mod->name] = data; mod_stat[mod->name] = data;
log("\n"); log("\n");

View File

@ -52,7 +52,9 @@ struct TeePass : public Pass {
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{ {
std::vector<FILE*> backup_log_files, files_to_close; std::vector<FILE*> backup_log_files, files_to_close;
std::vector<std::ostream*> backup_log_streams;
int backup_log_verbose_level = log_verbose_level; int backup_log_verbose_level = log_verbose_level;
backup_log_streams = log_streams;
backup_log_files = log_files; backup_log_files = log_files;
size_t argidx; size_t argidx;
@ -60,6 +62,7 @@ struct TeePass : public Pass {
{ {
if (args[argidx] == "-q" && files_to_close.empty()) { if (args[argidx] == "-q" && files_to_close.empty()) {
log_files.clear(); log_files.clear();
log_streams.clear();
continue; continue;
} }
if ((args[argidx] == "-o" || args[argidx] == "-a") && argidx+1 < args.size()) { if ((args[argidx] == "-o" || args[argidx] == "-a") && argidx+1 < args.size()) {
@ -89,6 +92,7 @@ struct TeePass : public Pass {
for (auto cf : files_to_close) for (auto cf : files_to_close)
fclose(cf); fclose(cf);
log_files = backup_log_files; log_files = backup_log_files;
log_streams = backup_log_streams;
throw; throw;
} }
@ -97,6 +101,7 @@ struct TeePass : public Pass {
log_verbose_level = backup_log_verbose_level; log_verbose_level = backup_log_verbose_level;
log_files = backup_log_files; log_files = backup_log_files;
log_streams = backup_log_streams;
} }
} TeePass; } TeePass;

View File

@ -44,7 +44,10 @@ struct EquivOptPass:public ScriptPass
log(" useful for handling architecture-specific primitives.\n"); log(" useful for handling architecture-specific primitives.\n");
log("\n"); log("\n");
log(" -assert\n"); log(" -assert\n");
log(" produce an error if the circuits are not equivalent\n"); log(" produce an error if the circuits are not equivalent.\n");
log("\n");
log(" -undef\n");
log(" enable modelling of undef states during equiv_induct.\n");
log("\n"); log("\n");
log("The following commands are executed by this verification command:\n"); log("The following commands are executed by this verification command:\n");
help_script(); help_script();
@ -52,13 +55,14 @@ struct EquivOptPass:public ScriptPass
} }
std::string command, techmap_opts; std::string command, techmap_opts;
bool assert; bool assert, undef;
void clear_flags() YS_OVERRIDE void clear_flags() YS_OVERRIDE
{ {
command = ""; command = "";
techmap_opts = ""; techmap_opts = "";
assert = false; assert = false;
undef = false;
} }
void execute(std::vector < std::string > args, RTLIL::Design * design) YS_OVERRIDE void execute(std::vector < std::string > args, RTLIL::Design * design) YS_OVERRIDE
@ -84,6 +88,10 @@ struct EquivOptPass:public ScriptPass
assert = true; assert = true;
continue; continue;
} }
if (args[argidx] == "-undef") {
undef = true;
continue;
}
break; break;
} }
@ -139,6 +147,11 @@ struct EquivOptPass:public ScriptPass
if (check_label("prove")) { if (check_label("prove")) {
run("equiv_make gold gate equiv"); run("equiv_make gold gate equiv");
if (help_mode)
run("equiv_induct [-undef] equiv");
else if (undef)
run("equiv_induct -undef equiv");
else
run("equiv_induct equiv"); run("equiv_induct equiv");
if (help_mode) if (help_mode)
run("equiv_status [-assert] equiv"); run("equiv_status [-assert] equiv");

View File

@ -562,7 +562,8 @@ struct HierarchyPass : public Pass {
log("In parametric designs, a module might exists in several variations with\n"); log("In parametric designs, a module might exists in several variations with\n");
log("different parameter values. This pass looks at all modules in the current\n"); log("different parameter values. This pass looks at all modules in the current\n");
log("design an re-runs the language frontends for the parametric modules as\n"); log("design an re-runs the language frontends for the parametric modules as\n");
log("needed.\n"); log("needed. It also resolves assignments to wired logic data types (wand/wor),\n");
log("resolves positional module parameters, unroll array instances, and more.\n");
log("\n"); log("\n");
log(" -check\n"); log(" -check\n");
log(" also check the design hierarchy. this generates an error when\n"); log(" also check the design hierarchy. this generates an error when\n");
@ -570,7 +571,7 @@ struct HierarchyPass : public Pass {
log("\n"); log("\n");
log(" -simcheck\n"); log(" -simcheck\n");
log(" like -check, but also throw an error if blackbox modules are\n"); log(" like -check, but also throw an error if blackbox modules are\n");
log(" instantiated, and throw an error if the design has no top module\n"); log(" instantiated, and throw an error if the design has no top module.\n");
log("\n"); log("\n");
log(" -purge_lib\n"); log(" -purge_lib\n");
log(" by default the hierarchy command will not remove library (blackbox)\n"); log(" by default the hierarchy command will not remove library (blackbox)\n");
@ -583,20 +584,20 @@ struct HierarchyPass : public Pass {
log("\n"); log("\n");
log(" -keep_positionals\n"); log(" -keep_positionals\n");
log(" per default this pass also converts positional arguments in cells\n"); log(" per default this pass also converts positional arguments in cells\n");
log(" to arguments using port names. this option disables this behavior.\n"); log(" to arguments using port names. This option disables this behavior.\n");
log("\n"); log("\n");
log(" -keep_portwidths\n"); log(" -keep_portwidths\n");
log(" per default this pass adjusts the port width on cells that are\n"); log(" per default this pass adjusts the port width on cells that are\n");
log(" module instances when the width does not match the module port. this\n"); log(" module instances when the width does not match the module port. This\n");
log(" option disables this behavior.\n"); log(" option disables this behavior.\n");
log("\n"); log("\n");
log(" -nokeep_asserts\n"); log(" -nokeep_asserts\n");
log(" per default this pass sets the \"keep\" attribute on all modules\n"); log(" per default this pass sets the \"keep\" attribute on all modules\n");
log(" that directly or indirectly contain one or more $assert cells. this\n"); log(" that directly or indirectly contain one or more formal properties.\n");
log(" option disables this behavior.\n"); log(" This option disables this behavior.\n");
log("\n"); log("\n");
log(" -top <module>\n"); log(" -top <module>\n");
log(" use the specified top module to built a design hierarchy. modules\n"); log(" use the specified top module to build the design hierarchy. Modules\n");
log(" outside this tree (unused modules) are removed.\n"); log(" outside this tree (unused modules) are removed.\n");
log("\n"); log("\n");
log(" when the -top option is used, the 'top' attribute will be set on the\n"); log(" when the -top option is used, the 'top' attribute will be set on the\n");
@ -606,6 +607,12 @@ struct HierarchyPass : public Pass {
log(" -auto-top\n"); log(" -auto-top\n");
log(" automatically determine the top of the design hierarchy and mark it.\n"); log(" automatically determine the top of the design hierarchy and mark it.\n");
log("\n"); log("\n");
log(" -chparam name value \n");
log(" elaborate the top module using this parameter value. Modules on which\n");
log(" this parameter does not exist may cause a warning message to be output.\n");
log(" This option can be specified multiple times to override multiple\n");
log(" parameters. String values must be passed in double quotes (\").\n");
log("\n");
log("In -generate mode this pass generates blackbox modules for the given cell\n"); log("In -generate mode this pass generates blackbox modules for the given cell\n");
log("types (wildcards supported). For this the design is searched for cells that\n"); log("types (wildcards supported). For this the design is searched for cells that\n");
log("match the given types and then the given port declarations are used to\n"); log("match the given types and then the given port declarations are used to\n");
@ -641,6 +648,7 @@ struct HierarchyPass : public Pass {
bool nokeep_asserts = false; bool nokeep_asserts = false;
std::vector<std::string> generate_cells; std::vector<std::string> generate_cells;
std::vector<generate_port_decl_t> generate_ports; std::vector<generate_port_decl_t> generate_ports;
std::map<std::string, std::string> parameters;
size_t argidx; size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) for (argidx = 1; argidx < args.size(); argidx++)
@ -715,13 +723,6 @@ struct HierarchyPass : public Pass {
if (args[argidx] == "-top") { if (args[argidx] == "-top") {
if (++argidx >= args.size()) if (++argidx >= args.size())
log_cmd_error("Option -top requires an additional argument!\n"); log_cmd_error("Option -top requires an additional argument!\n");
top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL;
if (top_mod == NULL && design->modules_.count("$abstract" + RTLIL::escape_id(args[argidx]))) {
dict<RTLIL::IdString, RTLIL::Const> empty_parameters;
design->modules_.at("$abstract" + RTLIL::escape_id(args[argidx]))->derive(design, empty_parameters);
top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL;
}
if (top_mod == NULL)
load_top_mod = args[argidx]; load_top_mod = args[argidx];
continue; continue;
} }
@ -729,14 +730,54 @@ struct HierarchyPass : public Pass {
auto_top_mode = true; auto_top_mode = true;
continue; continue;
} }
if (args[argidx] == "-chparam" && argidx+2 < args.size()) {
const std::string &key = args[++argidx];
const std::string &value = args[++argidx];
auto r = parameters.emplace(key, value);
if (!r.second) {
log_warning("-chparam %s already specified: overwriting.\n", key.c_str());
r.first->second = value;
}
continue;
}
break; break;
} }
extra_args(args, argidx, design, false); extra_args(args, argidx, design, false);
if (!load_top_mod.empty()) { if (!load_top_mod.empty())
{
IdString top_name = RTLIL::escape_id(load_top_mod);
IdString abstract_id = "$abstract" + RTLIL::escape_id(load_top_mod);
top_mod = design->module(top_name);
dict<RTLIL::IdString, RTLIL::Const> top_parameters;
for (auto &para : parameters) {
SigSpec sig_value;
if (!RTLIL::SigSpec::parse(sig_value, NULL, para.second))
log_cmd_error("Can't decode value '%s'!\n", para.second.c_str());
top_parameters[RTLIL::escape_id(para.first)] = sig_value.as_const();
}
if (top_mod == nullptr && design->module(abstract_id))
top_mod = design->module(design->module(abstract_id)->derive(design, top_parameters));
else if (top_mod != nullptr && !top_parameters.empty())
top_mod = design->module(top_mod->derive(design, top_parameters));
if (top_mod != nullptr && top_mod->name != top_name) {
Module *m = top_mod->clone();
m->name = top_name;
Module *old_mod = design->module(top_name);
if (old_mod)
design->remove(old_mod);
design->add(m);
top_mod = m;
}
}
if (top_mod == nullptr && !load_top_mod.empty()) {
#ifdef YOSYS_ENABLE_VERIFIC #ifdef YOSYS_ENABLE_VERIFIC
if (verific_import_pending) { if (verific_import_pending) {
verific_import(design, load_top_mod); verific_import(design, parameters, load_top_mod);
top_mod = design->module(RTLIL::escape_id(load_top_mod)); top_mod = design->module(RTLIL::escape_id(load_top_mod));
} }
#endif #endif
@ -745,7 +786,7 @@ struct HierarchyPass : public Pass {
} else { } else {
#ifdef YOSYS_ENABLE_VERIFIC #ifdef YOSYS_ENABLE_VERIFIC
if (verific_import_pending) if (verific_import_pending)
verific_import(design); verific_import(design, parameters);
#endif #endif
} }
@ -846,7 +887,7 @@ struct HierarchyPass : public Pass {
std::map<RTLIL::Module*, bool> cache; std::map<RTLIL::Module*, bool> cache;
for (auto mod : design->modules()) for (auto mod : design->modules())
if (set_keep_assert(cache, mod)) { if (set_keep_assert(cache, mod)) {
log("Module %s directly or indirectly contains $assert cells -> setting \"keep\" attribute.\n", log_id(mod)); log("Module %s directly or indirectly contains formal properties -> setting \"keep\" attribute.\n", log_id(mod));
mod->set_bool_attribute("\\keep"); mod->set_bool_attribute("\\keep");
} }
} }
@ -903,6 +944,121 @@ struct HierarchyPass : public Pass {
std::vector<Module*> design_modules = design->modules(); std::vector<Module*> design_modules = design->modules();
for (auto module : design_modules) for (auto module : design_modules)
{
pool<Wire*> wand_wor_index;
dict<Wire*, SigSpec> wand_map, wor_map;
vector<SigSig> new_connections;
for (auto wire : module->wires())
{
if (wire->get_bool_attribute("\\wand")) {
wand_map[wire] = SigSpec();
wand_wor_index.insert(wire);
}
if (wire->get_bool_attribute("\\wor")) {
wor_map[wire] = SigSpec();
wand_wor_index.insert(wire);
}
}
for (auto &conn : module->connections())
{
SigSig new_conn;
int cursor = 0;
for (auto c : conn.first.chunks())
{
Wire *w = c.wire;
SigSpec rhs = conn.second.extract(cursor, GetSize(c));
if (wand_wor_index.count(w) == 0) {
new_conn.first.append(c);
new_conn.second.append(rhs);
} else {
if (wand_map.count(w)) {
SigSpec sig = SigSpec(State::S1, GetSize(w));
sig.replace(c.offset, rhs);
wand_map.at(w).append(sig);
} else {
SigSpec sig = SigSpec(State::S0, GetSize(w));
sig.replace(c.offset, rhs);
wor_map.at(w).append(sig);
}
}
cursor += GetSize(c);
}
new_connections.push_back(new_conn);
}
module->new_connections(new_connections);
for (auto cell : module->cells())
{
if (!cell->known())
continue;
for (auto &conn : cell->connections())
{
if (!cell->output(conn.first))
continue;
SigSpec new_sig;
bool update_port = false;
for (auto c : conn.second.chunks())
{
Wire *w = c.wire;
if (wand_wor_index.count(w) == 0) {
new_sig.append(c);
continue;
}
Wire *t = module->addWire(NEW_ID, GetSize(c));
new_sig.append(t);
update_port = true;
if (wand_map.count(w)) {
SigSpec sig = SigSpec(State::S1, GetSize(w));
sig.replace(c.offset, t);
wand_map.at(w).append(sig);
} else {
SigSpec sig = SigSpec(State::S0, GetSize(w));
sig.replace(c.offset, t);
wor_map.at(w).append(sig);
}
}
if (update_port)
cell->setPort(conn.first, new_sig);
}
}
for (auto w : wand_wor_index)
{
bool wand = wand_map.count(w);
SigSpec sigs = wand ? wand_map.at(w) : wor_map.at(w);
if (GetSize(sigs) == 0)
continue;
if (GetSize(w) == 1) {
if (wand)
module->addReduceAnd(NEW_ID, sigs, w);
else
module->addReduceOr(NEW_ID, sigs, w);
continue;
}
SigSpec s = sigs.extract(0, GetSize(w));
for (int i = GetSize(w); i < GetSize(sigs); i += GetSize(w)) {
if (wand)
s = module->And(NEW_ID, s, sigs.extract(i, GetSize(w)));
else
s = module->Or(NEW_ID, s, sigs.extract(i, GetSize(w)));
}
module->connect(w, s);
}
for (auto cell : module->cells()) for (auto cell : module->cells())
{ {
Module *m = design->module(cell->type); Module *m = design->module(cell->type);
@ -961,6 +1117,7 @@ struct HierarchyPass : public Pass {
log_id(module), log_id(cell), log_id(conn.first), log_id(cell->type), log_signal(sig)); log_id(module), log_id(cell), log_id(conn.first), log_id(cell->type), log_signal(sig));
} }
} }
}
for (auto module : blackbox_derivatives) for (auto module : blackbox_derivatives)
design->remove(module); design->remove(module);

View File

@ -64,7 +64,7 @@ struct keep_cache_t
bool query(Cell *cell) bool query(Cell *cell)
{ {
if (cell->type.in("$memwr", "$meminit", "$assert", "$assume", "$live", "$fair", "$cover")) if (cell->type.in("$memwr", "$meminit", "$assert", "$assume", "$live", "$fair", "$cover", "$specify2", "$specify3", "$specrule"))
return true; return true;
if (cell->has_keep_attr()) if (cell->has_keep_attr())
@ -85,19 +85,31 @@ void rmunused_module_cells(Module *module, bool verbose)
{ {
SigMap sigmap(module); SigMap sigmap(module);
pool<Cell*> queue, unused; pool<Cell*> queue, unused;
pool<SigBit> used_raw_bits;
dict<SigBit, pool<Cell*>> wire2driver; dict<SigBit, pool<Cell*>> wire2driver;
dict<SigBit, vector<string>> driver_driver_logs;
SigMap raw_sigmap;
for (auto &it : module->connections_) {
for (int i = 0; i < GetSize(it.second); i++) {
if (it.second[i].wire != nullptr)
raw_sigmap.add(it.first[i], it.second[i]);
}
}
for (auto &it : module->cells_) { for (auto &it : module->cells_) {
Cell *cell = it.second; Cell *cell = it.second;
for (auto &it2 : cell->connections()) { for (auto &it2 : cell->connections()) {
if (!ct_all.cell_known(cell->type) || ct_all.cell_output(cell->type, it2.first)) if (ct_all.cell_known(cell->type) && !ct_all.cell_output(cell->type, it2.first))
continue;
for (auto raw_bit : it2.second) { for (auto raw_bit : it2.second) {
if (raw_bit.wire == nullptr) if (raw_bit.wire == nullptr)
continue; continue;
auto bit = sigmap(raw_bit); auto bit = sigmap(raw_bit);
if (bit.wire == nullptr) if (bit.wire == nullptr && ct_all.cell_known(cell->type))
log_warning("Driver-driver conflict for %s between cell %s.%s and constant %s in %s: Resolved using constant.\n", driver_driver_logs[raw_sigmap(raw_bit)].push_back(stringf("Driver-driver conflict "
log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module)); "for %s between cell %s.%s and constant %s in %s: Resolved using constant.",
log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module)));
if (bit.wire != nullptr) if (bit.wire != nullptr)
wire2driver[bit].insert(cell); wire2driver[bit].insert(cell);
} }
@ -114,6 +126,8 @@ void rmunused_module_cells(Module *module, bool verbose)
for (auto bit : sigmap(wire)) for (auto bit : sigmap(wire))
for (auto c : wire2driver[bit]) for (auto c : wire2driver[bit])
queue.insert(c), unused.erase(c); queue.insert(c), unused.erase(c);
for (auto raw_bit : SigSpec(wire))
used_raw_bits.insert(raw_sigmap(raw_bit));
} }
} }
@ -142,6 +156,22 @@ void rmunused_module_cells(Module *module, bool verbose)
module->remove(cell); module->remove(cell);
count_rm_cells++; count_rm_cells++;
} }
for (auto &it : module->cells_) {
Cell *cell = it.second;
for (auto &it2 : cell->connections()) {
if (ct_all.cell_known(cell->type) && !ct_all.cell_input(cell->type, it2.first))
continue;
for (auto raw_bit : raw_sigmap(it2.second))
used_raw_bits.insert(raw_bit);
}
}
for (auto it : driver_driver_logs) {
if (used_raw_bits.count(it.first))
for (auto msg : it.second)
log_warning("%s\n", msg.c_str());
}
} }
int count_nontrivial_wire_attrs(RTLIL::Wire *w) int count_nontrivial_wire_attrs(RTLIL::Wire *w)
@ -202,7 +232,7 @@ bool check_public_name(RTLIL::IdString id)
return true; return true;
} }
void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbose) bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbose)
{ {
SigPool register_signals; SigPool register_signals;
SigPool connected_signals; SigPool connected_signals;
@ -245,11 +275,13 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
module->connections_.clear(); module->connections_.clear();
SigPool used_signals; SigPool used_signals;
SigPool raw_used_signals;
SigPool used_signals_nodrivers; SigPool used_signals_nodrivers;
for (auto &it : module->cells_) { for (auto &it : module->cells_) {
RTLIL::Cell *cell = it.second; RTLIL::Cell *cell = it.second;
for (auto &it2 : cell->connections_) { for (auto &it2 : cell->connections_) {
assign_map.apply(it2.second); assign_map.apply(it2.second);
raw_used_signals.add(it2.second);
used_signals.add(it2.second); used_signals.add(it2.second);
if (!ct_all.cell_output(cell->type, it2.first)) if (!ct_all.cell_output(cell->type, it2.first))
used_signals_nodrivers.add(it2.second); used_signals_nodrivers.add(it2.second);
@ -259,6 +291,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
RTLIL::Wire *wire = it.second; RTLIL::Wire *wire = it.second;
if (wire->port_id > 0) { if (wire->port_id > 0) {
RTLIL::SigSpec sig = RTLIL::SigSpec(wire); RTLIL::SigSpec sig = RTLIL::SigSpec(wire);
raw_used_signals.add(sig);
assign_map.apply(sig); assign_map.apply(sig);
used_signals.add(sig); used_signals.add(sig);
if (!wire->port_input) if (!wire->port_input)
@ -271,40 +304,73 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
} }
} }
std::vector<RTLIL::Wire*> maybe_del_wires; pool<RTLIL::Wire*> del_wires_queue;
for (auto wire : module->wires()) for (auto wire : module->wires())
{ {
if ((!purge_mode && check_public_name(wire->name)) || wire->port_id != 0 || wire->get_bool_attribute("\\keep") || wire->attributes.count("\\init")) { SigSpec s1 = SigSpec(wire), s2 = assign_map(s1);
RTLIL::SigSpec s1 = RTLIL::SigSpec(wire), s2 = s1;
assign_map.apply(s2);
if (!used_signals.check_any(s2) && wire->port_id == 0 && !wire->get_bool_attribute("\\keep")) {
maybe_del_wires.push_back(wire);
} else {
log_assert(GetSize(s1) == GetSize(s2)); log_assert(GetSize(s1) == GetSize(s2));
Const initval;
if (wire->attributes.count("\\init"))
initval = wire->attributes.at("\\init");
if (GetSize(initval) != GetSize(wire))
initval.bits.resize(GetSize(wire), State::Sx);
if (initval.is_fully_undef())
wire->attributes.erase("\\init");
if (GetSize(wire) == 0) {
// delete zero-width wires, unless they are module ports
if (wire->port_id == 0)
goto delete_this_wire;
} else
if (wire->port_id != 0 || wire->get_bool_attribute("\\keep") || !initval.is_fully_undef()) {
// do not delete anything with "keep" or module ports or initialized wires
} else
if (!purge_mode && check_public_name(wire->name)) {
// do not get rid of public names unless in purge mode
} else
if (!raw_used_signals.check_any(s1)) {
// delete wires that aren't used by anything directly
goto delete_this_wire;
} else
if (!used_signals.check_any(s2)) {
// delete wires that aren't used by anything indirectly, even though other wires may alias it
goto delete_this_wire;
}
if (0)
{
delete_this_wire:
del_wires_queue.insert(wire);
}
else
{
RTLIL::SigSig new_conn; RTLIL::SigSig new_conn;
for (int i = 0; i < GetSize(s1); i++) for (int i = 0; i < GetSize(s1); i++)
if (s1[i] != s2[i]) { if (s1[i] != s2[i]) {
if (s2[i] == State::Sx && (initval[i] == State::S0 || initval[i] == State::S1)) {
s2[i] = initval[i];
initval[i] = State::Sx;
}
new_conn.first.append_bit(s1[i]); new_conn.first.append_bit(s1[i]);
new_conn.second.append_bit(s2[i]); new_conn.second.append_bit(s2[i]);
} }
if (new_conn.first.size() > 0) { if (new_conn.first.size() > 0) {
if (initval.is_fully_undef())
wire->attributes.erase("\\init");
else
wire->attributes.at("\\init") = initval;
used_signals.add(new_conn.first); used_signals.add(new_conn.first);
used_signals.add(new_conn.second); used_signals.add(new_conn.second);
module->connect(new_conn); module->connect(new_conn);
} }
}
} else {
if (!used_signals.check_any(RTLIL::SigSpec(wire)))
maybe_del_wires.push_back(wire);
}
RTLIL::SigSpec sig = assign_map(RTLIL::SigSpec(wire)); if (!used_signals_nodrivers.check_all(s2)) {
if (!used_signals_nodrivers.check_any(sig)) {
std::string unused_bits; std::string unused_bits;
for (int i = 0; i < GetSize(sig); i++) { for (int i = 0; i < GetSize(s2); i++) {
if (sig[i].wire == NULL) if (s2[i].wire == NULL)
continue; continue;
if (!used_signals_nodrivers.check(sig[i])) { if (!used_signals_nodrivers.check(s2[i])) {
if (!unused_bits.empty()) if (!unused_bits.empty())
unused_bits += " "; unused_bits += " ";
unused_bits += stringf("%d", i); unused_bits += stringf("%d", i);
@ -318,25 +384,23 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
wire->attributes.erase("\\unused_bits"); wire->attributes.erase("\\unused_bits");
} }
} }
}
int del_temp_wires_count = 0;
pool<RTLIL::Wire*> del_wires; for (auto wire : del_wires_queue) {
if (ys_debug() || (check_public_name(wire->name) && verbose))
int del_wires_count = 0;
for (auto wire : maybe_del_wires)
if (!used_signals.check_any(RTLIL::SigSpec(wire))) {
if (check_public_name(wire->name) && verbose) {
log_debug(" removing unused non-port wire %s.\n", wire->name.c_str()); log_debug(" removing unused non-port wire %s.\n", wire->name.c_str());
} else
del_wires.insert(wire); del_temp_wires_count++;
del_wires_count++;
} }
module->remove(del_wires); module->remove(del_wires_queue);
count_rm_wires += del_wires.size(); count_rm_wires += GetSize(del_wires_queue);
if (verbose && del_wires_count > 0) if (verbose && del_temp_wires_count)
log_debug(" removed %d unused temporary wires.\n", del_wires_count); log_debug(" removed %d unused temporary wires.\n", del_temp_wires_count);
return !del_wires_queue.empty();
} }
bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
@ -434,10 +498,10 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool
module->design->scratchpad_set_bool("opt.did_something", true); module->design->scratchpad_set_bool("opt.did_something", true);
rmunused_module_cells(module, verbose); rmunused_module_cells(module, verbose);
rmunused_module_signals(module, purge_mode, verbose); while (rmunused_module_signals(module, purge_mode, verbose)) { }
if (rminit && rmunused_module_init(module, purge_mode, verbose)) if (rminit && rmunused_module_init(module, purge_mode, verbose))
rmunused_module_signals(module, purge_mode, verbose); while (rmunused_module_signals(module, purge_mode, verbose)) { }
} }
struct OptCleanPass : public Pass { struct OptCleanPass : public Pass {
@ -483,6 +547,9 @@ struct OptCleanPass : public Pass {
ct_all.setup(design); ct_all.setup(design);
count_rm_cells = 0;
count_rm_wires = 0;
for (auto module : design->selected_whole_modules_warn()) { for (auto module : design->selected_whole_modules_warn()) {
if (module->has_processes_warn()) if (module->has_processes_warn())
continue; continue;
@ -548,7 +615,7 @@ struct CleanPass : public Pass {
for (auto module : design->selected_whole_modules()) { for (auto module : design->selected_whole_modules()) {
if (module->has_processes()) if (module->has_processes())
continue; continue;
rmunused_module(module, purge_mode, false, false); rmunused_module(module, purge_mode, ys_debug(), false);
} }
log_suppressed(); log_suppressed();

View File

@ -39,6 +39,9 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
SigPool used_signals; SigPool used_signals;
SigPool all_signals; SigPool all_signals;
dict<SigBit, pair<Wire*, State>> initbits;
pool<Wire*> revisit_initwires;
for (auto cell : module->cells()) for (auto cell : module->cells())
for (auto &conn : cell->connections()) { for (auto &conn : cell->connections()) {
if (!ct.cell_known(cell->type) || ct.cell_output(cell->type, conn.first)) if (!ct.cell_known(cell->type) || ct.cell_output(cell->type, conn.first))
@ -48,9 +51,17 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
} }
for (auto wire : module->wires()) { for (auto wire : module->wires()) {
if (wire->attributes.count("\\init")) {
SigSpec sig = sigmap(wire);
Const initval = wire->attributes.at("\\init");
for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++) {
if (initval[i] == State::S0 || initval[i] == State::S1)
initbits[sig[i]] = make_pair(wire, initval[i]);
}
}
if (wire->port_input) if (wire->port_input)
driven_signals.add(sigmap(wire)); driven_signals.add(sigmap(wire));
if (wire->port_output) if (wire->port_output || wire->get_bool_attribute("\\keep"))
used_signals.add(sigmap(wire)); used_signals.add(sigmap(wire));
all_signals.add(sigmap(wire)); all_signals.add(sigmap(wire));
} }
@ -67,10 +78,43 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
if (sig.size() == 0) if (sig.size() == 0)
continue; continue;
log_debug("Setting undriven signal in %s to undef: %s\n", RTLIL::id2cstr(module->name), log_signal(c)); Const val(RTLIL::State::Sx, GetSize(sig));
module->connect(RTLIL::SigSig(c, RTLIL::SigSpec(RTLIL::State::Sx, c.width))); for (int i = 0; i < GetSize(sig); i++) {
SigBit bit = sigmap(sig[i]);
auto cursor = initbits.find(bit);
if (cursor != initbits.end()) {
revisit_initwires.insert(cursor->second.first);
val[i] = cursor->second.second;
}
}
log_debug("Setting undriven signal in %s to constant: %s = %s\n", log_id(module), log_signal(sig), log_signal(val));
module->connect(sig, val);
did_something = true; did_something = true;
} }
if (!revisit_initwires.empty())
{
SigMap sm2(module);
for (auto wire : revisit_initwires) {
SigSpec sig = sm2(wire);
Const initval = wire->attributes.at("\\init");
for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++) {
if (SigBit(initval[i]) == sig[i])
initval[i] = State::Sx;
}
if (initval.is_fully_undef()) {
log_debug("Removing init attribute from %s/%s.\n", log_id(module), log_id(wire));
wire->attributes.erase("\\init");
did_something = true;
} else if (initval != wire->attributes.at("\\init")) {
log_debug("Updating init attribute on %s/%s: %s\n", log_id(module), log_id(wire), log_signal(initval));
wire->attributes["\\init"] = initval;
did_something = true;
}
}
}
} }
void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, std::string info, std::string out_port, RTLIL::SigSpec out_val) void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, std::string info, std::string out_port, RTLIL::SigSpec out_val)

View File

@ -184,6 +184,10 @@ struct OptMuxtreeWorker
log_debug(" Root of a mux tree: %s%s\n", log_id(mux2info[mux_idx].cell), root_enable_muxes.at(mux_idx) ? " (pure)" : ""); log_debug(" Root of a mux tree: %s%s\n", log_id(mux2info[mux_idx].cell), root_enable_muxes.at(mux_idx) ? " (pure)" : "");
root_mux_rerun.erase(mux_idx); root_mux_rerun.erase(mux_idx);
eval_root_mux(mux_idx); eval_root_mux(mux_idx);
if (glob_abort_cnt == 0) {
log(" Giving up (too many iterations)\n");
return;
}
} }
while (!root_mux_rerun.empty()) { while (!root_mux_rerun.empty()) {
@ -192,9 +196,14 @@ struct OptMuxtreeWorker
log_assert(root_enable_muxes.at(mux_idx)); log_assert(root_enable_muxes.at(mux_idx));
root_mux_rerun.erase(mux_idx); root_mux_rerun.erase(mux_idx);
eval_root_mux(mux_idx); eval_root_mux(mux_idx);
if (glob_abort_cnt == 0) {
log(" Giving up (too many iterations)\n");
return;
}
} }
log(" Analyzing evaluation results.\n"); log(" Analyzing evaluation results.\n");
log_assert(glob_abort_cnt > 0);
for (auto &mi : mux2info) for (auto &mi : mux2info)
{ {
@ -397,10 +406,8 @@ struct OptMuxtreeWorker
void eval_mux(knowledge_t &knowledge, int mux_idx, bool do_replace_known, bool do_enable_ports, int abort_count) void eval_mux(knowledge_t &knowledge, int mux_idx, bool do_replace_known, bool do_enable_ports, int abort_count)
{ {
if (glob_abort_cnt == 0) { if (glob_abort_cnt == 0)
log(" Giving up (too many iterations)\n");
return; return;
}
glob_abort_cnt--; glob_abort_cnt--;
muxinfo_t &muxinfo = mux2info[mux_idx]; muxinfo_t &muxinfo = mux2info[mux_idx];
@ -454,6 +461,7 @@ struct OptMuxtreeWorker
void eval_root_mux(int mux_idx) void eval_root_mux(int mux_idx)
{ {
log_assert(glob_abort_cnt > 0);
knowledge_t knowledge; knowledge_t knowledge;
knowledge.known_inactive.resize(GetSize(bit2info)); knowledge.known_inactive.resize(GetSize(bit2info));
knowledge.known_active.resize(GetSize(bit2info)); knowledge.known_active.resize(GetSize(bit2info));

View File

@ -260,8 +260,8 @@ delete_dlatch:
bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff) bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
{ {
RTLIL::SigSpec sig_d, sig_q, sig_c, sig_r; RTLIL::SigSpec sig_d, sig_q, sig_c, sig_r, sig_e;
RTLIL::Const val_cp, val_rp, val_rv; RTLIL::Const val_cp, val_rp, val_rv, val_ep;
if (dff->type == "$_FF_") { if (dff->type == "$_FF_") {
sig_d = dff->getPort("\\D"); sig_d = dff->getPort("\\D");
@ -285,6 +285,16 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
val_rp = RTLIL::Const(dff->type[7] == 'P', 1); val_rp = RTLIL::Const(dff->type[7] == 'P', 1);
val_rv = RTLIL::Const(dff->type[8] == '1', 1); val_rv = RTLIL::Const(dff->type[8] == '1', 1);
} }
else if (dff->type.substr(0,7) == "$_DFFE_" && dff->type.substr(9) == "_" &&
(dff->type[7] == 'N' || dff->type[7] == 'P') &&
(dff->type[8] == 'N' || dff->type[8] == 'P')) {
sig_d = dff->getPort("\\D");
sig_q = dff->getPort("\\Q");
sig_c = dff->getPort("\\C");
sig_e = dff->getPort("\\E");
val_cp = RTLIL::Const(dff->type[7] == 'P', 1);
val_ep = RTLIL::Const(dff->type[8] == 'P', 1);
}
else if (dff->type == "$ff") { else if (dff->type == "$ff") {
sig_d = dff->getPort("\\D"); sig_d = dff->getPort("\\D");
sig_q = dff->getPort("\\Q"); sig_q = dff->getPort("\\Q");
@ -295,6 +305,14 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
sig_c = dff->getPort("\\CLK"); sig_c = dff->getPort("\\CLK");
val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1); val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1);
} }
else if (dff->type == "$dffe") {
sig_e = dff->getPort("\\EN");
sig_d = dff->getPort("\\D");
sig_q = dff->getPort("\\Q");
sig_c = dff->getPort("\\CLK");
val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1);
val_ep = RTLIL::Const(dff->parameters["\\EN_POLARITY"].as_bool(), 1);
}
else if (dff->type == "$adff") { else if (dff->type == "$adff") {
sig_d = dff->getPort("\\D"); sig_d = dff->getPort("\\D");
sig_q = dff->getPort("\\Q"); sig_q = dff->getPort("\\Q");
@ -337,39 +355,60 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
} }
} }
// If clock is driven by a constant and (i) no reset signal
// (ii) Q has no initial value
// (iii) initial value is same as reset value
if (!sig_c.empty() && sig_c.is_fully_const() && (!sig_r.size() || !has_init || val_init == val_rv)) { if (!sig_c.empty() && sig_c.is_fully_const() && (!sig_r.size() || !has_init || val_init == val_rv)) {
if (val_rv.bits.size() == 0) if (val_rv.bits.size() == 0)
val_rv = val_init; val_rv = val_init;
// Q is permanently reset value or initial value
mod->connect(sig_q, val_rv); mod->connect(sig_q, val_rv);
goto delete_dff; goto delete_dff;
} }
// If D is fully undefined and reset signal present and (i) Q has no initial value
// (ii) initial value is same as reset value
if (sig_d.is_fully_undef() && sig_r.size() && (!has_init || val_init == val_rv)) { if (sig_d.is_fully_undef() && sig_r.size() && (!has_init || val_init == val_rv)) {
// Q is permanently reset value
mod->connect(sig_q, val_rv); mod->connect(sig_q, val_rv);
goto delete_dff; goto delete_dff;
} }
// If D is fully undefined and no reset signal and Q has an initial value
if (sig_d.is_fully_undef() && !sig_r.size() && has_init) { if (sig_d.is_fully_undef() && !sig_r.size() && has_init) {
// Q is permanently initial value
mod->connect(sig_q, val_init); mod->connect(sig_q, val_init);
goto delete_dff; goto delete_dff;
} }
// If D is fully constant and (i) no reset signal
// (ii) reset value is same as constant D
// and (a) has no initial value
// (b) initial value same as constant D
if (sig_d.is_fully_const() && (!sig_r.size() || val_rv == sig_d.as_const()) && (!has_init || val_init == sig_d.as_const())) { if (sig_d.is_fully_const() && (!sig_r.size() || val_rv == sig_d.as_const()) && (!has_init || val_init == sig_d.as_const())) {
// Q is permanently D
mod->connect(sig_q, sig_d); mod->connect(sig_q, sig_d);
goto delete_dff; goto delete_dff;
} }
// If D input is same as Q output and (i) no reset signal
// (ii) no initial signal
// (iii) initial value is same as reset value
if (sig_d == sig_q && (sig_r.empty() || !has_init || val_init == val_rv)) { if (sig_d == sig_q && (sig_r.empty() || !has_init || val_init == val_rv)) {
// Q is permanently reset value or initial value
if (sig_r.size()) if (sig_r.size())
mod->connect(sig_q, val_rv); mod->connect(sig_q, val_rv);
if (has_init) else if (has_init)
mod->connect(sig_q, val_init); mod->connect(sig_q, val_init);
goto delete_dff; goto delete_dff;
} }
// If reset signal is present, and is fully constant
if (!sig_r.empty() && sig_r.is_fully_const()) if (!sig_r.empty() && sig_r.is_fully_const())
{ {
// If reset value is permanently active or if reset is undefined
if (sig_r == val_rp || sig_r.is_fully_undef()) { if (sig_r == val_rp || sig_r.is_fully_undef()) {
// Q is permanently reset value
mod->connect(sig_q, val_rv); mod->connect(sig_q, val_rv);
goto delete_dff; goto delete_dff;
} }
@ -389,6 +428,30 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
dff->unsetPort("\\R"); dff->unsetPort("\\R");
} }
// If enable signal is present, and is fully constant
if (!sig_e.empty() && sig_e.is_fully_const())
{
// If enable value is permanently inactive
if (sig_e != val_ep) {
// Q is permanently initial value
mod->connect(sig_q, val_init);
goto delete_dff;
}
log("Removing unused enable from %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod));
if (dff->type == "$dffe") {
dff->type = "$dff";
dff->unsetPort("\\EN");
dff->unsetParam("\\EN_POLARITY");
return true;
}
log_assert(dff->type.substr(0,7) == "$_DFFE_");
dff->type = stringf("$_DFF_%c_", + dff->type[7]);
dff->unsetPort("\\E");
}
return false; return false;
delete_dff: delete_dff:
@ -489,7 +552,8 @@ struct OptRmdffPass : public Pass {
if (cell->type.in("$_FF_", "$_DFF_N_", "$_DFF_P_", if (cell->type.in("$_FF_", "$_DFF_N_", "$_DFF_P_",
"$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
"$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_", "$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_",
"$ff", "$dff", "$adff")) "$_DFFE_NN_", "$_DFFE_NP_", "$_DFFE_PN_", "$_DFFE_PP_",
"$ff", "$dff", "$dffe", "$adff"))
dff_list.push_back(cell->name); dff_list.push_back(cell->name);
if (cell->type.in("$dlatch", "$_DLATCH_P_", "$_DLATCH_N_")) if (cell->type.in("$dlatch", "$_DLATCH_P_", "$_DLATCH_N_"))

View File

@ -29,6 +29,7 @@ PRIVATE_NAMESPACE_BEGIN
struct WreduceConfig struct WreduceConfig
{ {
pool<IdString> supported_cell_types; pool<IdString> supported_cell_types;
bool keepdc = false;
WreduceConfig() WreduceConfig()
{ {
@ -82,7 +83,7 @@ struct WreduceWorker
SigBit ref = sig_a[i]; SigBit ref = sig_a[i];
for (int k = 0; k < GetSize(sig_s); k++) { for (int k = 0; k < GetSize(sig_s); k++) {
if (ref != Sx && sig_b[k*GetSize(sig_a) + i] != Sx && ref != sig_b[k*GetSize(sig_a) + i]) if ((config->keepdc || (ref != Sx && sig_b[k*GetSize(sig_a) + i] != Sx)) && ref != sig_b[k*GetSize(sig_a) + i])
goto no_match_ab; goto no_match_ab;
if (sig_b[k*GetSize(sig_a) + i] != Sx) if (sig_b[k*GetSize(sig_a) + i] != Sx)
ref = sig_b[k*GetSize(sig_a) + i]; ref = sig_b[k*GetSize(sig_a) + i];
@ -180,6 +181,8 @@ struct WreduceWorker
} }
auto info = mi.query(sig_q[i]); auto info = mi.query(sig_q[i]);
if (info == nullptr)
return;
if (!info->is_output && GetSize(info->ports) == 1 && !keep_bits.count(mi.sigmap(sig_q[i]))) { if (!info->is_output && GetSize(info->ports) == 1 && !keep_bits.count(mi.sigmap(sig_q[i]))) {
remove_init_bits.insert(sig_q[i]); remove_init_bits.insert(sig_q[i]);
sig_d.remove(i); sig_d.remove(i);
@ -462,12 +465,10 @@ struct WreduceWorker
SigSpec initsig = init_attr_sigmap(w); SigSpec initsig = init_attr_sigmap(w);
int width = std::min(GetSize(initval), GetSize(initsig)); int width = std::min(GetSize(initval), GetSize(initsig));
for (int i = 0; i < width; i++) { for (int i = 0; i < width; i++) {
log_dump(initsig[i], remove_init_bits.count(initsig[i]));
if (!remove_init_bits.count(initsig[i])) if (!remove_init_bits.count(initsig[i]))
new_initval[i] = initval[i]; new_initval[i] = initval[i];
} }
w->attributes.at("\\init") = new_initval; w->attributes.at("\\init") = new_initval;
log_dump(w->name, initval, new_initval);
} }
} }
} }
@ -495,6 +496,9 @@ struct WreducePass : public Pass {
log(" Do not change the width of memory address ports. Use this options in\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(" flows that use the 'memory_memx' pass.\n");
log("\n"); log("\n");
log(" -keepdc\n");
log(" Do not optimize explicit don't-care values.\n");
log("\n");
} }
void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
{ {
@ -509,6 +513,10 @@ struct WreducePass : public Pass {
opt_memx = true; opt_memx = true;
continue; continue;
} }
if (args[argidx] == "-keepdc") {
config.keepdc = true;
continue;
}
break; break;
} }
extra_args(args, argidx, design); extra_args(args, argidx, design);
@ -531,6 +539,42 @@ struct WreducePass : public Pass {
module->connect(sig, Const(0, GetSize(sig))); module->connect(sig, Const(0, GetSize(sig)));
} }
} }
if (c->type.in("$div", "$mod", "$pow"))
{
SigSpec A = c->getPort("\\A");
int original_a_width = GetSize(A);
if (c->getParam("\\A_SIGNED").as_bool()) {
while (GetSize(A) > 1 && A[GetSize(A)-1] == State::S0 && A[GetSize(A)-2] == State::S0)
A.remove(GetSize(A)-1, 1);
} else {
while (GetSize(A) > 0 && A[GetSize(A)-1] == State::S0)
A.remove(GetSize(A)-1, 1);
}
if (original_a_width != GetSize(A)) {
log("Removed top %d bits (of %d) from port A of cell %s.%s (%s).\n",
original_a_width-GetSize(A), original_a_width, log_id(module), log_id(c), log_id(c->type));
c->setPort("\\A", A);
c->setParam("\\A_WIDTH", GetSize(A));
}
SigSpec B = c->getPort("\\B");
int original_b_width = GetSize(B);
if (c->getParam("\\B_SIGNED").as_bool()) {
while (GetSize(B) > 1 && B[GetSize(B)-1] == State::S0 && B[GetSize(B)-2] == State::S0)
B.remove(GetSize(B)-1, 1);
} else {
while (GetSize(B) > 0 && B[GetSize(B)-1] == State::S0)
B.remove(GetSize(B)-1, 1);
}
if (original_b_width != GetSize(B)) {
log("Removed top %d bits (of %d) from port B of cell %s.%s (%s).\n",
original_b_width-GetSize(B), original_b_width, log_id(module), log_id(c), log_id(c->type));
c->setPort("\\B", B);
c->setParam("\\B_WIDTH", GetSize(B));
}
}
if (!opt_memx && c->type.in("$memrd", "$memwr", "$meminit")) { if (!opt_memx && c->type.in("$memrd", "$memwr", "$meminit")) {
IdString memid = c->getParam("\\MEMID").decode_string(); IdString memid = c->getParam("\\MEMID").decode_string();
RTLIL::Memory *mem = module->memories.at(memid); RTLIL::Memory *mem = module->memories.at(memid);

View File

@ -1 +1,2 @@
/ice40_dsp_pm.h /ice40_dsp_pm.h
/peepopt_pm.h

View File

@ -1,8 +1,23 @@
OBJS += passes/pmgen/ice40_dsp.o OBJS += passes/pmgen/ice40_dsp.o
OBJS += passes/pmgen/peepopt.o
# --------------------------------------
passes/pmgen/ice40_dsp.o: passes/pmgen/ice40_dsp_pm.h passes/pmgen/ice40_dsp.o: passes/pmgen/ice40_dsp_pm.h
EXTRA_OBJS += passes/pmgen/ice40_dsp_pm.h EXTRA_OBJS += passes/pmgen/ice40_dsp_pm.h
.SECONDARY: passes/pmgen/ice40_dsp_pm.h .SECONDARY: passes/pmgen/ice40_dsp_pm.h
passes/pmgen/ice40_dsp_pm.h: passes/pmgen/pmgen.py passes/pmgen/ice40_dsp.pmg passes/pmgen/ice40_dsp_pm.h: passes/pmgen/pmgen.py passes/pmgen/ice40_dsp.pmg
$(P) mkdir -p passes/pmgen && python3 $^ $@ $(P) mkdir -p passes/pmgen && python3 $< -o $@ -p ice40_dsp $(filter-out $<,$^)
# --------------------------------------
passes/pmgen/peepopt.o: passes/pmgen/peepopt_pm.h
EXTRA_OBJS += passes/pmgen/peepopt_pm.h
.SECONDARY: passes/pmgen/peepopt_pm.h
PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul.pmg
PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg
passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
$(P) mkdir -p passes/pmgen && python3 $< -o $@ -p peepopt $(filter-out $<,$^)

View File

@ -29,19 +29,25 @@ up in any future matches:
pm.blacklist(some_cell); pm.blacklist(some_cell);
The `.run(callback_function)` method searches for all matches and calls the The `.run_<pattern_name>(callback_function)` method searches for all matches
callback function for each found match: for the pattern`<pattern_name>` and calls the callback function for each found
match:
pm.run([&](){ pm.run_foobar([&](){
log("found matching 'foo' cell: %s\n", log_id(pm.st.foo)); log("found matching 'foo' cell: %s\n", log_id(pm.st.foo));
log(" with 'bar' cell: %s\n", log_id(pm.st.bar)); log(" with 'bar' cell: %s\n", log_id(pm.st.bar));
}); });
The `.pmg` file declares matcher state variables that are accessible via the The `.pmg` file declares matcher state variables that are accessible via the
`.st.<state_name>` members. (The `.st` member is of type `foobar_pm::state_t`.) `.st_<pattern_name>.<state_name>` members. (The `.st_<pattern_name>` member is
of type `foobar_pm::state_<pattern_name>_t`.)
Similarly the `.pmg` file declares user data variables that become members of Similarly the `.pmg` file declares user data variables that become members of
`.ud`, a struct of type `foobar_pm::udata_t`. `.ud_<pattern_name>`, a struct of type `foobar_pm::udata_<pattern_name>_t`.
There are four versions of the `run_<pattern_name>()` method: Without callback,
callback without arguments, callback with reference to `pm`, and callback with
reference to `pm.st_<pattern_name>`.
The .pmg File Format The .pmg File Format
@ -52,6 +58,12 @@ lines consist of whitespace-separated tokens.
Lines in `.pmg` files starting with `//` are comments. Lines in `.pmg` files starting with `//` are comments.
Declaring a pattern
-------------------
A `.pmg` file contains one or more patterns. Each pattern starts with a line
with the `pattern` keyword followed by the name of the pattern.
Declaring state variables Declaring state variables
------------------------- -------------------------
@ -66,7 +78,7 @@ State variables are automatically managed by the generated backtracking algorith
and saved and restored as needed. and saved and restored as needed.
They are automatically initialized to the default constructed value of their type They are automatically initialized to the default constructed value of their type
when `.run(callback_function)` is called. when `.run_<pattern_name>(callback_function)` is called.
Declaring udata variables Declaring udata variables
------------------------- -------------------------
@ -220,5 +232,5 @@ But in some cases it is more natural to utilize the implicit branch statement:
portAB = \B; portAB = \B;
endcode endcode
There is an implicit `code..endcode` block at the end of each `.pgm` file There is an implicit `code..endcode` block at the end of each `.pmg` file
that just accepts everything that gets all the way there. that just accepts everything that gets all the way there.

View File

@ -19,47 +19,50 @@
#include "kernel/yosys.h" #include "kernel/yosys.h"
#include "kernel/sigtools.h" #include "kernel/sigtools.h"
#include "passes/pmgen/ice40_dsp_pm.h"
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN PRIVATE_NAMESPACE_BEGIN
#include "passes/pmgen/ice40_dsp_pm.h"
void create_ice40_dsp(ice40_dsp_pm &pm) void create_ice40_dsp(ice40_dsp_pm &pm)
{ {
auto &st = pm.st_ice40_dsp;
#if 0 #if 0
log("\n"); log("\n");
log("ffA: %s\n", log_id(pm.st.ffA, "--")); log("ffA: %s\n", log_id(st.ffA, "--"));
log("ffB: %s\n", log_id(pm.st.ffB, "--")); log("ffB: %s\n", log_id(st.ffB, "--"));
log("mul: %s\n", log_id(pm.st.mul, "--")); log("mul: %s\n", log_id(st.mul, "--"));
log("ffY: %s\n", log_id(pm.st.ffY, "--")); log("ffY: %s\n", log_id(st.ffY, "--"));
log("addAB: %s\n", log_id(pm.st.addAB, "--")); log("addAB: %s\n", log_id(st.addAB, "--"));
log("muxAB: %s\n", log_id(pm.st.muxAB, "--")); log("muxAB: %s\n", log_id(st.muxAB, "--"));
log("ffS: %s\n", log_id(pm.st.ffS, "--")); log("ffS: %s\n", log_id(st.ffS, "--"));
#endif #endif
log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(pm.st.mul)); log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(st.mul));
if (GetSize(pm.st.sigA) > 16) { if (GetSize(st.sigA) > 16) {
log(" input A (%s) is too large (%d > 16).\n", log_signal(pm.st.sigA), GetSize(pm.st.sigA)); log(" input A (%s) is too large (%d > 16).\n", log_signal(st.sigA), GetSize(st.sigA));
return; return;
} }
if (GetSize(pm.st.sigB) > 16) { if (GetSize(st.sigB) > 16) {
log(" input B (%s) is too large (%d > 16).\n", log_signal(pm.st.sigB), GetSize(pm.st.sigB)); log(" input B (%s) is too large (%d > 16).\n", log_signal(st.sigB), GetSize(st.sigB));
return; return;
} }
if (GetSize(pm.st.sigS) > 32) { if (GetSize(st.sigS) > 32) {
log(" accumulator (%s) is too large (%d > 32).\n", log_signal(pm.st.sigS), GetSize(pm.st.sigS)); log(" accumulator (%s) is too large (%d > 32).\n", log_signal(st.sigS), GetSize(st.sigS));
return; return;
} }
if (GetSize(pm.st.sigY) > 32) { if (GetSize(st.sigY) > 32) {
log(" output (%s) is too large (%d > 32).\n", log_signal(pm.st.sigY), GetSize(pm.st.sigY)); log(" output (%s) is too large (%d > 32).\n", log_signal(st.sigY), GetSize(st.sigY));
return; return;
} }
bool mul_signed = pm.st.mul->getParam("\\A_SIGNED").as_bool(); bool mul_signed = st.mul->getParam("\\A_SIGNED").as_bool();
if (mul_signed) { if (mul_signed) {
log(" inference of signed iCE40 DSP arithmetic is currently not supported.\n"); log(" inference of signed iCE40 DSP arithmetic is currently not supported.\n");
@ -69,21 +72,21 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
log(" replacing $mul with SB_MAC16 cell.\n"); log(" replacing $mul with SB_MAC16 cell.\n");
Cell *cell = pm.module->addCell(NEW_ID, "\\SB_MAC16"); Cell *cell = pm.module->addCell(NEW_ID, "\\SB_MAC16");
pm.module->swap_names(cell, pm.st.mul); pm.module->swap_names(cell, st.mul);
// SB_MAC16 Input Interface // SB_MAC16 Input Interface
SigSpec A = pm.st.sigA; SigSpec A = st.sigA;
A.extend_u0(16, mul_signed); A.extend_u0(16, mul_signed);
SigSpec B = pm.st.sigB; SigSpec B = st.sigB;
B.extend_u0(16, mul_signed); B.extend_u0(16, mul_signed);
SigSpec CD; SigSpec CD;
if (pm.st.muxA) if (st.muxA)
CD = pm.st.muxA->getPort("\\B"); CD = st.muxA->getPort("\\B");
if (pm.st.muxB) if (st.muxB)
CD = pm.st.muxB->getPort("\\A"); CD = st.muxB->getPort("\\A");
CD.extend_u0(32, mul_signed); CD.extend_u0(32, mul_signed);
cell->setPort("\\A", A); cell->setPort("\\A", A);
@ -91,8 +94,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
cell->setPort("\\C", CD.extract(0, 16)); cell->setPort("\\C", CD.extract(0, 16));
cell->setPort("\\D", CD.extract(16, 16)); cell->setPort("\\D", CD.extract(16, 16));
cell->setParam("\\A_REG", pm.st.ffA ? State::S1 : State::S0); cell->setParam("\\A_REG", st.ffA ? State::S1 : State::S0);
cell->setParam("\\B_REG", pm.st.ffB ? State::S1 : State::S0); cell->setParam("\\B_REG", st.ffB ? State::S1 : State::S0);
cell->setPort("\\AHOLD", State::S0); cell->setPort("\\AHOLD", State::S0);
cell->setPort("\\BHOLD", State::S0); cell->setPort("\\BHOLD", State::S0);
@ -102,25 +105,25 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
cell->setPort("\\IRSTTOP", State::S0); cell->setPort("\\IRSTTOP", State::S0);
cell->setPort("\\IRSTBOT", State::S0); cell->setPort("\\IRSTBOT", State::S0);
if (pm.st.clock_vld) if (st.clock_vld)
{ {
cell->setPort("\\CLK", pm.st.clock); cell->setPort("\\CLK", st.clock);
cell->setPort("\\CE", State::S1); cell->setPort("\\CE", State::S1);
cell->setParam("\\NEG_TRIGGER", pm.st.clock_pol ? State::S0 : State::S1); cell->setParam("\\NEG_TRIGGER", st.clock_pol ? State::S0 : State::S1);
log(" clock: %s (%s)", log_signal(pm.st.clock), pm.st.clock_pol ? "posedge" : "negedge"); log(" clock: %s (%s)", log_signal(st.clock), st.clock_pol ? "posedge" : "negedge");
if (pm.st.ffA) if (st.ffA)
log(" ffA:%s", log_id(pm.st.ffA)); log(" ffA:%s", log_id(st.ffA));
if (pm.st.ffB) if (st.ffB)
log(" ffB:%s", log_id(pm.st.ffB)); log(" ffB:%s", log_id(st.ffB));
if (pm.st.ffY) if (st.ffY)
log(" ffY:%s", log_id(pm.st.ffY)); log(" ffY:%s", log_id(st.ffY));
if (pm.st.ffS) if (st.ffS)
log(" ffS:%s", log_id(pm.st.ffS)); log(" ffS:%s", log_id(st.ffS));
log("\n"); log("\n");
} }
@ -144,16 +147,16 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
// SB_MAC16 Output Interface // SB_MAC16 Output Interface
SigSpec O = pm.st.ffS ? pm.st.sigS : pm.st.sigY; SigSpec O = st.ffS ? st.sigS : st.sigY;
if (GetSize(O) < 32) if (GetSize(O) < 32)
O.append(pm.module->addWire(NEW_ID, 32-GetSize(O))); O.append(pm.module->addWire(NEW_ID, 32-GetSize(O)));
cell->setPort("\\O", O); cell->setPort("\\O", O);
if (pm.st.addAB) { if (st.addAB) {
log(" accumulator %s (%s)\n", log_id(pm.st.addAB), log_id(pm.st.addAB->type)); log(" accumulator %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type));
cell->setPort("\\ADDSUBTOP", pm.st.addAB->type == "$add" ? State::S0 : State::S1); cell->setPort("\\ADDSUBTOP", st.addAB->type == "$add" ? State::S0 : State::S1);
cell->setPort("\\ADDSUBBOT", pm.st.addAB->type == "$add" ? State::S0 : State::S1); cell->setPort("\\ADDSUBBOT", st.addAB->type == "$add" ? State::S0 : State::S1);
} else { } else {
cell->setPort("\\ADDSUBTOP", State::S0); cell->setPort("\\ADDSUBTOP", State::S0);
cell->setPort("\\ADDSUBBOT", State::S0); cell->setPort("\\ADDSUBBOT", State::S0);
@ -166,10 +169,10 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
cell->setPort("\\OHOLDBOT", State::S0); cell->setPort("\\OHOLDBOT", State::S0);
SigSpec acc_reset = State::S0; SigSpec acc_reset = State::S0;
if (pm.st.muxA) if (st.muxA)
acc_reset = pm.st.muxA->getPort("\\S"); acc_reset = st.muxA->getPort("\\S");
if (pm.st.muxB) if (st.muxB)
acc_reset = pm.module->Not(NEW_ID, pm.st.muxB->getPort("\\S")); acc_reset = pm.module->Not(NEW_ID, st.muxB->getPort("\\S"));
cell->setPort("\\OLOADTOP", acc_reset); cell->setPort("\\OLOADTOP", acc_reset);
cell->setPort("\\OLOADBOT", acc_reset); cell->setPort("\\OLOADBOT", acc_reset);
@ -179,17 +182,17 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
cell->setParam("\\C_REG", State::S0); cell->setParam("\\C_REG", State::S0);
cell->setParam("\\D_REG", State::S0); cell->setParam("\\D_REG", State::S0);
cell->setParam("\\TOP_8x8_MULT_REG", pm.st.ffY ? State::S1 : State::S0); cell->setParam("\\TOP_8x8_MULT_REG", st.ffY ? State::S1 : State::S0);
cell->setParam("\\BOT_8x8_MULT_REG", pm.st.ffY ? State::S1 : State::S0); cell->setParam("\\BOT_8x8_MULT_REG", st.ffY ? State::S1 : State::S0);
cell->setParam("\\PIPELINE_16x16_MULT_REG1", pm.st.ffY ? State::S1 : State::S0); cell->setParam("\\PIPELINE_16x16_MULT_REG1", st.ffY ? State::S1 : State::S0);
cell->setParam("\\PIPELINE_16x16_MULT_REG2", State::S0); cell->setParam("\\PIPELINE_16x16_MULT_REG2", State::S0);
cell->setParam("\\TOPOUTPUT_SELECT", Const(pm.st.ffS ? 1 : 3, 2)); cell->setParam("\\TOPOUTPUT_SELECT", Const(st.ffS ? 1 : 3, 2));
cell->setParam("\\TOPADDSUB_LOWERINPUT", Const(2, 2)); cell->setParam("\\TOPADDSUB_LOWERINPUT", Const(2, 2));
cell->setParam("\\TOPADDSUB_UPPERINPUT", State::S0); cell->setParam("\\TOPADDSUB_UPPERINPUT", State::S0);
cell->setParam("\\TOPADDSUB_CARRYSELECT", Const(3, 2)); cell->setParam("\\TOPADDSUB_CARRYSELECT", Const(3, 2));
cell->setParam("\\BOTOUTPUT_SELECT", Const(pm.st.ffS ? 1 : 3, 2)); cell->setParam("\\BOTOUTPUT_SELECT", Const(st.ffS ? 1 : 3, 2));
cell->setParam("\\BOTADDSUB_LOWERINPUT", Const(2, 2)); cell->setParam("\\BOTADDSUB_LOWERINPUT", Const(2, 2));
cell->setParam("\\BOTADDSUB_UPPERINPUT", State::S0); cell->setParam("\\BOTADDSUB_UPPERINPUT", State::S0);
cell->setParam("\\BOTADDSUB_CARRYSELECT", Const(0, 2)); cell->setParam("\\BOTADDSUB_CARRYSELECT", Const(0, 2));
@ -198,9 +201,9 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
cell->setParam("\\A_SIGNED", mul_signed ? State::S1 : State::S0); cell->setParam("\\A_SIGNED", mul_signed ? State::S1 : State::S0);
cell->setParam("\\B_SIGNED", mul_signed ? State::S1 : State::S0); cell->setParam("\\B_SIGNED", mul_signed ? State::S1 : State::S0);
pm.autoremove(pm.st.mul); pm.autoremove(st.mul);
pm.autoremove(pm.st.ffY); pm.autoremove(st.ffY);
pm.autoremove(pm.st.ffS); pm.autoremove(st.ffS);
} }
struct Ice40DspPass : public Pass { struct Ice40DspPass : public Pass {
@ -230,7 +233,7 @@ struct Ice40DspPass : public Pass {
extra_args(args, argidx, design); extra_args(args, argidx, design);
for (auto module : design->selected_modules()) for (auto module : design->selected_modules())
ice40_dsp_pm(module, module->selected_cells()).run(create_ice40_dsp); ice40_dsp_pm(module, module->selected_cells()).run_ice40_dsp(create_ice40_dsp);
} }
} Ice40DspPass; } Ice40DspPass;

View File

@ -1,3 +1,5 @@
pattern ice40_dsp
state <SigBit> clock state <SigBit> clock
state <bool> clock_pol clock_vld state <bool> clock_pol clock_vld
state <SigSpec> sigA sigB sigY sigS state <SigSpec> sigA sigB sigY sigS

68
passes/pmgen/peepopt.cc Normal file
View File

@ -0,0 +1,68 @@
/*
* 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
bool did_something;
#include "passes/pmgen/peepopt_pm.h"
struct PeepoptPass : public Pass {
PeepoptPass() : Pass("peepopt", "collection of peephole optimizers") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" peepopt [options] [selection]\n");
log("\n");
log("This pass applies a collection of peephole optimizers to the current design.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing PEEPOPT pass (run peephole optimizers).\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);
for (auto module : design->selected_modules()) {
did_something = true;
while (did_something) {
did_something = false;
peepopt_pm pm(module, module->selected_cells());
pm.run_shiftmul();
pm.run_muldiv();
}
}
}
} PeepoptPass;
PRIVATE_NAMESPACE_END

View File

@ -0,0 +1,36 @@
pattern muldiv
state <SigSpec> t x y
match mul
select mul->type == $mul
select GetSize(port(mul, \A)) + GetSize(port(mul, \B)) <= GetSize(port(mul, \Y))
endmatch
code t x y
t = port(mul, \Y);
x = port(mul, \A);
y = port(mul, \B);
branch;
std::swap(x, y);
endcode
match div
select div->type.in($div)
index <SigSpec> port(div, \A) === t
index <SigSpec> port(div, \B) === x
endmatch
code
SigSpec div_y = port(div, \Y);
SigSpec val_y = y;
if (GetSize(div_y) != GetSize(val_y))
val_y.extend_u0(GetSize(div_y), param(div, \A_SIGNED).as_bool());
did_something = true;
log("muldiv pattern in %s: mul=%s, div=%s\n", log_id(module), log_id(mul), log_id(div));
module->connect(div_y, val_y);
autoremove(div);
reject;
endcode

View File

@ -0,0 +1,94 @@
pattern shiftmul
//
// Optimize mul+shift pairs that result from expressions such as foo[s*W+:W]
//
state <SigSpec> shamt
match shift
select shift->type.in($shift, $shiftx, $shr)
endmatch
code shamt
shamt = port(shift, \B);
if (shamt.empty())
reject;
if (shamt[GetSize(shamt)-1] == State::S0) {
do {
shamt.remove(GetSize(shamt)-1);
if (shamt.empty())
reject;
} while (shamt[GetSize(shamt)-1] == State::S0);
} else
if (shift->type.in($shift, $shiftx) && param(shift, \B_SIGNED).as_bool()) {
reject;
}
if (GetSize(shamt) > 20)
reject;
endcode
match mul
select mul->type.in($mul)
select port(mul, \A).is_fully_const() || port(mul, \B).is_fully_const()
index <SigSpec> port(mul, \Y) === shamt
endmatch
code
IdString const_factor_port = port(mul, \A).is_fully_const() ? \A : \B;
IdString const_factor_signed = const_factor_port == \A ? \A_SIGNED : \B_SIGNED;
Const const_factor_cnst = port(mul, const_factor_port).as_const();
int const_factor = const_factor_cnst.as_int();
if (GetSize(const_factor_cnst) == 0)
reject;
if (const_factor_cnst.bits[GetSize(const_factor_cnst)-1] != State::S0 &&
param(mul, const_factor_signed).as_bool())
reject;
if (GetSize(const_factor_cnst) > 20)
reject;
if (GetSize(port(shift, \Y)) > const_factor)
reject;
int factor_bits = ceil_log2(const_factor);
SigSpec mul_din = port(mul, const_factor_port == \A ? \B : \A);
if (GetSize(shamt) < factor_bits+GetSize(mul_din))
reject;
did_something = true;
log("shiftmul pattern in %s: shift=%s, mul=%s\n", log_id(module), log_id(shift), log_id(mul));
int new_const_factor = 1 << factor_bits;
SigSpec padding(State::Sx, new_const_factor-const_factor);
SigSpec old_a = port(shift, \A), new_a;
int trunc = 0;
if (GetSize(old_a) % const_factor != 0) {
trunc = const_factor - GetSize(old_a) % const_factor;
old_a.append(SigSpec(State::Sx, trunc));
}
for (int i = 0; i*const_factor < GetSize(old_a); i++) {
SigSpec slice = old_a.extract(i*const_factor, const_factor);
new_a.append(slice);
new_a.append(padding);
}
if (trunc > 0)
new_a.remove(GetSize(new_a)-trunc, trunc);
SigSpec new_b = {mul_din, SigSpec(State::S0, factor_bits)};
if (param(shift, \B_SIGNED).as_bool())
new_b.append(State::S0);
shift->setPort(\A, new_a);
shift->setParam(\A_WIDTH, GetSize(new_a));
shift->setPort(\B, new_b);
shift->setParam(\B_WIDTH, GetSize(new_b));
blacklist(shift);
reject;
endcode

View File

@ -3,15 +3,42 @@
import re import re
import sys import sys
import pprint import pprint
import getopt
pp = pprint.PrettyPrinter(indent=4) pp = pprint.PrettyPrinter(indent=4)
pmgfile = sys.argv[1] prefix = None
assert pmgfile.endswith(".pmg") pmgfiles = list()
prefix = pmgfile[0:-4] outfile = None
prefix = prefix.split('/')[-1] debug = False
outfile = sys.argv[2] genhdr = False
opts, args = getopt.getopt(sys.argv[1:], "p:o:dg")
for o, a in opts:
if o == "-p":
prefix = a
elif o == "-o":
outfile = a
elif o == "-d":
debug = True
elif o == "-g":
genhdr = True
if outfile is None:
outfile = "/dev/stdout"
for a in args:
assert a.endswith(".pmg")
if prefix is None and len(args) == 1:
prefix = a[0:-4]
prefix = prefix.split('/')[-1]
pmgfiles.append(a)
assert prefix is not None
current_pattern = None
patterns = dict()
state_types = dict() state_types = dict()
udata_types = dict() udata_types = dict()
blocks = list() blocks = list()
@ -77,7 +104,8 @@ def rewrite_cpp(s):
return "".join(t) return "".join(t)
with open(pmgfile, "r") as f: def process_pmgfile(f):
global current_pattern
while True: while True:
line = f.readline() line = f.readline()
if line == "": break if line == "": break
@ -87,14 +115,31 @@ with open(pmgfile, "r") as f:
if len(cmd) == 0 or cmd[0].startswith("//"): continue if len(cmd) == 0 or cmd[0].startswith("//"): continue
cmd = cmd[0] cmd = cmd[0]
if cmd == "pattern":
if current_pattern is not None:
block = dict()
block["type"] = "final"
block["pattern"] = current_pattern
blocks.append(block)
line = line.split()
assert len(line) == 2
assert line[1] not in patterns
current_pattern = line[1]
patterns[current_pattern] = len(blocks)
state_types[current_pattern] = dict()
udata_types[current_pattern] = dict()
continue
assert current_pattern is not None
if cmd == "state": if cmd == "state":
m = re.match(r"^state\s+<(.*?)>\s+(([A-Za-z_][A-Za-z_0-9]*\s+)*[A-Za-z_][A-Za-z_0-9]*)\s*$", line) m = re.match(r"^state\s+<(.*?)>\s+(([A-Za-z_][A-Za-z_0-9]*\s+)*[A-Za-z_][A-Za-z_0-9]*)\s*$", line)
assert m assert m
type_str = m.group(1) type_str = m.group(1)
states_str = m.group(2) states_str = m.group(2)
for s in re.split(r"\s+", states_str): for s in re.split(r"\s+", states_str):
assert s not in state_types assert s not in state_types[current_pattern]
state_types[s] = type_str state_types[current_pattern][s] = type_str
continue continue
if cmd == "udata": if cmd == "udata":
@ -103,19 +148,20 @@ with open(pmgfile, "r") as f:
type_str = m.group(1) type_str = m.group(1)
udatas_str = m.group(2) udatas_str = m.group(2)
for s in re.split(r"\s+", udatas_str): for s in re.split(r"\s+", udatas_str):
assert s not in udata_types assert s not in udata_types[current_pattern]
udata_types[s] = type_str udata_types[current_pattern][s] = type_str
continue continue
if cmd == "match": if cmd == "match":
block = dict() block = dict()
block["type"] = "match" block["type"] = "match"
block["pattern"] = current_pattern
line = line.split() line = line.split()
assert len(line) == 2 assert len(line) == 2
assert line[1] not in state_types assert line[1] not in state_types[current_pattern]
block["cell"] = line[1] block["cell"] = line[1]
state_types[line[1]] = "Cell*"; state_types[current_pattern][line[1]] = "Cell*";
block["if"] = list() block["if"] = list()
block["select"] = list() block["select"] = list()
@ -158,15 +204,18 @@ with open(pmgfile, "r") as f:
assert False assert False
blocks.append(block) blocks.append(block)
continue
if cmd == "code": if cmd == "code":
block = dict() block = dict()
block["type"] = "code" block["type"] = "code"
block["pattern"] = current_pattern
block["code"] = list() block["code"] = list()
block["states"] = set() block["states"] = set()
for s in line.split()[1:]: for s in line.split()[1:]:
assert s in state_types assert s in state_types[current_pattern]
block["states"].add(s) block["states"].add(s)
while True: while True:
@ -179,15 +228,34 @@ with open(pmgfile, "r") as f:
block["code"].append(rewrite_cpp(l.rstrip())) block["code"].append(rewrite_cpp(l.rstrip()))
blocks.append(block) blocks.append(block)
continue
assert False
for fn in pmgfiles:
with open(fn, "r") as f:
process_pmgfile(f)
if current_pattern is not None:
block = dict()
block["type"] = "final"
block["pattern"] = current_pattern
blocks.append(block)
current_pattern = None
if debug:
pp.pprint(blocks)
with open(outfile, "w") as f: with open(outfile, "w") as f:
print("// Generated by pmgen.py from {}.pgm".format(prefix), file=f) for fn in pmgfiles:
print("// Generated by pmgen.py from {}".format(fn), file=f)
print("", file=f) print("", file=f)
if genhdr:
print("#include \"kernel/yosys.h\"", file=f) print("#include \"kernel/yosys.h\"", file=f)
print("#include \"kernel/sigtools.h\"", file=f) print("#include \"kernel/sigtools.h\"", file=f)
print("", file=f) print("", file=f)
print("YOSYS_NAMESPACE_BEGIN", file=f) print("YOSYS_NAMESPACE_BEGIN", file=f)
print("", file=f) print("", file=f)
@ -212,17 +280,19 @@ with open(outfile, "w") as f:
print(" int rollback;", file=f) print(" int rollback;", file=f)
print("", file=f) print("", file=f)
print(" struct state_t {", file=f) for current_pattern in sorted(patterns.keys()):
for s, t in sorted(state_types.items()): print(" struct state_{}_t {{".format(current_pattern), file=f)
for s, t in sorted(state_types[current_pattern].items()):
print(" {} {};".format(t, s), file=f) print(" {} {};".format(t, s), file=f)
print(" } st;", file=f) print(" }} st_{};".format(current_pattern), file=f)
print("", file=f) print("", file=f)
print(" struct udata_t {", file=f) print(" struct udata_{}_t {{".format(current_pattern), file=f)
for s, t in sorted(udata_types.items()): for s, t in sorted(udata_types[current_pattern].items()):
print(" {} {};".format(t, s), file=f) print(" {} {};".format(t, s), file=f)
print(" } ud;", file=f) print(" }} ud_{};".format(current_pattern), file=f)
print("", file=f) print("", file=f)
current_pattern = None
for v, n in sorted(ids.items()): for v, n in sorted(ids.items()):
if n[0] == "\\": if n[0] == "\\":
@ -258,20 +328,24 @@ with open(outfile, "w") as f:
print(" }", file=f) print(" }", file=f)
print("", file=f) print("", file=f)
print(" void check_blacklist() {", file=f) for current_pattern in sorted(patterns.keys()):
print(" void check_blacklist_{}() {{".format(current_pattern), file=f)
print(" if (!blacklist_dirty)", file=f) print(" if (!blacklist_dirty)", file=f)
print(" return;", file=f) print(" return;", file=f)
print(" blacklist_dirty = false;", file=f) print(" blacklist_dirty = false;", file=f)
for index in range(len(blocks)): for index in range(len(blocks)):
block = blocks[index] block = blocks[index]
if block["pattern"] != current_pattern:
continue
if block["type"] == "match": if block["type"] == "match":
print(" if (st.{} != nullptr && blacklist_cells.count(st.{})) {{".format(block["cell"], block["cell"]), file=f) print(" if (st_{}.{} != nullptr && blacklist_cells.count(st_{}.{})) {{".format(current_pattern, block["cell"], current_pattern, block["cell"]), file=f)
print(" rollback = {};".format(index+1), file=f) print(" rollback = {};".format(index+1), file=f)
print(" return;", file=f) print(" return;", file=f)
print(" }", file=f) print(" }", file=f)
print(" rollback = 0;", file=f) print(" rollback = 0;", file=f)
print(" }", file=f) print(" }", file=f)
print("", file=f) print("", file=f)
current_pattern = None
print(" SigSpec port(Cell *cell, IdString portname) {", file=f) print(" SigSpec port(Cell *cell, IdString portname) {", file=f)
print(" return sigmap(cell->getPort(portname));", file=f) print(" return sigmap(cell->getPort(portname));", file=f)
@ -294,11 +368,13 @@ with open(outfile, "w") as f:
print(" {}_pm(Module *module, const vector<Cell*> &cells) :".format(prefix), file=f) print(" {}_pm(Module *module, const vector<Cell*> &cells) :".format(prefix), file=f)
print(" module(module), sigmap(module) {", file=f) print(" module(module), sigmap(module) {", file=f)
for s, t in sorted(udata_types.items()): for current_pattern in sorted(patterns.keys()):
for s, t in sorted(udata_types[current_pattern].items()):
if t.endswith("*"): if t.endswith("*"):
print(" ud.{} = nullptr;".format(s), file=f) print(" ud_{}.{} = nullptr;".format(current_pattern,s), file=f)
else: else:
print(" ud.{} = {}();".format(s, t), file=f) print(" ud_{}.{} = {}();".format(current_pattern, s, t), file=f)
current_pattern = None
print(" for (auto cell : module->cells()) {", file=f) print(" for (auto cell : module->cells()) {", file=f)
print(" for (auto &conn : cell->connections())", file=f) print(" for (auto &conn : cell->connections())", file=f)
print(" add_siguser(conn.second, cell);", file=f) print(" add_siguser(conn.second, cell);", file=f)
@ -328,34 +404,52 @@ with open(outfile, "w") as f:
print(" }", file=f) print(" }", file=f)
print("", file=f) print("", file=f)
print(" void run(std::function<void()> on_accept_f) {", file=f) for current_pattern in sorted(patterns.keys()):
print(" void run_{}(std::function<void()> on_accept_f) {{".format(current_pattern), file=f)
print(" on_accept = on_accept_f;", file=f) print(" on_accept = on_accept_f;", file=f)
print(" rollback = 0;", file=f) print(" rollback = 0;", file=f)
print(" blacklist_dirty = false;", file=f) print(" blacklist_dirty = false;", file=f)
for s, t in sorted(state_types.items()): for s, t in sorted(state_types[current_pattern].items()):
if t.endswith("*"): if t.endswith("*"):
print(" st.{} = nullptr;".format(s), file=f) print(" st_{}.{} = nullptr;".format(current_pattern, s), file=f)
else: else:
print(" st.{} = {}();".format(s, t), file=f) print(" st_{}.{} = {}();".format(current_pattern, s, t), file=f)
print(" block_0();", file=f) print(" block_{}();".format(patterns[current_pattern]), file=f)
print(" }", file=f) print(" }", file=f)
print("", file=f) print("", file=f)
print(" void run_{}(std::function<void({}_pm&)> on_accept_f) {{".format(current_pattern, prefix), file=f)
print(" void run(std::function<void({}_pm&)> on_accept_f) {{".format(prefix), file=f) print(" run_{}([&](){{on_accept_f(*this);}});".format(current_pattern), file=f)
print(" run([&](){on_accept_f(*this);});", file=f)
print(" }", file=f) print(" }", file=f)
print("", file=f) print("", file=f)
print(" void run_{}(std::function<void(state_{}_t&)> on_accept_f) {{".format(current_pattern, current_pattern), file=f)
print(" run_{}([&](){{on_accept_f(st_{});}});".format(current_pattern, current_pattern), file=f)
print(" }", file=f)
print("", file=f)
print(" void run_{}() {{".format(current_pattern), file=f)
print(" run_{}([](){{}});".format(current_pattern, current_pattern), file=f)
print(" }", file=f)
print("", file=f)
current_pattern = None
for index in range(len(blocks)): for index in range(len(blocks)):
block = blocks[index] block = blocks[index]
print(" void block_{}() {{".format(index), file=f) print(" void block_{}() {{".format(index), file=f)
current_pattern = block["pattern"]
if block["type"] == "final":
print(" on_accept();", file=f)
print(" check_blacklist_{}();".format(current_pattern), file=f)
print(" }", file=f)
if index+1 != len(blocks):
print("", file=f)
continue
const_st = set() const_st = set()
nonconst_st = set() nonconst_st = set()
restore_st = set() restore_st = set()
for i in range(index): for i in range(patterns[current_pattern], index):
if blocks[i]["type"] == "code": if blocks[i]["type"] == "code":
for s in blocks[i]["states"]: for s in blocks[i]["states"]:
const_st.add(s) const_st.add(s)
@ -378,27 +472,27 @@ with open(outfile, "w") as f:
assert False assert False
for s in sorted(const_st): for s in sorted(const_st):
t = state_types[s] t = state_types[current_pattern][s]
if t.endswith("*"): if t.endswith("*"):
print(" {} const &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f) print(" {} const &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f)
else: else:
print(" const {} &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f) print(" const {} &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f)
for s in sorted(nonconst_st): for s in sorted(nonconst_st):
t = state_types[s] t = state_types[current_pattern][s]
print(" {} &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f) print(" {} &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f)
if len(restore_st): if len(restore_st):
print("", file=f) print("", file=f)
for s in sorted(restore_st): for s in sorted(restore_st):
t = state_types[s] t = state_types[current_pattern][s]
print(" {} backup_{} = {};".format(t, s, s), file=f) print(" {} backup_{} = {};".format(t, s, s), file=f)
if block["type"] == "code": if block["type"] == "code":
print("", file=f) print("", file=f)
print(" do {", file=f) print(" do {", file=f)
print("#define reject do { check_blacklist(); goto rollback_label; } while(0)", file=f) print("#define reject do {{ check_blacklist_{}(); goto rollback_label; }} while(0)".format(current_pattern), file=f)
print("#define accept do { on_accept(); check_blacklist(); if (rollback) goto rollback_label; } while(0)", file=f) print("#define accept do {{ on_accept(); check_blacklist_{}(); if (rollback) goto rollback_label; }} while(0)".format(current_pattern), file=f)
print("#define branch do {{ block_{}(); if (rollback) goto rollback_label; }} while(0)".format(index+1), file=f) print("#define branch do {{ block_{}(); if (rollback) goto rollback_label; }} while(0)".format(index+1), file=f)
for line in block["code"]: for line in block["code"]:
@ -417,11 +511,11 @@ with open(outfile, "w") as f:
if len(restore_st) or len(nonconst_st): if len(restore_st) or len(nonconst_st):
print("", file=f) print("", file=f)
for s in sorted(restore_st): for s in sorted(restore_st):
t = state_types[s] t = state_types[current_pattern][s]
print(" {} = backup_{};".format(s, s), file=f) print(" {} = backup_{};".format(s, s), file=f)
for s in sorted(nonconst_st): for s in sorted(nonconst_st):
if s not in restore_st: if s not in restore_st:
t = state_types[s] t = state_types[current_pattern][s]
if t.endswith("*"): if t.endswith("*"):
print(" {} = nullptr;".format(s), file=f) print(" {} = nullptr;".format(s), file=f)
else: else:
@ -470,17 +564,12 @@ with open(outfile, "w") as f:
else: else:
assert False assert False
current_pattern = None
print(" }", file=f) print(" }", file=f)
print("", file=f) print("", file=f)
print(" void block_{}() {{".format(len(blocks)), file=f)
print(" on_accept();", file=f)
print(" check_blacklist();", file=f)
print(" }", file=f)
print("};", file=f) print("};", file=f)
if genhdr:
print("", file=f) print("", file=f)
print("YOSYS_NAMESPACE_END", file=f) print("YOSYS_NAMESPACE_END", file=f)
# pp.pprint(blocks)

View File

@ -508,7 +508,7 @@ struct ExposePass : public Pass {
} }
for (auto &conn : module->connections_) for (auto &conn : module->connections_)
conn.first = out_to_in_map(sigmap(conn.first)); conn.first = out_to_in_map(conn.first);
} }
if (flag_cut) if (flag_cut)

View File

@ -26,6 +26,8 @@ PRIVATE_NAMESPACE_BEGIN
struct opts_t struct opts_t
{ {
bool initeq = false;
bool anyeq = false;
bool fwd = false; bool fwd = false;
bool bwd = false; bool bwd = false;
bool nop = false; bool nop = false;
@ -56,7 +58,7 @@ struct FmcombineWorker
return newsig; return newsig;
} }
void import_prim_cell(Cell *cell, const string &suffix) Cell *import_prim_cell(Cell *cell, const string &suffix)
{ {
Cell *c = module->addCell(cell->name.str() + suffix, cell->type); Cell *c = module->addCell(cell->name.str() + suffix, cell->type);
c->parameters = cell->parameters; c->parameters = cell->parameters;
@ -64,6 +66,8 @@ struct FmcombineWorker
for (auto &conn : cell->connections()) for (auto &conn : cell->connections())
c->setPort(conn.first, import_sig(conn.second, suffix)); c->setPort(conn.first, import_sig(conn.second, suffix));
return c;
} }
void import_hier_cell(Cell *cell) void import_hier_cell(Cell *cell)
@ -102,8 +106,24 @@ struct FmcombineWorker
for (auto cell : original->cells()) { for (auto cell : original->cells()) {
if (design->module(cell->type) == nullptr) { if (design->module(cell->type) == nullptr) {
import_prim_cell(cell, "_gold"); if (opts.anyeq && cell->type.in("$anyseq", "$anyconst")) {
import_prim_cell(cell, "_gate"); Cell *gold = import_prim_cell(cell, "_gold");
for (auto &conn : cell->connections())
module->connect(import_sig(conn.second, "_gate"), gold->getPort(conn.first));
} else {
Cell *gold = import_prim_cell(cell, "_gold");
Cell *gate = import_prim_cell(cell, "_gate");
if (opts.initeq) {
if (cell->type.in("$ff", "$dff", "$dffe",
"$dffsr", "$adff", "$dlatch", "$dlatchsr")) {
SigSpec gold_q = gold->getPort("\\Q");
SigSpec gate_q = gate->getPort("\\Q");
SigSpec en = module->Initstate(NEW_ID);
SigSpec eq = module->Eq(NEW_ID, gold_q, gate_q);
module->addAssume(NEW_ID, eq, en);
}
}
}
} else { } else {
import_hier_cell(cell); import_hier_cell(cell);
} }
@ -229,6 +249,13 @@ struct FmcombinePass : public Pass {
log("This is useful for formal test benches that check what differences in behavior\n"); log("This is useful for formal test benches that check what differences in behavior\n");
log("a slight difference in input causes in a module.\n"); log("a slight difference in input causes in a module.\n");
log("\n"); log("\n");
log(" -initeq\n");
log(" Insert assumptions that initially all FFs in both circuits have the\n");
log(" same initial values.\n");
log("\n");
log(" -anyeq\n");
log(" Do not duplicate $anyseq/$anyconst cells.\n");
log("\n");
log(" -fwd\n"); log(" -fwd\n");
log(" Insert forward hint assumptions into the combined module.\n"); log(" Insert forward hint assumptions into the combined module.\n");
log("\n"); log("\n");
@ -261,6 +288,14 @@ struct FmcombinePass : public Pass {
// filename = args[++argidx]; // filename = args[++argidx];
// continue; // continue;
// } // }
if (args[argidx] == "-initeq") {
opts.initeq = true;
continue;
}
if (args[argidx] == "-anyeq") {
opts.anyeq = true;
continue;
}
if (args[argidx] == "-fwd") { if (args[argidx] == "-fwd") {
opts.fwd = true; opts.fwd = true;
continue; continue;
@ -297,7 +332,7 @@ struct FmcombinePass : public Pass {
gate_cell = module->cell(gate_name); gate_cell = module->cell(gate_name);
if (gate_cell == nullptr) if (gate_cell == nullptr)
log_cmd_error("Gold cell %s not found in module %s.\n", log_id(gate_name), log_id(module)); log_cmd_error("Gate cell %s not found in module %s.\n", log_id(gate_name), log_id(module));
} }
else else
{ {
@ -316,7 +351,7 @@ struct FmcombinePass : public Pass {
if (!gold_cell->parameters.empty()) if (!gold_cell->parameters.empty())
log_cmd_error("Gold cell has unresolved instance parameters.\n"); log_cmd_error("Gold cell has unresolved instance parameters.\n");
if (!gate_cell->parameters.empty()) if (!gate_cell->parameters.empty())
log_cmd_error("Gold cell has unresolved instance parameters.\n"); log_cmd_error("Gate cell has unresolved instance parameters.\n");
FmcombineWorker worker(design, gold_cell->type, opts); FmcombineWorker worker(design, gold_cell->type, opts);
worker.generate(); worker.generate();

View File

@ -1169,6 +1169,7 @@ struct SatPass : public Pass {
if (args[argidx] == "-tempinduct-def") { if (args[argidx] == "-tempinduct-def") {
tempinduct = true; tempinduct = true;
tempinduct_def = true; tempinduct_def = true;
enable_undef = true;
continue; continue;
} }
if (args[argidx] == "-tempinduct-baseonly") { if (args[argidx] == "-tempinduct-baseonly") {

View File

@ -88,6 +88,8 @@ struct SimInstance
SimInstance(SimShared *shared, Module *module, Cell *instance = nullptr, SimInstance *parent = nullptr) : SimInstance(SimShared *shared, Module *module, Cell *instance = nullptr, SimInstance *parent = nullptr) :
shared(shared), module(module), instance(instance), parent(parent), sigmap(module) shared(shared), module(module), instance(instance), parent(parent), sigmap(module)
{ {
log_assert(module);
if (parent) { if (parent) {
log_assert(parent->children.count(instance) == 0); log_assert(parent->children.count(instance) == 0);
parent->children[instance] = this; parent->children[instance] = this;
@ -848,6 +850,9 @@ struct SimPass : public Pass {
if (design->full_selection()) { if (design->full_selection()) {
top_mod = design->top_module(); top_mod = design->top_module();
if (!top_mod)
log_cmd_error("Design has no top module, use the 'hierarchy' command to specify one.\n");
} else { } else {
auto mods = design->selected_whole_modules(); auto mods = design->selected_whole_modules();
if (GetSize(mods) != 1) if (GetSize(mods) != 1)

View File

@ -330,20 +330,33 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr) std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr)
{ {
std::string abc_sname = abc_name.substr(1); std::string abc_sname = abc_name.substr(1);
if (abc_sname.substr(0, 5) == "ys__n") { bool isnew = false;
bool inv = abc_sname.back() == 'v'; if (abc_sname.substr(0, 4) == "new_")
if (inv) abc_sname.pop_back(); {
abc_sname.erase(0, 4);
isnew = true;
}
if (abc_sname.substr(0, 5) == "ys__n")
{
abc_sname.erase(0, 5); abc_sname.erase(0, 5);
if (abc_sname.find_last_not_of("012345689") == std::string::npos) { if (std::isdigit(abc_sname.at(0)))
{
int sid = std::stoi(abc_sname); int sid = std::stoi(abc_sname);
for (auto sig : signal_list) { size_t postfix_start = abc_sname.find_first_not_of("0123456789");
if (sig.id == sid && sig.bit.wire != nullptr) { std::string postfix = postfix_start != std::string::npos ? abc_sname.substr(postfix_start) : "";
if (sid < GetSize(signal_list))
{
auto sig = signal_list.at(sid);
if (sig.bit.wire != nullptr)
{
std::stringstream sstr; std::stringstream sstr;
sstr << "$abc$" << map_autoidx << "$" << sig.bit.wire->name.substr(1); sstr << "$abc$" << map_autoidx << "$" << sig.bit.wire->name.substr(1);
if (sig.bit.wire->width != 1) if (sig.bit.wire->width != 1)
sstr << "[" << sig.bit.offset << "]"; sstr << "[" << sig.bit.offset << "]";
if (inv) if (isnew)
sstr << "_inv"; sstr << "_new";
sstr << postfix;
if (orig_wire != nullptr) if (orig_wire != nullptr)
*orig_wire = sig.bit.wire; *orig_wire = sig.bit.wire;
return sstr.str(); return sstr.str();

View File

@ -102,6 +102,7 @@ struct DffinitPass : public Pass {
if (wire->attributes.count("\\init")) { if (wire->attributes.count("\\init")) {
Const value = wire->attributes.at("\\init"); Const value = wire->attributes.at("\\init");
for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++)
if (value[i] != State::Sx)
init_bits[sigmap(SigBit(wire, i))] = value[i]; init_bits[sigmap(SigBit(wire, i))] = value[i];
} }
if (wire->port_output) if (wire->port_output)

View File

@ -397,7 +397,6 @@ struct FlowGraph
pool<RTLIL::SigBit> x, xi; pool<RTLIL::SigBit> x, xi;
NodePrime source_prime = {source, true}; NodePrime source_prime = {source, true};
NodePrime sink_prime = {sink, false};
pool<NodePrime> visited; pool<NodePrime> visited;
vector<NodePrime> worklist = {source_prime}; vector<NodePrime> worklist = {source_prime};
while (!worklist.empty()) while (!worklist.empty())
@ -1382,7 +1381,8 @@ struct FlowmapWorker
vector<RTLIL::SigBit> input_nodes(lut_edges_bw[node].begin(), lut_edges_bw[node].end()); vector<RTLIL::SigBit> input_nodes(lut_edges_bw[node].begin(), lut_edges_bw[node].end());
RTLIL::Const lut_table(State::Sx, max(1 << input_nodes.size(), 1 << minlut)); RTLIL::Const lut_table(State::Sx, max(1 << input_nodes.size(), 1 << minlut));
for (unsigned i = 0; i < (1 << input_nodes.size()); i++) unsigned const mask = 1 << input_nodes.size();
for (unsigned i = 0; i < mask; i++)
{ {
ce.push(); ce.push();
for (size_t n = 0; n < input_nodes.size(); n++) for (size_t n = 0; n < input_nodes.size(); n++)

View File

@ -94,7 +94,7 @@ int LibertyParser::lexer(std::string &str)
// search for identifiers, numbers, plus or minus. // search for identifiers, numbers, plus or minus.
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') { if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') {
str = c; str = static_cast<char>(c);
while (1) { while (1) {
c = f.get(); c = f.get();
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.')

View File

@ -58,12 +58,21 @@ struct MuxcoverWorker
bool use_mux16; bool use_mux16;
bool nodecode; bool nodecode;
int cost_mux2;
int cost_mux4;
int cost_mux8;
int cost_mux16;
MuxcoverWorker(Module *module) : module(module), sigmap(module) MuxcoverWorker(Module *module) : module(module), sigmap(module)
{ {
use_mux4 = false; use_mux4 = false;
use_mux8 = false; use_mux8 = false;
use_mux16 = false; use_mux16 = false;
nodecode = false; nodecode = false;
cost_mux2 = COST_MUX2;
cost_mux4 = COST_MUX4;
cost_mux8 = COST_MUX8;
cost_mux16 = COST_MUX16;
decode_mux_counter = 0; decode_mux_counter = 0;
} }
@ -157,7 +166,7 @@ struct MuxcoverWorker
if (std::get<2>(entry)) if (std::get<2>(entry))
return 0; return 0;
return COST_MUX2 / GetSize(std::get<1>(entry)); return cost_mux2 / GetSize(std::get<1>(entry));
} }
void implement_decode_mux(SigBit ctrl_bit) void implement_decode_mux(SigBit ctrl_bit)
@ -209,7 +218,7 @@ struct MuxcoverWorker
mux.inputs.push_back(B); mux.inputs.push_back(B);
mux.selects.push_back(S1); mux.selects.push_back(S1);
mux.cost += COST_MUX2; mux.cost += cost_mux2;
mux.cost += find_best_cover(tree, A); mux.cost += find_best_cover(tree, A);
mux.cost += find_best_cover(tree, B); mux.cost += find_best_cover(tree, B);
@ -247,7 +256,7 @@ struct MuxcoverWorker
mux.selects.push_back(S1); mux.selects.push_back(S1);
mux.selects.push_back(T1); mux.selects.push_back(T1);
mux.cost += COST_MUX4; mux.cost += cost_mux4;
mux.cost += find_best_cover(tree, A); mux.cost += find_best_cover(tree, A);
mux.cost += find_best_cover(tree, B); mux.cost += find_best_cover(tree, B);
mux.cost += find_best_cover(tree, C); mux.cost += find_best_cover(tree, C);
@ -310,7 +319,7 @@ struct MuxcoverWorker
mux.selects.push_back(T1); mux.selects.push_back(T1);
mux.selects.push_back(U1); mux.selects.push_back(U1);
mux.cost += COST_MUX8; mux.cost += cost_mux8;
mux.cost += find_best_cover(tree, A); mux.cost += find_best_cover(tree, A);
mux.cost += find_best_cover(tree, B); mux.cost += find_best_cover(tree, B);
mux.cost += find_best_cover(tree, C); mux.cost += find_best_cover(tree, C);
@ -414,7 +423,7 @@ struct MuxcoverWorker
mux.selects.push_back(U1); mux.selects.push_back(U1);
mux.selects.push_back(V1); mux.selects.push_back(V1);
mux.cost += COST_MUX16; mux.cost += cost_mux16;
mux.cost += find_best_cover(tree, A); mux.cost += find_best_cover(tree, A);
mux.cost += find_best_cover(tree, B); mux.cost += find_best_cover(tree, B);
mux.cost += find_best_cover(tree, C); mux.cost += find_best_cover(tree, C);
@ -569,9 +578,11 @@ struct MuxcoverPass : public Pass {
log("\n"); log("\n");
log("Cover trees of $_MUX_ cells with $_MUX{4,8,16}_ cells\n"); log("Cover trees of $_MUX_ cells with $_MUX{4,8,16}_ cells\n");
log("\n"); log("\n");
log(" -mux4, -mux8, -mux16\n"); log(" -mux4[=cost], -mux8[=cost], -mux16[=cost]\n");
log(" Use the specified types of MUXes. If none of those options are used,\n"); log(" Use the specified types of MUXes (with optional integer costs). If none\n");
log(" the effect is the same as if all of them where used.\n"); log(" of these options are given, the effect is the same as if all of them are.\n");
log(" Default costs: $_MUX_ = %d, $_MUX4_ = %d,\n", COST_MUX2, COST_MUX4);
log(" $_MUX8_ = %d, $_MUX16_ = %d\n", COST_MUX8, COST_MUX16);
log("\n"); log("\n");
log(" -nodecode\n"); log(" -nodecode\n");
log(" Do not insert decoder logic. This reduces the number of possible\n"); log(" Do not insert decoder logic. This reduces the number of possible\n");
@ -587,23 +598,39 @@ struct MuxcoverPass : public Pass {
bool use_mux8 = false; bool use_mux8 = false;
bool use_mux16 = false; bool use_mux16 = false;
bool nodecode = false; bool nodecode = false;
int cost_mux4 = COST_MUX4;
int cost_mux8 = COST_MUX8;
int cost_mux16 = COST_MUX16;
size_t argidx; size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) for (argidx = 1; argidx < args.size(); argidx++)
{ {
if (args[argidx] == "-mux4") { const auto &arg = args[argidx];
if (arg.size() >= 5 && arg.substr(0,5) == "-mux4") {
use_mux4 = true; use_mux4 = true;
if (arg.size() > 5) {
if (arg[5] != '=') break;
cost_mux4 = atoi(arg.substr(5).c_str());
}
continue; continue;
} }
if (args[argidx] == "-mux8") { if (arg.size() >= 5 && arg.substr(0,5) == "-mux8") {
use_mux8 = true; use_mux8 = true;
if (arg.size() > 5) {
if (arg[5] != '=') break;
cost_mux8 = atoi(arg.substr(5).c_str());
}
continue; continue;
} }
if (args[argidx] == "-mux16") { if (arg.size() >= 6 && arg.substr(0,6) == "-mux16") {
use_mux16 = true; use_mux16 = true;
if (arg.size() > 6) {
if (arg[6] != '=') break;
cost_mux16 = atoi(arg.substr(6).c_str());
}
continue; continue;
} }
if (args[argidx] == "-nodecode") { if (arg == "-nodecode") {
nodecode = true; nodecode = true;
continue; continue;
} }
@ -623,6 +650,9 @@ struct MuxcoverPass : public Pass {
worker.use_mux4 = use_mux4; worker.use_mux4 = use_mux4;
worker.use_mux8 = use_mux8; worker.use_mux8 = use_mux8;
worker.use_mux16 = use_mux16; worker.use_mux16 = use_mux16;
worker.cost_mux4 = cost_mux4;
worker.cost_mux8 = cost_mux8;
worker.cost_mux16 = cost_mux16;
worker.nodecode = nodecode; worker.nodecode = nodecode;
worker.run(); worker.run();
} }

View File

@ -178,7 +178,17 @@ struct ShregmapTechXilinx7 : ShregmapTech
// Only map if $shiftx exclusively covers the shift register // Only map if $shiftx exclusively covers the shift register
if (shiftx->type == "$shiftx") { if (shiftx->type == "$shiftx") {
if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int()) if (GetSize(taps) > shiftx->getParam("\\A_WIDTH").as_int())
return false;
// Due to padding the most significant bits of A may be 1'bx,
// and if so, discount them
if (GetSize(taps) < shiftx->getParam("\\A_WIDTH").as_int()) {
const SigSpec A = shiftx->getPort("\\A");
const int A_width = shiftx->getParam("\\A_WIDTH").as_int();
for (int i = GetSize(taps); i < A_width; ++i)
if (A[i] != RTLIL::Sx) return false;
}
else if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int())
return false; return false;
} }
else if (shiftx->type == "$mux") { else if (shiftx->type == "$mux") {
@ -596,6 +606,9 @@ struct ShregmapPass : public Pass {
log(" -tech greenpak4\n"); log(" -tech greenpak4\n");
log(" map to greenpak4 shift registers.\n"); log(" map to greenpak4 shift registers.\n");
log("\n"); log("\n");
log(" -tech xilinx\n");
log(" map to xilinx dynamic-length shift registers.\n");
log("\n");
} }
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{ {

View File

@ -46,7 +46,7 @@ struct ZinitPass : public Pass {
size_t argidx; size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) for (argidx = 1; argidx < args.size(); argidx++)
{ {
if (args[argidx] == "-singleton") { if (args[argidx] == "-all") {
all_mode = true; all_mode = true;
continue; continue;
} }

View File

@ -195,9 +195,11 @@ struct PrepPass : public ScriptPass
run(nokeepdc ? "opt" : "opt -keepdc"); run(nokeepdc ? "opt" : "opt -keepdc");
if (!ifxmode) { if (!ifxmode) {
if (help_mode) if (help_mode)
run("wreduce [-memx]"); run("wreduce -keepdc [-memx]");
else else if (nokeepdc)
run(memxmode ? "wreduce -memx" : "wreduce"); run(memxmode ? "wreduce -memx" : "wreduce");
else
run(memxmode ? "wreduce -keepdc -memx" : "wreduce -keepdc");
} }
if (!nomemmode) { if (!nomemmode) {
run(string("memory_dff") + (help_mode ? " [-nordff]" : nordff ? " -nordff" : "")); run(string("memory_dff") + (help_mode ? " [-nordff]" : nordff ? " -nordff" : ""));

View File

@ -1271,6 +1271,181 @@ endmodule
// -------------------------------------------------------- // --------------------------------------------------------
module \$specify2 (EN, SRC, DST);
parameter FULL = 0;
parameter SRC_WIDTH = 1;
parameter DST_WIDTH = 1;
parameter SRC_DST_PEN = 0;
parameter SRC_DST_POL = 0;
parameter T_RISE_MIN = 0;
parameter T_RISE_TYP = 0;
parameter T_RISE_MAX = 0;
parameter T_FALL_MIN = 0;
parameter T_FALL_TYP = 0;
parameter T_FALL_MAX = 0;
input EN;
input [SRC_WIDTH-1:0] SRC;
input [DST_WIDTH-1:0] DST;
localparam SD = SRC_DST_PEN ? (SRC_DST_POL ? 1 : 2) : 0;
`ifdef SIMLIB_SPECIFY
specify
if (EN && SD==0 && !FULL) (SRC => DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && SD==0 && FULL) (SRC *> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && SD==1 && !FULL) (SRC +=> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && SD==1 && FULL) (SRC +*> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && SD==2 && !FULL) (SRC -=> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && SD==2 && FULL) (SRC -*> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
endspecify
`endif
endmodule
// --------------------------------------------------------
module \$specify3 (EN, SRC, DST, DAT);
parameter FULL = 0;
parameter SRC_WIDTH = 1;
parameter DST_WIDTH = 1;
parameter EDGE_EN = 0;
parameter EDGE_POL = 0;
parameter SRC_DST_PEN = 0;
parameter SRC_DST_POL = 0;
parameter DAT_DST_PEN = 0;
parameter DAT_DST_POL = 0;
parameter T_RISE_MIN = 0;
parameter T_RISE_TYP = 0;
parameter T_RISE_MAX = 0;
parameter T_FALL_MIN = 0;
parameter T_FALL_TYP = 0;
parameter T_FALL_MAX = 0;
input EN;
input [SRC_WIDTH-1:0] SRC;
input [DST_WIDTH-1:0] DST, DAT;
localparam ED = EDGE_EN ? (EDGE_POL ? 1 : 2) : 0;
localparam SD = SRC_DST_PEN ? (SRC_DST_POL ? 1 : 2) : 0;
localparam DD = DAT_DST_PEN ? (DAT_DST_POL ? 1 : 2) : 0;
`ifdef SIMLIB_SPECIFY
specify
// DD=0
if (EN && DD==0 && SD==0 && ED==0 && !FULL) ( SRC => (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==0 && ED==0 && FULL) ( SRC *> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==0 && ED==1 && !FULL) (posedge SRC => (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==0 && ED==1 && FULL) (posedge SRC *> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==0 && ED==2 && !FULL) (negedge SRC => (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==0 && ED==2 && FULL) (negedge SRC *> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==1 && ED==0 && !FULL) ( SRC +=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==1 && ED==0 && FULL) ( SRC +*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==1 && ED==1 && FULL) (posedge SRC +*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==1 && ED==2 && FULL) (negedge SRC +*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==2 && ED==0 && !FULL) ( SRC -=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==2 && ED==0 && FULL) ( SRC -*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==2 && ED==1 && FULL) (posedge SRC -*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==2 && ED==2 && FULL) (negedge SRC -*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
// DD=1
if (EN && DD==1 && SD==0 && ED==0 && !FULL) ( SRC => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==0 && ED==0 && FULL) ( SRC *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==0 && ED==1 && !FULL) (posedge SRC => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==0 && ED==1 && FULL) (posedge SRC *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==0 && ED==2 && !FULL) (negedge SRC => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==0 && ED==2 && FULL) (negedge SRC *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==1 && ED==0 && !FULL) ( SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==1 && ED==0 && FULL) ( SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==1 && ED==1 && FULL) (posedge SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==1 && ED==2 && FULL) (negedge SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==2 && ED==0 && !FULL) ( SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==2 && ED==0 && FULL) ( SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==2 && ED==1 && FULL) (posedge SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==2 && ED==2 && FULL) (negedge SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
// DD=2
if (EN && DD==2 && SD==0 && ED==0 && !FULL) ( SRC => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==0 && ED==0 && FULL) ( SRC *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==0 && ED==1 && !FULL) (posedge SRC => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==0 && ED==1 && FULL) (posedge SRC *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==0 && ED==2 && !FULL) (negedge SRC => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==0 && ED==2 && FULL) (negedge SRC *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==1 && ED==0 && !FULL) ( SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==1 && ED==0 && FULL) ( SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==1 && ED==1 && FULL) (posedge SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==1 && ED==2 && FULL) (negedge SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==2 && ED==0 && !FULL) ( SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==2 && ED==0 && FULL) ( SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==2 && ED==1 && FULL) (posedge SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==2 && ED==2 && FULL) (negedge SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
endspecify
`endif
endmodule
// --------------------------------------------------------
module \$specrule (EN_SRC, EN_DST, SRC, DST);
parameter TYPE = "";
parameter T_LIMIT = 0;
parameter T_LIMIT2 = 0;
parameter SRC_WIDTH = 1;
parameter DST_WIDTH = 1;
parameter SRC_PEN = 0;
parameter SRC_POL = 0;
parameter DST_PEN = 0;
parameter DST_POL = 0;
input EN_SRC, EN_DST;
input [SRC_WIDTH-1:0] SRC;
input [DST_WIDTH-1:0] DST;
`ifdef SIMLIB_SPECIFY
specify
// TBD
endspecify
`endif
endmodule
// --------------------------------------------------------
module \$assert (A, EN); module \$assert (A, EN);
input A, EN; input A, EN;
@ -1863,4 +2038,5 @@ end
endmodule endmodule
`endif `endif
// -------------------------------------------------------- // --------------------------------------------------------

View File

@ -209,6 +209,8 @@ struct SynthPass : public ScriptPass
run("check"); run("check");
run("opt"); run("opt");
run("wreduce"); run("wreduce");
run("peepopt");
run("opt_clean");
if (help_mode) if (help_mode)
run("techmap -map +/cmp2lut.v", " (if -lut)"); run("techmap -map +/cmp2lut.v", " (if -lut)");
else else

View File

@ -47,6 +47,21 @@ module \$__DFFSE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"
module \$__DFFSE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFSE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFSE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFSE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
// Diamond I/O buffers
module IB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
module IBPU (input I, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
module IBPD (input I, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
module OB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I)); endmodule
module OBZ (input I, T, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule
module OBZPU(input I, T, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule
module OBZPD(input I, T, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule
module OBCO (input I, output OT, OC); OLVDS _TECHMAP_REPLACE_ (.A(I), .Z(OT), .ZN(OC)); endmodule
module BB (input I, T, output O, inout B); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule
module BBPU (input I, T, output O, inout B); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule
module BBPD (input I, T, output O, inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule
module ILVDS(input A, AN, output Z); TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(A), .O(Z)); endmodule
module OLVDS(input A, output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(Z), .I(A)); endmodule
// For Diamond compatibility, FIXME: add all Diamond flipflop mappings // For Diamond compatibility, FIXME: add all Diamond flipflop mappings
module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule

View File

@ -253,7 +253,7 @@ struct SynthEcp5Pass : public ScriptPass
if (!nodffe) if (!nodffe)
run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*"); run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*");
run("techmap -D NO_LUT -map +/ecp5/cells_map.v"); run("techmap -D NO_LUT -map +/ecp5/cells_map.v");
run("opt_expr -mux_undef"); run("opt_expr -undriven -mux_undef");
run("simplemap"); run("simplemap");
run("ecp5_ffinit"); run("ecp5_ffinit");
} }

View File

@ -957,10 +957,21 @@ endmodule
(* blackbox *) (* blackbox *)
module SB_HFOSC( module SB_HFOSC(
input TRIM0,
input TRIM1,
input TRIM2,
input TRIM3,
input TRIM4,
input TRIM5,
input TRIM6,
input TRIM7,
input TRIM8,
input TRIM9,
input CLKHFPU, input CLKHFPU,
input CLKHFEN, input CLKHFEN,
output CLKHF output CLKHF
); );
parameter TRIM_EN = "0b0";
parameter CLKHF_DIV = "0b00"; parameter CLKHF_DIV = "0b00";
endmodule endmodule
@ -989,6 +1000,30 @@ parameter RGB1_CURRENT = "0b000000";
parameter RGB2_CURRENT = "0b000000"; parameter RGB2_CURRENT = "0b000000";
endmodule endmodule
(* blackbox *)
module SB_LED_DRV_CUR(
input EN,
output LEDPU
);
endmodule
(* blackbox *)
module SB_RGB_DRV(
input RGBLEDEN,
input RGB0PWM,
input RGB1PWM,
input RGB2PWM,
input RGBPU,
output RGB0,
output RGB1,
output RGB2
);
parameter CURRENT_MODE = "0b0";
parameter RGB0_CURRENT = "0b000000";
parameter RGB1_CURRENT = "0b000000";
parameter RGB2_CURRENT = "0b000000";
endmodule
(* blackbox *) (* blackbox *)
module SB_I2C( module SB_I2C(
input SBCLKI, input SBCLKI,

View File

@ -245,12 +245,14 @@ struct SynthIce40Pass : public ScriptPass
run("proc"); run("proc");
} }
if (flatten && check_label("flatten", "(unless -noflatten)")) if (check_label("flatten", "(unless -noflatten)"))
{ {
if (flatten) {
run("flatten"); run("flatten");
run("tribuf -logic"); run("tribuf -logic");
run("deminout"); run("deminout");
} }
}
if (check_label("coarse")) if (check_label("coarse"))
{ {
@ -259,6 +261,8 @@ struct SynthIce40Pass : public ScriptPass
run("check"); run("check");
run("opt"); run("opt");
run("wreduce"); run("wreduce");
run("peepopt");
run("opt_clean");
run("share"); run("share");
run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4"); run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4");
run("opt_expr"); run("opt_expr");

View File

@ -17,10 +17,10 @@
* *
*/ */
#include "kernel/register.h"
#include "kernel/celltypes.h" #include "kernel/celltypes.h"
#include "kernel/rtlil.h"
#include "kernel/log.h" #include "kernel/log.h"
#include "kernel/register.h"
#include "kernel/rtlil.h"
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN PRIVATE_NAMESPACE_BEGIN
@ -38,7 +38,7 @@ struct SynthIntelPass : public ScriptPass {
log("\n"); log("\n");
log(" -family < max10 | a10gx | cyclone10 | cyclonev | cycloneiv | cycloneive>\n"); log(" -family < max10 | a10gx | cyclone10 | cyclonev | cycloneiv | cycloneive>\n");
log(" generate the synthesis netlist for the specified family.\n"); log(" generate the synthesis netlist for the specified family.\n");
log(" MAX10 is the default target if no family argument specified.\n"); log(" MAX10 is the default target if not family argument specified.\n");
log(" For Cyclone GX devices, use cycloneiv argument; For Cyclone E, use cycloneive.\n"); log(" For Cyclone GX devices, use cycloneiv argument; For Cyclone E, use cycloneive.\n");
log(" Cyclone V and Arria 10 GX devices are experimental, use it with a10gx argument.\n"); log(" Cyclone V and Arria 10 GX devices are experimental, use it with a10gx argument.\n");
log("\n"); log("\n");
@ -97,8 +97,7 @@ struct SynthIntelPass : public ScriptPass {
clear_flags(); clear_flags();
size_t argidx; size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) for (argidx = 1; argidx < args.size(); argidx++) {
{
if (args[argidx] == "-family" && argidx + 1 < args.size()) { if (args[argidx] == "-family" && argidx + 1 < args.size()) {
family_opt = args[++argidx]; family_opt = args[++argidx];
continue; continue;
@ -145,8 +144,9 @@ struct SynthIntelPass : public ScriptPass {
if (!design->full_selection()) if (!design->full_selection())
log_cmd_error("This command only operates on fully selected designs!\n"); log_cmd_error("This command only operates on fully selected designs!\n");
if (family_opt != "max10" && family_opt !="a10gx" && family_opt != "cyclonev" && family_opt !="cycloneiv" && family_opt !="cycloneive" && family_opt != "cyclone10") if (family_opt != "max10" && family_opt != "a10gx" && family_opt != "cyclonev" && family_opt != "cycloneiv" &&
log_cmd_error("Invalid or no family specified: '%s'\n", family_opt.c_str()); family_opt != "cycloneive" && family_opt != "cyclone10")
log_cmd_error("Invalid or not family specified: '%s'\n", family_opt.c_str());
log_header(design, "Executing SYNTH_INTEL pass.\n"); log_header(design, "Executing SYNTH_INTEL pass.\n");
log_push(); log_push();
@ -158,8 +158,7 @@ struct SynthIntelPass : public ScriptPass {
void script() YS_OVERRIDE void script() YS_OVERRIDE
{ {
if (check_label("begin")) if (check_label("begin")) {
{
if (check_label("family") && family_opt == "max10") if (check_label("family") && family_opt == "max10")
run("read_verilog -sv -lib +/intel/max10/cells_sim.v"); run("read_verilog -sv -lib +/intel/max10/cells_sim.v");
else if (check_label("family") && family_opt == "a10gx") else if (check_label("family") && family_opt == "a10gx")
@ -178,27 +177,23 @@ struct SynthIntelPass : public ScriptPass {
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str())); run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
} }
if (flatten && check_label("flatten", "(unless -noflatten)")) if (flatten && check_label("flatten", "(unless -noflatten)")) {
{
run("proc"); run("proc");
run("flatten"); run("flatten");
run("tribuf -logic"); run("tribuf -logic");
run("deminout"); run("deminout");
} }
if (check_label("coarse")) if (check_label("coarse")) {
{
run("synth -run coarse"); run("synth -run coarse");
} }
if (!nobram && check_label("bram", "(skip if -nobram)")) if (!nobram && check_label("bram", "(skip if -nobram)")) {
{
run("memory_bram -rules +/intel/common/brams.txt"); run("memory_bram -rules +/intel/common/brams.txt");
run("techmap -map +/intel/common/brams_map.v"); run("techmap -map +/intel/common/brams_map.v");
} }
if (check_label("fine")) if (check_label("fine")) {
{
run("opt -fast -mux_undef -undriven -fine -full"); run("opt -fast -mux_undef -undriven -fine -full");
run("memory_map"); run("memory_map");
run("opt -undriven -fine"); run("opt -undriven -fine");
@ -213,8 +208,7 @@ struct SynthIntelPass : public ScriptPass {
run("abc -markgroups -dff", "(only if -retime)"); run("abc -markgroups -dff", "(only if -retime)");
} }
if (check_label("map_luts")) if (check_label("map_luts")) {
{
if (family_opt == "a10gx" || family_opt == "cyclonev") if (family_opt == "a10gx" || family_opt == "cyclonev")
run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : "")); run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : ""));
else else
@ -222,8 +216,7 @@ struct SynthIntelPass : public ScriptPass {
run("clean"); run("clean");
} }
if (check_label("map_cells")) if (check_label("map_cells")) {
{
if (!noiopads) if (!noiopads)
run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(unless -noiopads)"); run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(unless -noiopads)");
if (family_opt == "max10") if (family_opt == "max10")
@ -242,24 +235,20 @@ struct SynthIntelPass : public ScriptPass {
run("clean -purge"); run("clean -purge");
} }
if (check_label("check")) if (check_label("check")) {
{
run("hierarchy -check"); run("hierarchy -check");
run("stat"); run("stat");
run("check -noinit"); run("check -noinit");
} }
if (check_label("vqm")) if (check_label("vqm")) {
{
if (!vout_file.empty() || help_mode) if (!vout_file.empty() || help_mode)
run(stringf("write_verilog -attr2comment -defparam -nohex -decimal -renameprefix syn_ %s", run(stringf("write_verilog -attr2comment -defparam -nohex -decimal -renameprefix syn_ %s",
help_mode ? "<file-name>" : vout_file.c_str())); help_mode ? "<file-name>" : vout_file.c_str()));
} }
if (check_label("vpr")) if (check_label("vpr")) {
{ if (!blif_file.empty() || help_mode) {
if (!blif_file.empty() || help_mode)
{
run(stringf("opt_clean -purge")); run(stringf("opt_clean -purge"));
run(stringf("write_blif %s", help_mode ? "<file-name>" : blif_file.c_str())); run(stringf("write_blif %s", help_mode ? "<file-name>" : blif_file.c_str()));
} }

View File

@ -17,6 +17,16 @@
* *
*/ */
// Convert negative-polarity reset to positive-polarity
(* techmap_celltype = "$_DFF_NN0_" *)
module _90_dff_nn0_to_np0 (input D, C, R, output Q); \$_DFF_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
(* techmap_celltype = "$_DFF_PN0_" *)
module _90_dff_pn0_to_pp0 (input D, C, R, output Q); \$_DFF_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
(* techmap_celltype = "$_DFF_NN1_" *)
module _90_dff_nn1_to_np1 (input D, C, R, output Q); \$_DFF_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
(* techmap_celltype = "$_DFF_PN1_" *)
module _90_dff_pn1_to_pp1 (input D, C, R, output Q); \$_DFF_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
module \$__SHREG_ (input C, input D, input E, output Q); module \$__SHREG_ (input C, input D, input E, output Q);
parameter DEPTH = 0; parameter DEPTH = 0;
parameter [DEPTH-1:0] INIT = 0; parameter [DEPTH-1:0] INIT = 0;

View File

@ -26,11 +26,15 @@ bram $__XILINX_RAM128X1D
endbram endbram
match $__XILINX_RAM64X1D match $__XILINX_RAM64X1D
min bits 5
min wports 1
make_outreg make_outreg
or_next_if_better or_next_if_better
endmatch endmatch
match $__XILINX_RAM128X1D match $__XILINX_RAM128X1D
min bits 9
min wports 1
make_outreg make_outreg
endmatch endmatch

View File

@ -22,26 +22,21 @@
`ifndef _NO_FFS `ifndef _NO_FFS
`ifndef _NO_POS_SR
module \$_DFF_N_ (input D, C, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule module \$_DFF_N_ (input D, C, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule
module \$_DFF_P_ (input D, C, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule module \$_DFF_P_ (input D, C, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule
module \$_DFFE_NP_ (input D, C, E, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule module \$_DFFE_NP_ (input D, C, E, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule
module \$_DFFE_PP_ (input D, C, E, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule module \$_DFFE_PP_ (input D, C, E, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule
module \$_DFF_NN0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule
module \$_DFF_NP0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule module \$_DFF_NP0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule
module \$_DFF_PN0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule
module \$_DFF_PP0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule module \$_DFF_PP0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule
module \$_DFF_NN1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule
module \$_DFF_NP1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule module \$_DFF_NP1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule
module \$_DFF_PN1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule
module \$_DFF_PP1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule module \$_DFF_PP1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule
`endif
module \$_DFF_NN0_ (input D, C, R, output Q); \$_DFF_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
module \$_DFF_PN0_ (input D, C, R, output Q); \$_DFF_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
module \$_DFF_NN1_ (input D, C, R, output Q); \$_DFF_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
module \$_DFF_PN1_ (input D, C, R, output Q); \$_DFF_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
`endif
`endif `endif

View File

@ -25,18 +25,9 @@
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN PRIVATE_NAMESPACE_BEGIN
bool check_label(bool &active, std::string run_from, std::string run_to, std::string label) struct SynthXilinxPass : public ScriptPass
{ {
if (label == run_from) SynthXilinxPass() : ScriptPass("synth_xilinx", "synthesis for Xilinx FPGAs") { }
active = true;
if (label == run_to)
active = false;
return active;
}
struct SynthXilinxPass : public Pass
{
SynthXilinxPass() : Pass("synth_xilinx", "synthesis for Xilinx FPGAs") { }
void help() YS_OVERRIDE void help() YS_OVERRIDE
{ {
@ -51,6 +42,10 @@ struct SynthXilinxPass : public Pass
log(" -top <module>\n"); log(" -top <module>\n");
log(" use the specified module as top module\n"); log(" use the specified module as top module\n");
log("\n"); log("\n");
log(" -arch {xcup|xcu|xc7|xc6s}\n");
log(" run synthesis for the specified Xilinx architecture\n");
log(" default: xc7\n");
log("\n");
log(" -edif <file>\n"); log(" -edif <file>\n");
log(" write the design to the specified edif file. writing of an output file\n"); log(" write the design to the specified edif file. writing of an output file\n");
log(" is omitted if this parameter is not specified.\n"); log(" is omitted if this parameter is not specified.\n");
@ -63,6 +58,9 @@ struct SynthXilinxPass : public Pass
log(" generate an output netlist (and BLIF file) suitable for VPR\n"); log(" generate an output netlist (and BLIF file) suitable for VPR\n");
log(" (this feature is experimental and incomplete)\n"); log(" (this feature is experimental and incomplete)\n");
log("\n"); log("\n");
log(" -nocarry\n");
log(" disable inference of carry chains\n");
log("\n");
log(" -nobram\n"); log(" -nobram\n");
log(" disable inference of block rams\n"); log(" disable inference of block rams\n");
log("\n"); log("\n");
@ -72,6 +70,9 @@ struct SynthXilinxPass : public Pass
log(" -nosrl\n"); log(" -nosrl\n");
log(" disable inference of shift registers\n"); log(" disable inference of shift registers\n");
log("\n"); log("\n");
log(" -nomux\n");
log(" disable inference of wide multiplexers\n");
log("\n");
log(" -run <from_label>:<to_label>\n"); log(" -run <from_label>:<to_label>\n");
log(" only run the commands between the labels (see below). an empty\n"); log(" only run the commands between the labels (see below). an empty\n");
log(" from label is synonymous to 'begin', and empty to label is\n"); log(" from label is synonymous to 'begin', and empty to label is\n");
@ -88,80 +89,34 @@ struct SynthXilinxPass : public Pass
log("\n"); log("\n");
log("\n"); log("\n");
log("The following commands are executed by this synthesis command:\n"); log("The following commands are executed by this synthesis command:\n");
log("\n"); help_script();
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(" hierarchy -check -top <top>\n");
log("\n");
log(" flatten: (only if -flatten)\n");
log(" proc\n");
log(" flatten\n");
log("\n");
log(" coarse:\n");
log(" synth -run coarse\n");
log("\n");
log(" bram: (only executed when '-nobram' is not given)\n");
log(" memory_bram -rules +/xilinx/brams.txt\n");
log(" techmap -map +/xilinx/brams_map.v\n");
log("\n");
log(" dram: (only executed when '-nodram' is not given)\n");
log(" memory_bram -rules +/xilinx/drams.txt\n");
log(" techmap -map +/xilinx/drams_map.v\n");
log("\n");
log(" fine:\n");
log(" opt -fast\n");
log(" memory_map\n");
log(" dffsr2dff\n");
log(" dff2dffe\n");
log(" techmap -map +/xilinx/arith_map.v\n");
log(" opt -fast\n");
log("\n");
log(" map_cells:\n");
log(" simplemap t:$dff t:$dffe (without '-nosrl' only)\n");
log(" pmux2shiftx (without '-nosrl' only)\n");
log(" opt_expr -mux_undef (without '-nosrl' only)\n");
log(" shregmap -tech xilinx -minlen 3 (without '-nosrl' only)\n");
log(" techmap -map +/xilinx/cells_map.v\n");
log(" clean\n");
log("\n");
log(" map_luts:\n");
log(" opt -full\n");
log(" techmap -map +/techmap.v -D _NO_POS_SR -map +/xilinx/ff_map.v\n");
log(" abc -luts 2:2,3,6:5,10,20 [-dff]\n");
log(" clean\n");
log(" shregmap -minlen 3 -init -params -enpol any_or_none (without '-nosrl' only)\n");
log(" techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v");
log(" dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT \\\n");
log(" -ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT\n");
log(" clean\n");
log("\n");
log(" check:\n");
log(" hierarchy -check\n");
log(" stat\n");
log(" check -noinit\n");
log("\n");
log(" edif: (only if -edif)\n");
log(" write_edif <file-name>\n");
log("\n");
log(" blif: (only if -blif)\n");
log(" write_blif <file-name>\n");
log("\n"); log("\n");
} }
std::string top_opt, edif_file, blif_file, abc, arch;
bool flatten, retime, vpr, nocarry, nobram, nodram, nosrl, nomux;
void clear_flags() YS_OVERRIDE
{
top_opt = "-auto-top";
edif_file.clear();
blif_file.clear();
abc = "abc";
flatten = false;
retime = false;
vpr = false;
nocarry = false;
nobram = false;
nodram = false;
nosrl = false;
nomux = false;
arch = "xc7";
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{ {
std::string top_opt = "-auto-top";
std::string edif_file;
std::string blif_file;
std::string run_from, run_to; std::string run_from, run_to;
std::string abc = "abc"; clear_flags();
bool flatten = false;
bool retime = false;
bool vpr = false;
bool nobram = false;
bool nodram = false;
bool nosrl = false;
size_t argidx; size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) for (argidx = 1; argidx < args.size(); argidx++)
@ -170,6 +125,10 @@ struct SynthXilinxPass : public Pass
top_opt = "-top " + args[++argidx]; top_opt = "-top " + args[++argidx];
continue; continue;
} }
if (args[argidx] == "-arch" && argidx+1 < args.size()) {
arch = args[++argidx];
continue;
}
if (args[argidx] == "-edif" && argidx+1 < args.size()) { if (args[argidx] == "-edif" && argidx+1 < args.size()) {
edif_file = args[++argidx]; edif_file = args[++argidx];
continue; continue;
@ -198,6 +157,10 @@ struct SynthXilinxPass : public Pass
vpr = true; vpr = true;
continue; continue;
} }
if (args[argidx] == "-nocarry") {
nocarry = true;
continue;
}
if (args[argidx] == "-nobram") { if (args[argidx] == "-nobram") {
nobram = true; nobram = true;
continue; continue;
@ -210,6 +173,10 @@ struct SynthXilinxPass : public Pass
nosrl = true; nosrl = true;
continue; continue;
} }
if (args[argidx] == "-nomux") {
nomux = true;
continue;
}
if (args[argidx] == "-abc9") { if (args[argidx] == "-abc9") {
abc = "abc9"; abc = "abc9";
continue; continue;
@ -218,132 +185,151 @@ struct SynthXilinxPass : public Pass
} }
extra_args(args, argidx, design); extra_args(args, argidx, design);
if (arch != "xcup" && arch != "xcu" && arch != "xc7" && arch != "xc6s")
log_cmd_error("Invalid Xilinx -arch setting: %s\n", arch.c_str());
if (!design->full_selection()) if (!design->full_selection())
log_cmd_error("This command only operates on fully selected designs!\n"); log_cmd_error("This command only operates on fully selected designs!\n");
bool active = run_from.empty();
log_header(design, "Executing SYNTH_XILINX pass.\n"); log_header(design, "Executing SYNTH_XILINX pass.\n");
log_push(); log_push();
if (check_label(active, run_from, run_to, "begin")) run_script(design, run_from, run_to);
{
if (vpr) {
Pass::call(design, "read_verilog -lib -D_EXPLICIT_CARRY +/xilinx/cells_sim.v");
} else {
Pass::call(design, "read_verilog -lib +/xilinx/cells_sim.v");
}
Pass::call(design, "read_verilog -lib +/xilinx/cells_xtra.v");
if (!nobram) {
Pass::call(design, "read_verilog -lib +/xilinx/brams_bb.v");
}
Pass::call(design, stringf("hierarchy -check %s", top_opt.c_str()));
}
if (flatten && check_label(active, run_from, run_to, "flatten"))
{
Pass::call(design, "proc");
Pass::call(design, "flatten");
}
if (check_label(active, run_from, run_to, "coarse"))
{
Pass::call(design, "synth -run coarse");
}
if (check_label(active, run_from, run_to, "bram"))
{
if (!nobram) {
Pass::call(design, "memory_bram -rules +/xilinx/brams.txt");
Pass::call(design, "techmap -map +/xilinx/brams_map.v");
}
}
if (check_label(active, run_from, run_to, "dram"))
{
if (!nodram) {
Pass::call(design, "memory_bram -rules +/xilinx/drams.txt");
Pass::call(design, "techmap -map +/xilinx/drams_map.v");
}
}
if (check_label(active, run_from, run_to, "fine"))
{
Pass::call(design, "opt -fast");
Pass::call(design, "memory_map");
Pass::call(design, "dffsr2dff");
Pass::call(design, "dff2dffe");
if (vpr) {
Pass::call(design, "techmap -map +/xilinx/arith_map.v -D _EXPLICIT_CARRY");
} else {
Pass::call(design, "techmap -map +/xilinx/arith_map.v");
}
Pass::call(design, "hierarchy -check");
Pass::call(design, "opt -fast");
}
if (check_label(active, run_from, run_to, "map_cells"))
{
if (!nosrl) {
// shregmap operates on bit-level flops, not word-level,
// so break those down here
Pass::call(design, "simplemap t:$dff t:$dffe");
// shregmap -tech xilinx can cope with $shiftx and $mux
// cells for identifiying variable-length shift registers,
// so attempt to convert $pmux-es to the former
Pass::call(design, "pmux2shiftx");
// pmux2shiftx can leave behind a $pmux with a single entry
// -- need this to clean that up before shregmap
Pass::call(design, "opt_expr -mux_undef");
// shregmap with '-tech xilinx' infers variable length shift regs
Pass::call(design, "shregmap -tech xilinx -minlen 3");
}
Pass::call(design, "techmap -map +/xilinx/cells_map.v");
Pass::call(design, "clean");
}
if (check_label(active, run_from, run_to, "map_luts"))
{
Pass::call(design, "opt -full");
Pass::call(design, "techmap -map +/techmap.v -D _NO_POS_SR -map +/xilinx/ff_map.v");
Pass::call(design, abc + " -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : ""));
Pass::call(design, "clean");
// This shregmap call infers fixed length shift registers after abc
// has performed any necessary retiming
if (!nosrl)
Pass::call(design, "shregmap -minlen 3 -init -params -enpol any_or_none");
Pass::call(design, "techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v");
Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
"-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT");
Pass::call(design, "clean");
}
if (check_label(active, run_from, run_to, "check"))
{
Pass::call(design, "hierarchy -check");
Pass::call(design, "stat");
Pass::call(design, "check -noinit");
}
if (check_label(active, run_from, run_to, "edif"))
{
if (!edif_file.empty())
Pass::call(design, stringf("write_edif -pvector bra %s", edif_file.c_str()));
}
if (check_label(active, run_from, run_to, "blif"))
{
if (!blif_file.empty())
Pass::call(design, stringf("write_blif %s", edif_file.c_str()));
}
log_pop(); log_pop();
} }
void script() YS_OVERRIDE
{
if (check_label("begin")) {
if (vpr)
run("read_verilog -lib -D _ABC -D_EXPLICIT_CARRY +/xilinx/cells_sim.v");
else
run("read_verilog -lib -D _ABC +/xilinx/cells_sim.v");
run("read_verilog -lib +/xilinx/cells_xtra.v");
if (!nobram || help_mode)
run("read_verilog -lib +/xilinx/brams_bb.v", "(skip if '-nobram')");
run(stringf("hierarchy -check %s", top_opt.c_str()));
}
if (check_label("flatten", "(with '-flatten' only)")) {
if (flatten || help_mode) {
run("proc");
run("flatten");
}
}
if (check_label("coarse")) {
run("synth -run coarse");
//if (!nomux || help_mode)
// run("muxpack", "(skip if '-nomux')");
// shregmap -tech xilinx can cope with $shiftx and $mux
// cells for identifying variable-length shift registers,
// so attempt to convert $pmux-es to the former
// Also: wide multiplexer inference benefits from this too
if (!(nosrl && nomux) || help_mode)
run("pmux2shiftx", "(skip if '-nosrl' and '-nomux')");
// Run a number of peephole optimisations, including one
// that optimises $mul cells driving $shiftx's B input
// and that aids wide mux analysis
run("peepopt");
}
if (check_label("bram", "(skip if '-nobram')")) {
if (!nobram || help_mode) {
run("memory_bram -rules +/xilinx/brams.txt");
run("techmap -map +/xilinx/brams_map.v");
}
}
if (check_label("dram", "(skip if '-nodram')")) {
if (!nodram || help_mode) {
run("memory_bram -rules +/xilinx/drams.txt");
run("techmap -map +/xilinx/drams_map.v");
}
}
if (check_label("fine")) {
run("opt -fast -full");
run("memory_map");
run("dffsr2dff");
run("dff2dffe");
run("opt -full");
if (!nosrl || help_mode) {
// shregmap operates on bit-level flops, not word-level,
// so break those down here
run("simplemap t:$dff t:$dffe", "(skip if '-nosrl')");
// shregmap with '-tech xilinx' infers variable length shift regs
run("shregmap -tech xilinx -minlen 3", "(skip if '-nosrl')");
}
std::string techmap_files = " -map +/techmap.v";
if (help_mode)
techmap_files += " [-map +/xilinx/mux_map.v]";
else if (!nomux)
techmap_files += " -map +/xilinx/mux_map.v";
if (help_mode)
techmap_files += " [-map +/xilinx/arith_map.v]";
else if (!nocarry) {
techmap_files += " -map +/xilinx/arith_map.v";
if (vpr)
techmap_files += " -D _EXPLICIT_CARRY";
else if (abc == "abc9")
techmap_files += " -D _CLB_CARRY";
}
run("techmap " + techmap_files);
run("opt -fast");
}
if (check_label("map_cells")) {
if (!nomux || help_mode)
run("muxcover -mux8 -mux16", "(skip if '-nomux')");
run("techmap -map +/techmap.v -map +/xilinx/cells_map.v");
run("clean");
}
if (check_label("map_luts")) {
if (abc == "abc9")
run(abc + " -lut +/xilinx/abc.lut -box +/xilinx/abc.box -W 160" + string(retime ? " -dff" : ""));
else if (help_mode)
run(abc + " -luts 2:2,3,6:5,10,20 [-dff]");
else
run(abc + " -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : ""));
run("clean");
// This shregmap call infers fixed length shift registers after abc
// has performed any necessary retiming
if (!nosrl || help_mode)
run("shregmap -minlen 3 -init -params -enpol any_or_none", "(skip if '-nosrl')");
run("techmap -map +/xilinx/lut_map.v -map +/xilinx/cells_map.v -map +/xilinx/ff_map.v");
run("dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
"-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT");
run("clean");
}
if (check_label("check")) {
run("hierarchy -check");
run("stat -tech xilinx");
run("check -noinit");
}
if (check_label("edif")) {
if (!edif_file.empty() || help_mode)
run(stringf("write_edif -pvector bra %s", edif_file.c_str()));
}
if (check_label("blif")) {
if (!blif_file.empty() || help_mode)
run(stringf("write_blif %s", edif_file.c_str()));
}
}
} SynthXilinxPass; } SynthXilinxPass;
PRIVATE_NAMESPACE_END PRIVATE_NAMESPACE_END

View File

@ -1,3 +0,0 @@
aig 3 2 0 1 1
6


View File

@ -3,3 +3,6 @@ aag 3 2 0 1 1
4 4
6 6
6 2 4 6 2 4
i0 pi0
i1 pi1
o0 po0

5
tests/aiger/and_.aig Normal file
View File

@ -0,0 +1,5 @@
aig 3 2 0 1 1
6
i0 pi0
i1 pi1
o0 po0

View File

@ -1,3 +1,5 @@
aag 1 1 0 1 0 aag 1 1 0 1 0
2 2
2 2
i0 pi0
o0 po0

View File

@ -1,2 +1,4 @@
aig 1 1 0 1 0 aig 1 1 0 1 0
2 2
i0 pi0
o0 po0

View File

@ -1,3 +1,4 @@
aag 1 0 1 0 0 1 aag 1 0 1 0 0 1
2 3 2 3
2 2
b0 po0

View File

@ -1,3 +1,4 @@
aig 1 0 1 0 0 1 aig 1 0 1 0 0 1
3 3
2 2
b0 po0

View File

@ -6,3 +6,4 @@ aag 5 1 1 0 3 1
8 4 2 8 4 2
10 9 7 10 9 7
b0 AIGER_NEVER b0 AIGER_NEVER
i0 po0

View File

@ -1,4 +1,5 @@
aig 5 1 1 0 3 1 aig 5 1 1 0 3 1
10 10
4 4
b0 AIGER_NEVER i0 po0
b0 AIGER_NEVER

View File

@ -1,2 +1,3 @@
aag 0 0 0 1 0 aag 0 0 0 1 0
0 0
o0 po0

View File

@ -1,2 +1,3 @@
aig 0 0 0 1 0 aig 0 0 0 1 0
0 0
o0 po0

View File

@ -1,3 +1,5 @@
aag 1 1 0 1 0 aag 1 1 0 1 0
2 2
3 3
i0 pi0
o0 po0

View File

@ -1,2 +1,4 @@
aig 1 1 0 1 0 aig 1 1 0 1 0
3 3
i0 pi0
o0 po0

View File

@ -6,3 +6,4 @@ aag 5 1 1 0 3 1
8 4 2 8 4 2
10 9 7 10 9 7
b0 AIGER_NEVER b0 AIGER_NEVER
i0 pi0

View File

@ -1,4 +1,5 @@
aig 5 1 1 0 3 1 aig 5 1 1 0 3 1
10 10
5 5
b0 AIGER_NEVER i0 pi0
b0 AIGER_NEVER

View File

@ -1,3 +0,0 @@
aig 3 2 0 1 1
7


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