mirror of https://github.com/YosysHQ/yosys.git
Merge remote-tracking branch 'origin/master' into xaig
This commit is contained in:
commit
f7a9769c14
|
@ -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
|
|
@ -4,6 +4,7 @@
|
|||
*.gch
|
||||
*.gcda
|
||||
*.gcno
|
||||
__pycache__
|
||||
/.cproject
|
||||
/.project
|
||||
/.settings
|
||||
|
@ -28,6 +29,8 @@
|
|||
/yosys-smtbmc-script.py
|
||||
/yosys-filterlib
|
||||
/yosys-filterlib.exe
|
||||
/kernel/*.pyh
|
||||
/kernel/python_wrappers.cc
|
||||
/kernel/version_*.cc
|
||||
/share
|
||||
/yosys-win32-mxebin-*
|
||||
|
|
|
@ -16,6 +16,7 @@ Yosys 0.8 .. Yosys 0.8-dev
|
|||
- Added "gate2lut.v" techmap rule
|
||||
- Added "rename -src"
|
||||
- Added "equiv_opt" pass
|
||||
- Added "read_aiger" frontend
|
||||
- "synth_xilinx" to now infer hard shift registers, using new "shregmap -tech xilinx"
|
||||
|
||||
|
||||
|
|
88
Makefile
88
Makefile
|
@ -2,6 +2,7 @@
|
|||
CONFIG := clang
|
||||
# CONFIG := gcc
|
||||
# CONFIG := gcc-4.8
|
||||
# CONFIG := afl-gcc
|
||||
# CONFIG := emcc
|
||||
# CONFIG := mxe
|
||||
# CONFIG := msys2
|
||||
|
@ -21,11 +22,6 @@ ENABLE_PROTOBUF := 0
|
|||
|
||||
# python wrappers
|
||||
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
|
||||
ENABLE_GCOV := 0
|
||||
|
@ -50,6 +46,10 @@ OS := $(shell uname -s)
|
|||
PREFIX ?= /usr/local
|
||||
INSTALL_SUDO :=
|
||||
|
||||
ifneq ($(wildcard Makefile.conf),)
|
||||
include Makefile.conf
|
||||
endif
|
||||
|
||||
BINDIR := $(PREFIX)/bin
|
||||
LIBDIR := $(PREFIX)/lib
|
||||
DATDIR := $(PREFIX)/share/yosys
|
||||
|
@ -89,6 +89,9 @@ PLUGIN_LDFLAGS += -undefined dynamic_lookup
|
|||
# homebrew search paths
|
||||
ifneq ($(shell which brew),)
|
||||
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
|
||||
LDFLAGS += -L$(BREW_PREFIX)/readline/lib
|
||||
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
|
||||
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)
|
||||
CXX = clang
|
||||
LD = clang++
|
||||
|
@ -185,6 +203,12 @@ LD = gcc-4.8
|
|||
CXXFLAGS += -std=c++11 -Os
|
||||
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)
|
||||
CXX = gcc
|
||||
LD = gcc
|
||||
|
@ -272,29 +296,50 @@ endif
|
|||
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
|
||||
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 \
|
||||
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$(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 \
|
||||
echo ""; fi; fi; fi; fi;)
|
||||
endif
|
||||
|
||||
ifeq ($(BOOST_PYTHON_LIB),)
|
||||
$(error BOOST_PYTHON_LIB could not be detected. Please define manualy)
|
||||
endif
|
||||
|
||||
ifeq ($(OS), Darwin)
|
||||
ifeq ($(PYTHON_MAJOR_VERSION),3)
|
||||
LDLIBS += `$(PYTHON_EXECUTABLE)-config --libs` $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
|
||||
CXXFLAGS += `$(PYTHON_EXECUTABLE)-config --includes` -D WITH_PYTHON
|
||||
LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --ldflags) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
|
||||
CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON
|
||||
else
|
||||
LDLIBS += `$(PYTHON_EXECUTABLE)-config --libs` $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
|
||||
CXXFLAGS += `$(PYTHON_EXECUTABLE)-config --includes` -D WITH_PYTHON
|
||||
LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --ldflags) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
|
||||
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
|
||||
|
||||
ifeq ($(ENABLE_PYOSYS),1)
|
||||
PY_WRAPPER_FILE = kernel/python_wrappers
|
||||
OBJS += $(PY_WRAPPER_FILE).o
|
||||
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
|
||||
|
||||
ifeq ($(ENABLE_READLINE),1)
|
||||
|
@ -540,7 +585,11 @@ yosys$(EXE): $(OBJS)
|
|||
$(P) $(LD) -o yosys$(EXE) $(LDFLAGS) $(OBJS) $(LDLIBS)
|
||||
|
||||
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)
|
||||
endif
|
||||
|
||||
%.o: %.cc
|
||||
$(Q) mkdir -p $(dir $@)
|
||||
|
@ -550,9 +599,11 @@ libyosys.so: $(filter-out kernel/driver.o,$(OBJS))
|
|||
$(Q) mkdir -p $(dir $@)
|
||||
$(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 $@)
|
||||
$(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
|
||||
$(Q) mkdir -p $(dir $@)
|
||||
|
@ -679,13 +730,13 @@ endif
|
|||
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR)
|
||||
$(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/.
|
||||
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) ldconfig
|
||||
ifeq ($(ENABLE_PYOSYS),1)
|
||||
$(INSTALL_SUDO) mkdir -p $(PYTHON_DESTDIR)/pyosys
|
||||
$(INSTALL_SUDO) cp libyosys.so $(PYTHON_DESTDIR)/pyosys
|
||||
$(INSTALL_SUDO) cp __init__.py $(PYTHON_DESTDIR)/pyosys
|
||||
$(INSTALL_SUDO) cp libyosys.so $(PYTHON_DESTDIR)/pyosys/
|
||||
$(INSTALL_SUDO) cp misc/__init__.py $(PYTHON_DESTDIR)/pyosys/
|
||||
endif
|
||||
endif
|
||||
|
||||
|
@ -787,6 +838,9 @@ config-gcc-static: clean
|
|||
config-gcc-4.8: clean
|
||||
echo 'CONFIG := gcc-4.8' > Makefile.conf
|
||||
|
||||
config-afl-gcc: clean
|
||||
echo 'CONFIG := afl-gcc' > Makefile.conf
|
||||
|
||||
config-emcc: clean
|
||||
echo 'CONFIG := emcc' > Makefile.conf
|
||||
echo 'ENABLE_TCL := 0' >> Makefile.conf
|
||||
|
@ -833,5 +887,5 @@ echo-git-rev:
|
|||
-include techlibs/*/*.d
|
||||
|
||||
.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
|
||||
|
||||
|
|
28
README.md
28
README.md
|
@ -257,13 +257,9 @@ for them:
|
|||
- Non-synthesizable language features as defined in
|
||||
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 ``disable``, ``primitive`` and ``specify`` statements
|
||||
|
||||
- Latched logic (is synthesized as logic with feedback loops)
|
||||
- The ``config`` and ``disable`` keywords and library map files
|
||||
|
||||
|
||||
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
|
||||
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) """
|
||||
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'
|
||||
|
||||
- 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``
|
||||
|
||||
- The system tasks ``$finish`` and ``$display`` are supported in initial blocks
|
||||
in an unconditional context (only if/case statements on parameters
|
||||
and constant values). The intended use for this is synthesis-time DRC.
|
||||
- The system tasks ``$finish``, ``$stop`` and ``$display`` are supported in
|
||||
initial blocks in an unconditional context (only if/case statements on
|
||||
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
|
||||
|
@ -457,7 +459,7 @@ Non-standard or SystemVerilog features for formal verification
|
|||
supported in any clocked block.
|
||||
|
||||
- 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>``
|
||||
is marked with the ``(* gclk *)`` Verilog attribute.
|
||||
|
||||
|
@ -470,7 +472,7 @@ from SystemVerilog:
|
|||
|
||||
- The ``assert`` statement from SystemVerilog is supported in its most basic
|
||||
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
|
||||
also supported. The same limitations as with the ``assert`` statement apply.
|
||||
|
|
|
@ -409,12 +409,26 @@ struct BlifDumper
|
|||
|
||||
f << stringf(".%s %s", subckt_or_gate(cell->type.str()), cstr(cell->type));
|
||||
for (auto &conn : cell->connections())
|
||||
for (int i = 0; i < conn.second.size(); i++) {
|
||||
if (conn.second.size() == 1)
|
||||
f << stringf(" %s", cstr(conn.first));
|
||||
else
|
||||
f << stringf(" %s[%d]", cstr(conn.first), i);
|
||||
f << stringf("=%s", cstr(conn.second.extract(i, 1)));
|
||||
{
|
||||
if (conn.second.size() == 1) {
|
||||
f << stringf(" %s=%s", cstr(conn.first), cstr(conn.second[0]));
|
||||
continue;
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
|
|
|
@ -129,7 +129,13 @@ struct BtorWorker
|
|||
|
||||
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);
|
||||
btorf_push(log_id(cell));
|
||||
|
||||
|
|
|
@ -146,7 +146,7 @@ struct FirrtlWorker
|
|||
if (!mask.is_fully_def())
|
||||
this->ena = SigSpec(RTLIL::Const(1));
|
||||
}
|
||||
string gen_read(const char * /* indent */) {
|
||||
string gen_read(const char * /* indent */) {
|
||||
log_error("gen_read called on write_port: %s\n", name.c_str());
|
||||
return stringf("gen_read called on write_port: %s\n", name.c_str());
|
||||
}
|
||||
|
@ -163,31 +163,61 @@ struct FirrtlWorker
|
|||
}
|
||||
};
|
||||
/* Memories defined within this module. */
|
||||
struct memory {
|
||||
string name; // memory name
|
||||
int abits; // number of address bits
|
||||
int size; // size (in units) of the memory
|
||||
int width; // size (in bits) of each element
|
||||
int read_latency;
|
||||
int write_latency;
|
||||
vector<read_port> read_ports;
|
||||
vector<write_port> write_ports;
|
||||
std::string init_file;
|
||||
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("") {}
|
||||
memory() : read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){}
|
||||
void add_memory_read_port(read_port &rp) {
|
||||
read_ports.push_back(rp);
|
||||
}
|
||||
void add_memory_write_port(write_port &wp) {
|
||||
write_ports.push_back(wp);
|
||||
}
|
||||
void add_memory_file(std::string init_file, std::string init_file_srcFileSpec) {
|
||||
this->init_file = init_file;
|
||||
this->init_file_srcFileSpec = init_file_srcFileSpec;
|
||||
struct memory {
|
||||
Cell *pCell; // for error reporting
|
||||
string name; // memory name
|
||||
int abits; // number of address bits
|
||||
int size; // size (in units) of the memory
|
||||
int width; // size (in bits) of each element
|
||||
int read_latency;
|
||||
int write_latency;
|
||||
vector<read_port> read_ports;
|
||||
vector<write_port> write_ports;
|
||||
std::string init_file;
|
||||
std::string init_file_srcFileSpec;
|
||||
string srcLine;
|
||||
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) {
|
||||
read_ports.push_back(rp);
|
||||
}
|
||||
void add_memory_write_port(write_port &wp) {
|
||||
write_ports.push_back(wp);
|
||||
}
|
||||
void add_memory_file(std::string init_file, std::string init_file_srcFileSpec) {
|
||||
this->init_file = init_file;
|
||||
this->init_file_srcFileSpec = init_file_srcFileSpec;
|
||||
}
|
||||
|
||||
};
|
||||
dict<string, memory> memories;
|
||||
|
||||
void register_memory(memory &m)
|
||||
|
@ -314,6 +344,7 @@ struct FirrtlWorker
|
|||
switch (dir) {
|
||||
case FD_INOUT:
|
||||
log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second));
|
||||
/* FALLTHRU */
|
||||
case FD_OUT:
|
||||
sourceExpr = firstName;
|
||||
sinkExpr = secondExpr;
|
||||
|
@ -321,7 +352,7 @@ struct FirrtlWorker
|
|||
break;
|
||||
case FD_NODIRECTION:
|
||||
log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second));
|
||||
/* FALL_THROUGH */
|
||||
/* FALLTHRU */
|
||||
case FD_IN:
|
||||
sourceExpr = secondExpr;
|
||||
sinkExpr = firstName;
|
||||
|
@ -418,8 +449,10 @@ struct FirrtlWorker
|
|||
string primop;
|
||||
bool always_uint = false;
|
||||
if (cell->type == "$not") primop = "not";
|
||||
else if (cell->type == "$neg") primop = "neg";
|
||||
else if (cell->type == "$logic_not") {
|
||||
else if (cell->type == "$neg") {
|
||||
primop = "neg";
|
||||
is_signed = true; // Result of "neg" is signed (an SInt).
|
||||
} else if (cell->type == "$logic_not") {
|
||||
primop = "eq";
|
||||
a_expr = stringf("%s, UInt(0)", a_expr.c_str());
|
||||
}
|
||||
|
@ -531,6 +564,7 @@ struct FirrtlWorker
|
|||
auto b_sig = cell->getPort("\\B");
|
||||
if (b_sig.is_fully_const()) {
|
||||
primop = "shl";
|
||||
b_expr = std::to_string(b_sig.as_int());
|
||||
} else {
|
||||
primop = "dshl";
|
||||
// Convert from FIRRTL left shift semantics.
|
||||
|
@ -544,6 +578,7 @@ struct FirrtlWorker
|
|||
auto b_sig = cell->getPort("\\B");
|
||||
if (b_sig.is_fully_const()) {
|
||||
primop = "shr";
|
||||
b_expr = std::to_string(b_sig.as_int());
|
||||
} else {
|
||||
primop = "dshr";
|
||||
}
|
||||
|
@ -604,7 +639,7 @@ struct FirrtlWorker
|
|||
int abits = cell->parameters.at("\\ABITS").as_int();
|
||||
int width = cell->parameters.at("\\WIDTH").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 wr_ports = cell->parameters.at("\\WR_PORTS").as_int();
|
||||
|
||||
|
@ -681,6 +716,8 @@ struct FirrtlWorker
|
|||
{
|
||||
std::string cell_type = fid(cell->type);
|
||||
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;
|
||||
if (cell->type == "$meminit" ) {
|
||||
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_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);
|
||||
int portNum = 0;
|
||||
bool transparency = false;
|
||||
|
@ -890,7 +932,7 @@ struct FirrtlWorker
|
|||
|
||||
// If we have any memory definitions, output them.
|
||||
for (auto kv : memories) {
|
||||
memory m = kv.second;
|
||||
memory &m = kv.second;
|
||||
f << stringf(" mem %s:\n", m.name.c_str());
|
||||
f << stringf(" data-type => UInt<%d>\n", m.width);
|
||||
f << stringf(" depth => %d\n", m.size);
|
||||
|
|
|
@ -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());
|
||||
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);
|
||||
f << stringf("\n");
|
||||
}
|
||||
|
|
|
@ -183,8 +183,9 @@ bool is_reg_wire(RTLIL::SigSpec sig, std::string ®_name)
|
|||
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)
|
||||
width = data.bits.size() - offset;
|
||||
if (width == 0) {
|
||||
|
@ -275,7 +276,8 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
|
|||
}
|
||||
}
|
||||
} else {
|
||||
f << stringf("\"");
|
||||
if ((data.flags & RTLIL::CONST_FLAG_REAL) == 0)
|
||||
f << stringf("\"");
|
||||
std::string str = data.decode_string();
|
||||
for (size_t i = 0; i < str.size(); i++) {
|
||||
if (str[i] == '\n')
|
||||
|
@ -293,7 +295,8 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
|
|||
else
|
||||
f << str[i];
|
||||
}
|
||||
f << stringf("\"");
|
||||
if ((data.flags & RTLIL::CONST_FLAG_REAL) == 0)
|
||||
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)))
|
||||
f << stringf(" 1 ");
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -1242,6 +1245,118 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
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, $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())
|
||||
f << stringf(",");
|
||||
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, -1, 0, false, is_signed);
|
||||
dump_const(f, it->second);
|
||||
f << stringf(")");
|
||||
}
|
||||
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) {
|
||||
for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) {
|
||||
f << stringf("%sdefparam %s.%s = ", indent.c_str(), cell_name.c_str(), id(it->first).c_str());
|
||||
bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0;
|
||||
dump_const(f, it->second, -1, 0, false, is_signed);
|
||||
dump_const(f, it->second);
|
||||
f << stringf(";\n");
|
||||
}
|
||||
}
|
||||
|
@ -1505,7 +1618,8 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
|
|||
SigSpec sig = active_sigmap(wire);
|
||||
Const val = wire->attributes.at("\\init");
|
||||
for (int i = 0; i < GetSize(sig) && i < GetSize(val); i++)
|
||||
active_initdata[sig[i]] = val.bits.at(i);
|
||||
if (val[i] == State::S0 || val[i] == State::S1)
|
||||
active_initdata[sig[i]] = val[i];
|
||||
}
|
||||
|
||||
if (!module->processes.empty())
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -37,16 +37,20 @@ struct AigerReader
|
|||
unsigned M, I, L, O, A;
|
||||
unsigned B, C, J, F; // Optional in AIGER 1.9
|
||||
unsigned line_count;
|
||||
uint32_t piNum, flopNum;
|
||||
|
||||
std::vector<RTLIL::Wire*> inputs;
|
||||
std::vector<RTLIL::Wire*> latches;
|
||||
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);
|
||||
void parse_aiger();
|
||||
void parse_xaiger();
|
||||
void parse_aiger_ascii();
|
||||
void parse_aiger_binary();
|
||||
void post_process();
|
||||
};
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
|
|
@ -154,6 +154,7 @@ std::string AST::type2str(AstNodeType type)
|
|||
X(AST_GENIF)
|
||||
X(AST_GENCASE)
|
||||
X(AST_GENBLOCK)
|
||||
X(AST_TECALL)
|
||||
X(AST_POSEDGE)
|
||||
X(AST_NEGEDGE)
|
||||
X(AST_EDGE)
|
||||
|
@ -194,6 +195,9 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch
|
|||
is_logic = false;
|
||||
is_signed = false;
|
||||
is_string = false;
|
||||
is_wand = false;
|
||||
is_wor = false;
|
||||
is_unsized = false;
|
||||
was_checked = false;
|
||||
range_valid = 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)
|
||||
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);
|
||||
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_left = node->bits.size()-1;
|
||||
node->range_right = 0;
|
||||
node->is_unsized = is_unsized;
|
||||
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)
|
||||
AstNode *AstNode::mkconst_str(const std::vector<RTLIL::State> &v)
|
||||
{
|
||||
|
@ -775,6 +785,14 @@ bool AstNode::bits_only_01() const
|
|||
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)
|
||||
{
|
||||
std::vector<RTLIL::State> bits = this->bits;
|
||||
|
@ -951,6 +969,9 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
|
|||
continue;
|
||||
if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
|
||||
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;
|
||||
break;
|
||||
}
|
||||
|
@ -1035,6 +1056,9 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
|
|||
child->delete_children();
|
||||
child->children.push_back(AstNode::mkconst_int(0, false, 0));
|
||||
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 {
|
||||
delete child;
|
||||
}
|
||||
|
|
|
@ -137,7 +137,8 @@ namespace AST
|
|||
AST_GENIF,
|
||||
AST_GENCASE,
|
||||
AST_GENBLOCK,
|
||||
|
||||
AST_TECALL,
|
||||
|
||||
AST_POSEDGE,
|
||||
AST_NEGEDGE,
|
||||
AST_EDGE,
|
||||
|
@ -173,7 +174,7 @@ namespace AST
|
|||
// node content - most of it is unused in most node types
|
||||
std::string str;
|
||||
std::vector<RTLIL::State> bits;
|
||||
bool is_input, is_output, is_reg, is_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;
|
||||
uint32_t integer;
|
||||
double realvalue;
|
||||
|
@ -262,6 +263,7 @@ namespace AST
|
|||
|
||||
// helper functions for creating AST nodes for constants
|
||||
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_str(const std::vector<RTLIL::State> &v);
|
||||
static AstNode *mkconst_str(const std::string &str);
|
||||
|
@ -269,6 +271,7 @@ namespace AST
|
|||
// helper function for creating sign-extended const objects
|
||||
RTLIL::Const bitsAsConst(int width, bool is_signed);
|
||||
RTLIL::Const bitsAsConst(int width = -1);
|
||||
RTLIL::Const bitsAsUnsizedConst(int width);
|
||||
RTLIL::Const asAttrConst();
|
||||
RTLIL::Const asParaConst();
|
||||
uint64_t asInt(bool is_signed);
|
||||
|
|
|
@ -645,6 +645,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
|||
if (!id_ast->children[0]->range_valid)
|
||||
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;
|
||||
if (children.size() > 1)
|
||||
range = children[1];
|
||||
} else
|
||||
log_file_error(filename, linenum, "Failed to detect width for identifier %s!\n", str.c_str());
|
||||
if (range) {
|
||||
|
@ -902,7 +904,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
if (!range_valid)
|
||||
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);
|
||||
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());
|
||||
wire->attributes[attr.first] = attr.second->asAttrConst();
|
||||
}
|
||||
|
||||
if (is_wand) wire->set_bool_attribute("\\wand");
|
||||
if (is_wor) wire->set_bool_attribute("\\wor");
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -961,8 +967,13 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
detectSignWidth(width_hint, sign_hint);
|
||||
is_signed = sign_hint;
|
||||
|
||||
if (type == AST_CONSTANT)
|
||||
return RTLIL::SigSpec(bitsAsConst());
|
||||
if (type == AST_CONSTANT) {
|
||||
if (is_unsized) {
|
||||
return RTLIL::SigSpec(bitsAsUnsizedConst(width_hint));
|
||||
} else {
|
||||
return RTLIL::SigSpec(bitsAsConst());
|
||||
}
|
||||
}
|
||||
|
||||
RTLIL::SigSpec sig = realAsConst(width_hint);
|
||||
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;
|
||||
}
|
||||
if (child->type == AST_PARASET) {
|
||||
int extra_const_flags = 0;
|
||||
IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str;
|
||||
if (child->children[0]->type == AST_REALVALUE) {
|
||||
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);
|
||||
extra_const_flags = RTLIL::CONST_FLAG_REAL;
|
||||
auto strnode = AstNode::mkconst_str(stringf("%f", child->children[0]->realvalue));
|
||||
strnode->cloneInto(child->children[0]);
|
||||
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_id(cell), log_id(paraname));
|
||||
cell->parameters[paraname] = child->children[0]->asParaConst();
|
||||
cell->parameters[paraname].flags |= extra_const_flags;
|
||||
continue;
|
||||
}
|
||||
if (child->type == AST_ARGUMENT) {
|
||||
|
@ -1521,9 +1535,29 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
}
|
||||
for (auto &attr : attributes) {
|
||||
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();
|
||||
}
|
||||
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;
|
||||
|
||||
|
@ -1541,6 +1575,37 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
delete always;
|
||||
} 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: {
|
||||
if (str == "\\$anyconst" || str == "\\$anyseq" || str == "\\$allconst" || str == "\\$allseq")
|
||||
{
|
||||
|
|
|
@ -1172,6 +1172,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
|||
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;
|
||||
delete varbuf;
|
||||
delete_children();
|
||||
|
@ -1598,6 +1605,7 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
current_scope[wire_tmp->str] = wire_tmp;
|
||||
wire_tmp->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
|
||||
while (wire_tmp->simplify(true, false, false, 1, -1, false, false)) { }
|
||||
wire_tmp->is_logic = true;
|
||||
|
||||
AstNode *wire_tmp_id = new AstNode(AST_IDENTIFIER);
|
||||
wire_tmp_id->str = wire_tmp->str;
|
||||
|
|
|
@ -53,6 +53,7 @@ USING_YOSYS_NAMESPACE
|
|||
"attribute" { return TOK_ATTRIBUTE; }
|
||||
"parameter" { return TOK_PARAMETER; }
|
||||
"signed" { return TOK_SIGNED; }
|
||||
"real" { return TOK_REAL; }
|
||||
"wire" { return TOK_WIRE; }
|
||||
"memory" { return TOK_MEMORY; }
|
||||
"width" { return TOK_WIDTH; }
|
||||
|
|
|
@ -45,7 +45,16 @@ YOSYS_NAMESPACE_END
|
|||
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 {
|
||||
char *string;
|
||||
|
@ -61,7 +70,7 @@ USING_YOSYS_NAMESPACE
|
|||
%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_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 <sigspec> sigspec sigspec_list
|
||||
|
@ -241,6 +250,12 @@ cell_body:
|
|||
free($4);
|
||||
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 {
|
||||
if (current_cell->hasPort($3))
|
||||
rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell port %s.", $3).c_str());
|
||||
|
@ -445,4 +460,3 @@ conn_stmt:
|
|||
delete $2;
|
||||
delete $3;
|
||||
};
|
||||
|
||||
|
|
|
@ -46,7 +46,15 @@ USING_YOSYS_NAMESPACE
|
|||
#include "VeriModule.h"
|
||||
#include "VeriWrite.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__
|
||||
#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)
|
||||
{
|
||||
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;
|
||||
|
||||
if (design->has(module_name)) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1752,32 +1761,64 @@ struct VerificExtNets
|
|||
}
|
||||
};
|
||||
|
||||
void verific_import(Design *design, std::string top)
|
||||
void verific_import(Design *design, const std::map<std::string,std::string> ¶meters, std::string top)
|
||||
{
|
||||
verific_sva_fsm_limit = 16;
|
||||
|
||||
std::set<Netlist*> nl_todo, nl_done;
|
||||
|
||||
{
|
||||
VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1);
|
||||
VeriLibrary *veri_lib = veri_file::GetLibrary("work", 1);
|
||||
VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1);
|
||||
VeriLibrary *veri_lib = veri_file::GetLibrary("work", 1);
|
||||
Array *netlists = NULL;
|
||||
Array veri_libs, vhdl_libs;
|
||||
if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib);
|
||||
if (veri_lib) veri_libs.InsertLast(veri_lib);
|
||||
|
||||
Array veri_libs, vhdl_libs;
|
||||
if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib);
|
||||
if (veri_lib) veri_libs.InsertLast(veri_lib);
|
||||
Map verific_params(STRING_HASH);
|
||||
for (const auto &i : parameters)
|
||||
verific_params.Insert(i.first.c_str(), i.second.c_str());
|
||||
|
||||
Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs);
|
||||
Netlist *nl;
|
||||
int i;
|
||||
if (top.empty()) {
|
||||
netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, &verific_params);
|
||||
}
|
||||
else {
|
||||
Array veri_modules, vhdl_units;
|
||||
|
||||
FOREACH_ARRAY_ITEM(netlists, i, nl) {
|
||||
if (top.empty() || nl->Owner()->Name() == top)
|
||||
nl_todo.insert(nl);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
delete netlists;
|
||||
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;
|
||||
int i;
|
||||
|
||||
FOREACH_ARRAY_ITEM(netlists, i, nl) {
|
||||
if (top.empty() && nl->CellBaseName() != top)
|
||||
continue;
|
||||
nl->AddAtt(new Att(" \\top", NULL));
|
||||
nl_todo.insert(nl);
|
||||
}
|
||||
|
||||
delete netlists;
|
||||
|
||||
if (!verific_error_msg.empty())
|
||||
log_error("%s\n", verific_error_msg.c_str());
|
||||
|
||||
|
@ -1983,6 +2024,9 @@ struct VerificPass : public Pass {
|
|||
// WARNING: instantiating unknown module 'XYZ' (VERI-1063)
|
||||
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
|
||||
# warning Verific was built without DB_PRESERVE_INITIAL_VALUE.
|
||||
#endif
|
||||
|
@ -2212,8 +2256,8 @@ struct VerificPass : public Pass {
|
|||
continue;
|
||||
}
|
||||
if (args[argidx] == "-chparam" && argidx+2 < GetSize(args)) {
|
||||
const std::string &key = args[++argidx];
|
||||
const std::string &value = args[++argidx];
|
||||
const std::string &key = args[++argidx];
|
||||
const std::string &value = args[++argidx];
|
||||
unsigned new_insertion = parameters.Insert(key.c_str(), value.c_str(),
|
||||
1 /* force_overwrite */);
|
||||
if (!new_insertion)
|
||||
|
@ -2270,12 +2314,22 @@ struct VerificPass : public Pass {
|
|||
for (; argidx < GetSize(args); argidx++)
|
||||
{
|
||||
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_module) {
|
||||
log("Adding Verilog module '%s' to elaboration queue.\n", name);
|
||||
veri_modules.InsertLast(veri_module);
|
||||
continue;
|
||||
if (veri_lib) {
|
||||
VeriModule *veri_module = veri_lib->GetModule(name, 1);
|
||||
if (veri_module) {
|
||||
log("Adding Verilog module '%s' to elaboration queue.\n", name);
|
||||
veri_modules.InsertLast(veri_module);
|
||||
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);
|
||||
|
@ -2294,8 +2348,10 @@ struct VerificPass : public Pass {
|
|||
Netlist *nl;
|
||||
int i;
|
||||
|
||||
FOREACH_ARRAY_ITEM(netlists, i, nl)
|
||||
FOREACH_ARRAY_ITEM(netlists, i, nl) {
|
||||
nl->AddAtt(new Att(" \\top", NULL));
|
||||
nl_todo.insert(nl);
|
||||
}
|
||||
delete netlists;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ YOSYS_NAMESPACE_BEGIN
|
|||
extern int verific_verbose;
|
||||
|
||||
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> ¶meters, std::string top = std::string());
|
||||
|
||||
extern pool<int> verific_sva_prims;
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l
|
|||
$(Q) mkdir -p $(dir $@)
|
||||
$(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_lexer.o
|
||||
|
|
|
@ -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 '?')
|
||||
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)
|
||||
std::vector<uint8_t> digits;
|
||||
|
@ -129,6 +129,9 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
|
|||
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--)
|
||||
if (data[len] == RTLIL::S1)
|
||||
break;
|
||||
|
@ -186,7 +189,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
|
|||
// Simple base-10 integer
|
||||
if (*endptr == 0) {
|
||||
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)
|
||||
data.push_back(RTLIL::S0);
|
||||
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;
|
||||
bool is_signed = false;
|
||||
bool is_unsized = false;
|
||||
if (*(endptr+1) == 's') {
|
||||
is_signed = true;
|
||||
endptr++;
|
||||
|
@ -209,28 +213,34 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
|
|||
{
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
default:
|
||||
return NULL;
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (len_in_bits < 0) {
|
||||
if (is_signed && data.back() == RTLIL::S1)
|
||||
data.push_back(RTLIL::S0);
|
||||
}
|
||||
return AstNode::mkconst_bits(data, is_signed);
|
||||
return AstNode::mkconst_bits(data, is_signed, is_unsized);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
|
|
@ -158,6 +158,9 @@ struct VerilogFrontend : public Frontend {
|
|||
log(" delete (* whitebox *) and (* lib_whitebox *) attributes from\n");
|
||||
log(" all modules.\n");
|
||||
log("\n");
|
||||
log(" -specify\n");
|
||||
log(" parse and import specify blocks\n");
|
||||
log("\n");
|
||||
log(" -noopt\n");
|
||||
log(" don't perform basic optimizations (such as const folding) in the\n");
|
||||
log(" high-level front-end.\n");
|
||||
|
@ -228,6 +231,8 @@ struct VerilogFrontend : public Frontend {
|
|||
bool flag_nooverwrite = false;
|
||||
bool flag_overwrite = false;
|
||||
bool flag_defer = false;
|
||||
bool flag_noblackbox = false;
|
||||
bool flag_nowb = false;
|
||||
std::map<std::string, std::string> defines_map;
|
||||
std::list<std::string> include_dirs;
|
||||
std::list<std::string> attributes;
|
||||
|
@ -237,13 +242,10 @@ struct VerilogFrontend : public Frontend {
|
|||
formal_mode = false;
|
||||
norestrict_mode = false;
|
||||
assume_asserts_mode = false;
|
||||
noblackbox_mode = false;
|
||||
lib_mode = false;
|
||||
nowb_mode = false;
|
||||
specify_mode = false;
|
||||
default_nettype_wire = true;
|
||||
|
||||
log_header(design, "Executing Verilog-2005 frontend.\n");
|
||||
|
||||
args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end());
|
||||
|
||||
size_t argidx;
|
||||
|
@ -342,7 +344,7 @@ struct VerilogFrontend : public Frontend {
|
|||
continue;
|
||||
}
|
||||
if (arg == "-noblackbox") {
|
||||
noblackbox_mode = true;
|
||||
flag_noblackbox = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-lib") {
|
||||
|
@ -351,7 +353,11 @@ struct VerilogFrontend : public Frontend {
|
|||
continue;
|
||||
}
|
||||
if (arg == "-nowb") {
|
||||
nowb_mode = true;
|
||||
flag_nowb = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-specify") {
|
||||
specify_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-noopt") {
|
||||
|
@ -415,6 +421,8 @@ struct VerilogFrontend : public Frontend {
|
|||
}
|
||||
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",
|
||||
formal_mode ? "formal " : "", sv_mode ? "SystemVerilog" : "Verilog", filename.c_str());
|
||||
|
||||
|
@ -450,7 +458,7 @@ struct VerilogFrontend : public Frontend {
|
|||
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,
|
||||
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)
|
||||
delete lexin;
|
||||
|
|
|
@ -69,14 +69,11 @@ namespace VERILOG_FRONTEND
|
|||
// running in -assert-assumes mode
|
||||
extern bool assert_assumes_mode;
|
||||
|
||||
// running in -noblackbox mode
|
||||
extern bool noblackbox_mode;
|
||||
|
||||
// running in -lib mode
|
||||
extern bool lib_mode;
|
||||
|
||||
// running in -nowb mode
|
||||
extern bool nowb_mode;
|
||||
// running in -specify mode
|
||||
extern bool specify_mode;
|
||||
|
||||
// lexer input stream
|
||||
extern std::istream *lexin;
|
||||
|
|
|
@ -148,7 +148,7 @@ YOSYS_NAMESPACE_END
|
|||
"endfunction" { return TOK_ENDFUNCTION; }
|
||||
"task" { return TOK_TASK; }
|
||||
"endtask" { return TOK_ENDTASK; }
|
||||
"specify" { return TOK_SPECIFY; }
|
||||
"specify" { return specify_mode ? TOK_SPECIFY : TOK_IGNORED_SPECIFY; }
|
||||
"endspecify" { return TOK_ENDSPECIFY; }
|
||||
"specparam" { return TOK_SPECPARAM; }
|
||||
"package" { SV_KEYWORD(TOK_PACKAGE); }
|
||||
|
@ -206,7 +206,9 @@ YOSYS_NAMESPACE_END
|
|||
"const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); }
|
||||
"checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); }
|
||||
"endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); }
|
||||
"final" { SV_KEYWORD(TOK_FINAL); }
|
||||
"logic" { SV_KEYWORD(TOK_LOGIC); }
|
||||
"var" { SV_KEYWORD(TOK_VAR); }
|
||||
"bit" { SV_KEYWORD(TOK_REG); }
|
||||
|
||||
"eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
|
||||
|
@ -216,6 +218,8 @@ YOSYS_NAMESPACE_END
|
|||
"output" { return TOK_OUTPUT; }
|
||||
"inout" { return TOK_INOUT; }
|
||||
"wire" { return TOK_WIRE; }
|
||||
"wor" { return TOK_WOR; }
|
||||
"wand" { return TOK_WAND; }
|
||||
"reg" { return TOK_REG; }
|
||||
"integer" { return TOK_INTEGER; }
|
||||
"signed" { return TOK_SIGNED; }
|
||||
|
@ -230,7 +234,7 @@ YOSYS_NAMESPACE_END
|
|||
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);
|
||||
return TOK_CONSTVAL;
|
||||
}
|
||||
|
@ -301,6 +305,17 @@ supply1 { return TOK_SUPPLY1; }
|
|||
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; }
|
||||
"$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_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); }
|
||||
<COMMENT>. /* ignore comment body */
|
||||
<COMMENT>\n /* ignore comment body */
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace VERILOG_FRONTEND {
|
|||
std::vector<char> case_type_stack;
|
||||
bool do_not_require_port_stubs;
|
||||
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 assume_asserts_mode, assert_assumes_mode;
|
||||
bool current_wire_rand, current_wire_const;
|
||||
|
@ -94,29 +94,58 @@ static void free_attr(std::map<std::string, AstNode*> *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 {
|
||||
std::string *string;
|
||||
struct YOSYS_NAMESPACE_PREFIX AST::AstNode *ast;
|
||||
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;
|
||||
char ch;
|
||||
}
|
||||
|
||||
%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE TOK_SVA_LABEL
|
||||
%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER
|
||||
%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE
|
||||
%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 TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
|
||||
%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
|
||||
%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT
|
||||
%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG TOK_LOGIC
|
||||
%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR
|
||||
%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_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_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_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
|
||||
%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 <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
|
||||
%left OP_LOR
|
||||
%left OP_LAND
|
||||
|
@ -450,12 +485,21 @@ wire_type_token_io:
|
|||
wire_type_token:
|
||||
TOK_WIRE {
|
||||
} |
|
||||
TOK_WOR {
|
||||
astbuf3->is_wor = true;
|
||||
} |
|
||||
TOK_WAND {
|
||||
astbuf3->is_wand = true;
|
||||
} |
|
||||
TOK_REG {
|
||||
astbuf3->is_reg = true;
|
||||
} |
|
||||
TOK_LOGIC {
|
||||
astbuf3->is_logic = true;
|
||||
} |
|
||||
TOK_VAR {
|
||||
astbuf3->is_logic = true;
|
||||
} |
|
||||
TOK_INTEGER {
|
||||
astbuf3->is_reg = true;
|
||||
astbuf3->range_left = 31;
|
||||
|
@ -539,7 +583,7 @@ module_body:
|
|||
|
||||
module_body_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:
|
||||
TOK_CHECKER TOK_ID ';' {
|
||||
|
@ -697,15 +741,254 @@ task_func_body:
|
|||
task_func_body behavioral_stmt |
|
||||
/* empty */;
|
||||
|
||||
specify_block:
|
||||
TOK_SPECIFY specify_item_opt TOK_ENDSPECIFY |
|
||||
TOK_SPECIFY TOK_ENDSPECIFY ;
|
||||
/*************************** specify parser ***************************/
|
||||
|
||||
specify_item_opt:
|
||||
specify_item_opt specify_item |
|
||||
specify_item ;
|
||||
specify_block:
|
||||
TOK_SPECIFY specify_item_list TOK_ENDSPECIFY;
|
||||
|
||||
specify_item_list:
|
||||
specify_item specify_item_list |
|
||||
/* empty */;
|
||||
|
||||
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
|
||||
// | pulsestyle_declaration
|
||||
// | showcancelled_declaration
|
||||
|
@ -721,13 +1004,13 @@ specparam_declaration:
|
|||
// and the 'non_opt_range' rule allows index ranges not allowed by 1364-2005
|
||||
// exxxxtending this for SV specparam would change this anyhow
|
||||
specparam_range:
|
||||
'[' constant_expression ':' constant_expression ']' ;
|
||||
'[' ignspec_constant_expression ':' ignspec_constant_expression ']' ;
|
||||
|
||||
list_of_specparam_assignments:
|
||||
specparam_assignment | list_of_specparam_assignments ',' specparam_assignment;
|
||||
|
||||
specparam_assignment:
|
||||
TOK_ID '=' constant_mintypmax_expression ;
|
||||
ignspec_id '=' constant_mintypmax_expression ;
|
||||
|
||||
/*
|
||||
pulsestyle_declaration :
|
||||
|
@ -802,19 +1085,19 @@ opt_polarity_operator :
|
|||
|
||||
// Good enough for the time being
|
||||
specify_input_terminal_descriptor :
|
||||
TOK_ID ;
|
||||
ignspec_id ;
|
||||
|
||||
// Good enough for the time being
|
||||
specify_output_terminal_descriptor :
|
||||
TOK_ID ;
|
||||
ignspec_id ;
|
||||
|
||||
system_timing_declaration :
|
||||
TOK_ID '(' system_timing_args ')' ';' ;
|
||||
ignspec_id '(' system_timing_args ')' ';' ;
|
||||
|
||||
system_timing_arg :
|
||||
TOK_POSEDGE TOK_ID |
|
||||
TOK_NEGEDGE TOK_ID |
|
||||
expr ;
|
||||
TOK_POSEDGE ignspec_id |
|
||||
TOK_NEGEDGE ignspec_id |
|
||||
ignspec_expr ;
|
||||
|
||||
system_timing_args :
|
||||
system_timing_arg |
|
||||
|
@ -871,19 +1154,27 @@ tzx_path_delay_expression :
|
|||
*/
|
||||
|
||||
path_delay_expression :
|
||||
constant_expression;
|
||||
ignspec_constant_expression;
|
||||
|
||||
constant_mintypmax_expression :
|
||||
constant_expression
|
||||
| constant_expression ':' constant_expression ':' constant_expression
|
||||
ignspec_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.
|
||||
// as I'm not sure it is legal to use a full expr here (probably not)
|
||||
// On the other hand, other rules requiring constant expressions also use 'expr'
|
||||
// (such as param assignment), so we may leave this as-is, perhaps adding runtime checks for constant-ness
|
||||
constant_expression:
|
||||
expr ;
|
||||
ignspec_constant_expression:
|
||||
expr { delete $1; };
|
||||
|
||||
ignspec_expr:
|
||||
expr { delete $1; };
|
||||
|
||||
ignspec_id:
|
||||
TOK_ID { delete $1; };
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
param_signed:
|
||||
TOK_SIGNED {
|
||||
|
@ -917,7 +1208,7 @@ param_range:
|
|||
};
|
||||
|
||||
param_decl:
|
||||
TOK_PARAMETER {
|
||||
attr TOK_PARAMETER {
|
||||
astbuf1 = new AstNode(AST_PARAMETER);
|
||||
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
|
||||
} param_signed param_integer param_real param_range param_decl_list ';' {
|
||||
|
@ -925,7 +1216,7 @@ param_decl:
|
|||
};
|
||||
|
||||
localparam_decl:
|
||||
TOK_LOCALPARAM {
|
||||
attr TOK_LOCALPARAM {
|
||||
astbuf1 = new AstNode(AST_LOCALPARAM);
|
||||
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
|
||||
} 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:
|
||||
/* empty */ {
|
||||
attr {
|
||||
AstNode *node = new AstNode(AST_ARGUMENT);
|
||||
astbuf2->children.push_back(node);
|
||||
free_attr($1);
|
||||
} |
|
||||
expr {
|
||||
attr expr {
|
||||
AstNode *node = new AstNode(AST_ARGUMENT);
|
||||
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);
|
||||
node->str = *$2;
|
||||
node->str = *$3;
|
||||
astbuf2->children.push_back(node);
|
||||
node->children.push_back($4);
|
||||
delete $2;
|
||||
node->children.push_back($5);
|
||||
delete $3;
|
||||
free_attr($1);
|
||||
} |
|
||||
'.' TOK_ID '(' ')' {
|
||||
attr '.' TOK_ID '(' ')' {
|
||||
AstNode *node = new AstNode(AST_ARGUMENT);
|
||||
node->str = *$2;
|
||||
node->str = *$3;
|
||||
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:
|
||||
|
@ -1341,6 +1645,9 @@ opt_property:
|
|||
TOK_PROPERTY {
|
||||
$$ = true;
|
||||
} |
|
||||
TOK_FINAL {
|
||||
$$ = false;
|
||||
} |
|
||||
/* empty */ {
|
||||
$$ = false;
|
||||
};
|
||||
|
@ -1869,6 +2176,15 @@ gen_stmt:
|
|||
if ($6 != NULL)
|
||||
delete $6;
|
||||
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:
|
||||
|
@ -2139,4 +2455,3 @@ concat_list:
|
|||
$$ = $3;
|
||||
$$->children.push_back($1);
|
||||
};
|
||||
|
||||
|
|
|
@ -453,7 +453,7 @@ Aig::Aig(Cell *cell)
|
|||
int B = mk.inport("\\B");
|
||||
int C = mk.inport("\\C");
|
||||
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");
|
||||
goto optimize;
|
||||
}
|
||||
|
|
|
@ -85,6 +85,8 @@ struct CellTypes
|
|||
setup_internals_eval();
|
||||
|
||||
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);
|
||||
|
||||
|
@ -99,6 +101,9 @@ struct CellTypes
|
|||
setup_type("$allconst", pool<RTLIL::IdString>(), {Y}, true);
|
||||
setup_type("$allseq", pool<RTLIL::IdString>(), {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()
|
||||
|
@ -464,7 +469,7 @@ struct CellTypes
|
|||
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));
|
||||
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);
|
||||
return eval(cell, arg1, arg2, arg3, errp);
|
||||
|
|
|
@ -529,13 +529,13 @@ int main(int argc, char **argv)
|
|||
log_error("Can't open dependencies file for writing: %s\n", strerror(errno));
|
||||
bool first = true;
|
||||
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;
|
||||
}
|
||||
fprintf(f, ":");
|
||||
for (auto fn : yosys_input_files) {
|
||||
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");
|
||||
}
|
||||
|
|
|
@ -230,6 +230,9 @@ static void logv_warning_with_prefix(const char *prefix,
|
|||
}
|
||||
else
|
||||
{
|
||||
int bak_log_make_debug = log_make_debug;
|
||||
log_make_debug = 0;
|
||||
|
||||
for (auto &re : log_werror_regexes)
|
||||
if (std::regex_search(message, re))
|
||||
log_error("%s", message.c_str());
|
||||
|
@ -254,6 +257,7 @@ static void logv_warning_with_prefix(const char *prefix,
|
|||
}
|
||||
|
||||
log_warnings_count++;
|
||||
log_make_debug = bak_log_make_debug;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -273,11 +277,22 @@ void log_file_warning(const std::string &filename, int lineno,
|
|||
va_list ap;
|
||||
va_start(ap, format);
|
||||
std::string prefix = stringf("%s:%d: Warning: ",
|
||||
filename.c_str(), lineno);
|
||||
filename.c_str(), lineno);
|
||||
logv_warning_with_prefix(prefix.c_str(), format, 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)
|
||||
static void logv_error_with_prefix(const char *prefix,
|
||||
const char *format, va_list ap)
|
||||
|
@ -285,6 +300,9 @@ static void logv_error_with_prefix(const char *prefix,
|
|||
#ifdef EMSCRIPTEN
|
||||
auto backup_log_files = log_files;
|
||||
#endif
|
||||
int bak_log_make_debug = log_make_debug;
|
||||
log_make_debug = 0;
|
||||
log_suppressed();
|
||||
|
||||
if (log_errfile != NULL)
|
||||
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_flush();
|
||||
|
||||
log_make_debug = bak_log_make_debug;
|
||||
|
||||
if (log_error_atexit)
|
||||
log_error_atexit();
|
||||
|
||||
|
|
|
@ -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.
|
||||
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));
|
||||
YS_NORETURN void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn);
|
||||
|
|
|
@ -218,15 +218,19 @@ void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id, bool value)
|
|||
{
|
||||
if (value)
|
||||
attributes[id] = RTLIL::Const(1);
|
||||
else if (attributes.count(id))
|
||||
attributes.erase(id);
|
||||
else {
|
||||
const auto it = attributes.find(id);
|
||||
if (it != attributes.end())
|
||||
attributes.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
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 attributes.at(id).as_bool();
|
||||
return it->second.as_bool();
|
||||
}
|
||||
|
||||
void RTLIL::AttrObject::set_strpool_attribute(RTLIL::IdString id, const pool<string> &data)
|
||||
|
@ -1194,6 +1198,46 @@ namespace {
|
|||
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 == "$_NOT_") { check_gate("AY"); return; }
|
||||
if (cell->type == "$_AND_") { check_gate("ABY"); return; }
|
||||
|
@ -1470,7 +1514,10 @@ void RTLIL::Module::add(RTLIL::Cell *cell)
|
|||
cell->module = this;
|
||||
}
|
||||
|
||||
namespace {
|
||||
void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires)
|
||||
{
|
||||
log_assert(refcount_wires_ == 0);
|
||||
|
||||
struct DeleteWireWorker
|
||||
{
|
||||
RTLIL::Module *module;
|
||||
|
@ -1485,17 +1532,29 @@ namespace {
|
|||
}
|
||||
sig = chunks;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires)
|
||||
{
|
||||
log_assert(refcount_wires_ == 0);
|
||||
void operator()(RTLIL::SigSpec &lhs, RTLIL::SigSpec &rhs) {
|
||||
log_assert(GetSize(lhs) == GetSize(rhs));
|
||||
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;
|
||||
delete_wire_worker.module = this;
|
||||
delete_wire_worker.wires_p = &wires;
|
||||
rewrite_sigspecs(delete_wire_worker);
|
||||
rewrite_sigspecs2(delete_wire_worker);
|
||||
|
||||
for (auto &it : wires) {
|
||||
log_assert(wires_.count(it->name) != 0);
|
||||
|
@ -3456,7 +3515,7 @@ bool RTLIL::SigSpec::operator ==(const RTLIL::SigSpec &other) const
|
|||
pack();
|
||||
other.pack();
|
||||
|
||||
if (chunks_.size() != chunks_.size())
|
||||
if (chunks_.size() != other.chunks_.size())
|
||||
return false;
|
||||
|
||||
updhash();
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace RTLIL
|
|||
CONST_FLAG_NONE = 0,
|
||||
CONST_FLAG_STRING = 1,
|
||||
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;
|
||||
|
@ -524,6 +524,7 @@ struct RTLIL::Const
|
|||
Const(const std::vector<RTLIL::State> &bits) : bits(bits) { flags = CONST_FLAG_NONE; }
|
||||
Const(const std::vector<bool> &bits);
|
||||
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;
|
||||
|
@ -603,8 +604,10 @@ struct RTLIL::SigChunk
|
|||
SigChunk(RTLIL::State bit, int width = 1);
|
||||
SigChunk(RTLIL::SigBit bit);
|
||||
SigChunk(const RTLIL::SigChunk &sigchunk);
|
||||
RTLIL::SigChunk &operator =(const RTLIL::SigChunk &other) = default;
|
||||
|
||||
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;
|
||||
|
@ -628,6 +631,7 @@ struct RTLIL::SigBit
|
|||
SigBit(const RTLIL::SigChunk &chunk, int index);
|
||||
SigBit(const RTLIL::SigSpec &sig);
|
||||
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;
|
||||
|
@ -1004,6 +1008,7 @@ public:
|
|||
void fixup_ports();
|
||||
|
||||
template<typename T> void rewrite_sigspecs(T &functor);
|
||||
template<typename T> void rewrite_sigspecs2(T &functor);
|
||||
void cloneInto(RTLIL::Module *new_mod) const;
|
||||
virtual RTLIL::Module *clone() const;
|
||||
|
||||
|
@ -1309,6 +1314,7 @@ public:
|
|||
}
|
||||
|
||||
template<typename T> void rewrite_sigspecs(T &functor);
|
||||
template<typename T> void rewrite_sigspecs2(T &functor);
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
static std::map<unsigned int, RTLIL::Cell*> *get_all_cells(void);
|
||||
|
@ -1327,6 +1333,7 @@ struct RTLIL::CaseRule
|
|||
bool empty() const;
|
||||
|
||||
template<typename T> void rewrite_sigspecs(T &functor);
|
||||
template<typename T> void rewrite_sigspecs2(T &functor);
|
||||
RTLIL::CaseRule *clone() const;
|
||||
};
|
||||
|
||||
|
@ -1340,6 +1347,7 @@ struct RTLIL::SwitchRule : public RTLIL::AttrObject
|
|||
bool empty() const;
|
||||
|
||||
template<typename T> void rewrite_sigspecs(T &functor);
|
||||
template<typename T> void rewrite_sigspecs2(T &functor);
|
||||
RTLIL::SwitchRule *clone() const;
|
||||
};
|
||||
|
||||
|
@ -1350,6 +1358,7 @@ struct RTLIL::SyncRule
|
|||
std::vector<RTLIL::SigSig> actions;
|
||||
|
||||
template<typename T> void rewrite_sigspecs(T &functor);
|
||||
template<typename T> void rewrite_sigspecs2(T &functor);
|
||||
RTLIL::SyncRule *clone() const;
|
||||
};
|
||||
|
||||
|
@ -1362,6 +1371,7 @@ struct RTLIL::Process : public RTLIL::AttrObject
|
|||
~Process();
|
||||
|
||||
template<typename T> void rewrite_sigspecs(T &functor);
|
||||
template<typename T> void rewrite_sigspecs2(T &functor);
|
||||
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>
|
||||
void RTLIL::Cell::rewrite_sigspecs(T &functor) {
|
||||
for (auto &it : connections_)
|
||||
functor(it.second);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void RTLIL::Cell::rewrite_sigspecs2(T &functor) {
|
||||
for (auto &it : connections_)
|
||||
functor(it.second);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void RTLIL::CaseRule::rewrite_sigspecs(T &functor) {
|
||||
for (auto &it : compare)
|
||||
|
@ -1441,6 +1469,17 @@ void RTLIL::CaseRule::rewrite_sigspecs(T &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>
|
||||
void RTLIL::SwitchRule::rewrite_sigspecs(T &functor)
|
||||
{
|
||||
|
@ -1449,6 +1488,14 @@ void RTLIL::SwitchRule::rewrite_sigspecs(T &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>
|
||||
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>
|
||||
void RTLIL::Process::rewrite_sigspecs(T &functor)
|
||||
{
|
||||
|
@ -1467,6 +1523,14 @@ void RTLIL::Process::rewrite_sigspecs(T &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
|
||||
|
||||
#endif
|
||||
|
|
|
@ -151,14 +151,16 @@ void yosys_banner()
|
|||
|
||||
int ceil_log2(int x)
|
||||
{
|
||||
#if defined(__GNUC__)
|
||||
return x > 1 ? (8*sizeof(int)) - __builtin_clz(x-1) : 0;
|
||||
#else
|
||||
if (x <= 0)
|
||||
return 0;
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
if (((x-1) >> i) == 0)
|
||||
return i;
|
||||
|
||||
log_abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string stringf(const char *fmt, ...)
|
||||
|
@ -482,6 +484,20 @@ void remove_directory(std::string dirname)
|
|||
#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)
|
||||
{
|
||||
return wire->width;
|
||||
|
|
|
@ -244,7 +244,7 @@ extern bool memhasher_active;
|
|||
inline void memhasher() { if (memhasher_active) memhasher_do(); }
|
||||
|
||||
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 vstringf(const char *fmt, va_list ap);
|
||||
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 is_absolute_path(std::string filename);
|
||||
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(); }
|
||||
int GetSize(RTLIL::Wire *wire);
|
||||
|
|
|
@ -320,12 +320,10 @@ class SubCircuit::SolverWorker
|
|||
|
||||
static int numberOfPermutations(const std::vector<std::string> &list)
|
||||
{
|
||||
int numPermutations = 1;
|
||||
for (int i = 0; i < int(list.size()); i++) {
|
||||
assert(numPermutations < maxPermutationsLimit);
|
||||
numPermutations *= i+1;
|
||||
}
|
||||
return numPermutations;
|
||||
constexpr size_t mappedPermutationsSize = 10;
|
||||
constexpr int mappedPermutations[mappedPermutationsSize] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
|
||||
assert(list.size() < mappedPermutationsSize);
|
||||
return mappedPermutations[list.size()];
|
||||
}
|
||||
|
||||
static void permutateVectorToMap(std::map<std::string, std::string> &map, const std::vector<std::string> &list, int idx)
|
||||
|
|
|
@ -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.
|
||||
\end{fixme}
|
||||
|
||||
\begin{fixme}
|
||||
Add information about {\tt \$specify2}, {\tt \$specify3}, and {\tt \$specrule} cells.
|
||||
\end{fixme}
|
||||
|
||||
\begin{fixme}
|
||||
Add information about {\tt \$slice} and {\tt \$concat} cells.
|
||||
\end{fixme}
|
||||
|
|
|
@ -2026,7 +2026,6 @@ def gen_wrappers(filename, debug_level_ = 0):
|
|||
#include <boost/python/wrapper.hpp>
|
||||
#include <boost/python/call.hpp>
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/log/exceptions.hpp>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
|
||||
|
@ -2060,7 +2059,6 @@ namespace YOSYS_PYTHON {
|
|||
Yosys::log_streams.push_back(&std::cout);
|
||||
Yosys::log_error_stderr = true;
|
||||
Yosys::yosys_setup();
|
||||
Yosys::yosys_banner();
|
||||
}
|
||||
}
|
||||
|
|
@ -281,6 +281,9 @@ struct BugpointPass : public Pass {
|
|||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
if (script.empty())
|
||||
log_cmd_error("Missing -script option.\n");
|
||||
|
||||
if (!has_part)
|
||||
{
|
||||
modules = true;
|
||||
|
@ -298,7 +301,7 @@ struct BugpointPass : public Pass {
|
|||
if (!check_logfile(grep))
|
||||
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;
|
||||
while (true)
|
||||
{
|
||||
|
@ -324,7 +327,6 @@ struct BugpointPass : public Pass {
|
|||
if (crashing_design != design)
|
||||
delete crashing_design;
|
||||
crashing_design = simplified;
|
||||
crashing_seed = seed;
|
||||
found_something = true;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -98,21 +98,23 @@ struct CoverPass : public Pass {
|
|||
}
|
||||
if ((args[argidx] == "-o" || args[argidx] == "-a" || args[argidx] == "-d") && argidx+1 < args.size()) {
|
||||
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") {
|
||||
#ifdef _WIN32
|
||||
log_cmd_error("The 'cover -d' option is not supported on win32.\n");
|
||||
#else
|
||||
char filename_buffer[4096];
|
||||
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
|
||||
} else {
|
||||
f = fopen(filename.c_str(), open_mode);
|
||||
}
|
||||
FILE *f = fopen(filename.c_str(), open_mode);
|
||||
if (f == NULL) {
|
||||
for (auto f : out_files)
|
||||
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);
|
||||
continue;
|
||||
|
|
|
@ -291,7 +291,7 @@ struct QwpWorker
|
|||
// gaussian elimination
|
||||
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);
|
||||
|
||||
// find best row
|
||||
|
|
|
@ -393,44 +393,112 @@ struct SetundefPass : public Pass {
|
|||
ffbits.insert(bit);
|
||||
}
|
||||
|
||||
for (auto wire : module->wires())
|
||||
auto process_initwires = [&]()
|
||||
{
|
||||
if (!wire->attributes.count("\\init"))
|
||||
continue;
|
||||
dict<Wire*, int> wire_weights;
|
||||
|
||||
for (auto bit : sigmap(wire))
|
||||
ffbits.erase(bit);
|
||||
|
||||
initwires.insert(wire);
|
||||
}
|
||||
|
||||
for (int wire_types = 0; wire_types < 2; wire_types++)
|
||||
for (auto wire : module->wires())
|
||||
for (auto wire : initwires)
|
||||
{
|
||||
if (wire->name[0] == (wire_types ? '\\' : '$'))
|
||||
next_wire:
|
||||
continue;
|
||||
int weight = 0;
|
||||
|
||||
for (auto bit : sigmap(wire))
|
||||
if (!ffbits.count(bit))
|
||||
goto next_wire;
|
||||
weight += ffbits.count(bit) ? +1 : -1;
|
||||
|
||||
for (auto bit : sigmap(wire))
|
||||
ffbits.erase(bit);
|
||||
|
||||
initwires.insert(wire);
|
||||
wire_weights[wire] = weight;
|
||||
}
|
||||
|
||||
for (auto wire : initwires)
|
||||
{
|
||||
Const &initval = wire->attributes["\\init"];
|
||||
initwires.sort([&](Wire *a, Wire *b) { return wire_weights.at(a) > wire_weights.at(b); });
|
||||
|
||||
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();
|
||||
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())
|
||||
{
|
||||
if (wire->name[0] == (wire_types ? '\\' : '$'))
|
||||
continue;
|
||||
|
||||
if (!wire->attributes.count("\\init"))
|
||||
continue;
|
||||
|
||||
Const &initval = wire->attributes["\\init"];
|
||||
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);
|
||||
}
|
||||
|
||||
process_initwires();
|
||||
}
|
||||
|
||||
// next consider wires that completely contain bits to be initialized
|
||||
if (!ffbits.empty())
|
||||
{
|
||||
for (auto wire : module->wires())
|
||||
{
|
||||
if (wire->name[0] == (wire_types ? '\\' : '$'))
|
||||
continue;
|
||||
|
||||
for (auto bit : sigmap(wire))
|
||||
if (!ffbits.count(bit))
|
||||
goto next_wire;
|
||||
|
||||
initwires.insert(wire);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
process_initwires();
|
||||
}
|
||||
}
|
||||
|
||||
log_assert(ffbits.empty());
|
||||
}
|
||||
|
||||
module->rewrite_sigspecs(worker);
|
||||
|
|
|
@ -37,7 +37,9 @@ struct statdata_t
|
|||
STAT_INT_MEMBERS
|
||||
#undef X
|
||||
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::set<RTLIL::IdString> unknown_cell_area;
|
||||
|
||||
|
@ -70,8 +72,10 @@ struct statdata_t
|
|||
#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;
|
||||
STAT_NUMERIC_MEMBERS
|
||||
#undef X
|
||||
|
@ -153,7 +157,8 @@ struct statdata_t
|
|||
log(" Number of processes: %6d\n", num_processes);
|
||||
log(" Number of cells: %6d\n", num_cells);
|
||||
for (auto &it : num_cells_by_type)
|
||||
log(" %-26s %6d\n", RTLIL::id2cstr(it.first), it.second);
|
||||
if (it.second)
|
||||
log(" %-26s %6d\n", RTLIL::id2cstr(it.first), it.second);
|
||||
|
||||
if (!unknown_cell_area.empty()) {
|
||||
log("\n");
|
||||
|
@ -165,6 +170,59 @@ struct statdata_t
|
|||
log("\n");
|
||||
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(" use cell area information from the provided liberty file\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(" annotate internal cell types with their word width.\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;
|
||||
std::map<RTLIL::IdString, statdata_t> mod_stat;
|
||||
dict<IdString, double> cell_area;
|
||||
string techname;
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
|
@ -253,6 +316,10 @@ struct StatPass : public Pass {
|
|||
read_liberty_cellarea(cell_area, liberty_file);
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-tech" && argidx+1 < args.size()) {
|
||||
techname = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-top" && argidx+1 < args.size()) {
|
||||
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());
|
||||
|
@ -263,13 +330,16 @@ struct StatPass : public Pass {
|
|||
}
|
||||
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())
|
||||
{
|
||||
if (!top_mod && design->full_selection())
|
||||
if (mod->get_bool_attribute("\\top"))
|
||||
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;
|
||||
|
||||
log("\n");
|
||||
|
|
|
@ -52,7 +52,9 @@ struct TeePass : public Pass {
|
|||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
std::vector<FILE*> backup_log_files, files_to_close;
|
||||
std::vector<std::ostream*> backup_log_streams;
|
||||
int backup_log_verbose_level = log_verbose_level;
|
||||
backup_log_streams = log_streams;
|
||||
backup_log_files = log_files;
|
||||
|
||||
size_t argidx;
|
||||
|
@ -60,6 +62,7 @@ struct TeePass : public Pass {
|
|||
{
|
||||
if (args[argidx] == "-q" && files_to_close.empty()) {
|
||||
log_files.clear();
|
||||
log_streams.clear();
|
||||
continue;
|
||||
}
|
||||
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)
|
||||
fclose(cf);
|
||||
log_files = backup_log_files;
|
||||
log_streams = backup_log_streams;
|
||||
throw;
|
||||
}
|
||||
|
||||
|
@ -97,6 +101,7 @@ struct TeePass : public Pass {
|
|||
|
||||
log_verbose_level = backup_log_verbose_level;
|
||||
log_files = backup_log_files;
|
||||
log_streams = backup_log_streams;
|
||||
}
|
||||
} TeePass;
|
||||
|
||||
|
|
|
@ -44,7 +44,10 @@ struct EquivOptPass:public ScriptPass
|
|||
log(" useful for handling architecture-specific primitives.\n");
|
||||
log("\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("The following commands are executed by this verification command:\n");
|
||||
help_script();
|
||||
|
@ -52,13 +55,14 @@ struct EquivOptPass:public ScriptPass
|
|||
}
|
||||
|
||||
std::string command, techmap_opts;
|
||||
bool assert;
|
||||
bool assert, undef;
|
||||
|
||||
void clear_flags() YS_OVERRIDE
|
||||
{
|
||||
command = "";
|
||||
techmap_opts = "";
|
||||
assert = false;
|
||||
undef = false;
|
||||
}
|
||||
|
||||
void execute(std::vector < std::string > args, RTLIL::Design * design) YS_OVERRIDE
|
||||
|
@ -84,6 +88,10 @@ struct EquivOptPass:public ScriptPass
|
|||
assert = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-undef") {
|
||||
undef = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -139,7 +147,12 @@ struct EquivOptPass:public ScriptPass
|
|||
|
||||
if (check_label("prove")) {
|
||||
run("equiv_make gold gate equiv");
|
||||
run("equiv_induct equiv");
|
||||
if (help_mode)
|
||||
run("equiv_induct [-undef] equiv");
|
||||
else if (undef)
|
||||
run("equiv_induct -undef equiv");
|
||||
else
|
||||
run("equiv_induct equiv");
|
||||
if (help_mode)
|
||||
run("equiv_status [-assert] equiv");
|
||||
else if (assert)
|
||||
|
|
|
@ -562,7 +562,8 @@ struct HierarchyPass : public Pass {
|
|||
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("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(" -check\n");
|
||||
log(" also check the design hierarchy. this generates an error when\n");
|
||||
|
@ -570,7 +571,7 @@ struct HierarchyPass : public Pass {
|
|||
log("\n");
|
||||
log(" -simcheck\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(" -purge_lib\n");
|
||||
log(" by default the hierarchy command will not remove library (blackbox)\n");
|
||||
|
@ -583,20 +584,20 @@ struct HierarchyPass : public Pass {
|
|||
log("\n");
|
||||
log(" -keep_positionals\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(" -keep_portwidths\n");
|
||||
log(" per default this pass adjusts the port width on cells that are\n");
|
||||
log(" module instances when the width does not match the module port. this\n");
|
||||
log(" module instances when the width does not match the module port. This\n");
|
||||
log(" option disables this behavior.\n");
|
||||
log("\n");
|
||||
log(" -nokeep_asserts\n");
|
||||
log(" 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(" option disables this behavior.\n");
|
||||
log(" that directly or indirectly contain one or more formal properties.\n");
|
||||
log(" This option disables this behavior.\n");
|
||||
log("\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("\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(" automatically determine the top of the design hierarchy and mark it.\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("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");
|
||||
|
@ -641,6 +648,7 @@ struct HierarchyPass : public Pass {
|
|||
bool nokeep_asserts = false;
|
||||
std::vector<std::string> generate_cells;
|
||||
std::vector<generate_port_decl_t> generate_ports;
|
||||
std::map<std::string, std::string> parameters;
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
|
@ -715,28 +723,61 @@ struct HierarchyPass : public Pass {
|
|||
if (args[argidx] == "-top") {
|
||||
if (++argidx >= args.size())
|
||||
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;
|
||||
}
|
||||
if (args[argidx] == "-auto-top") {
|
||||
auto_top_mode = true;
|
||||
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;
|
||||
}
|
||||
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 ¶ : 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
|
||||
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));
|
||||
}
|
||||
#endif
|
||||
|
@ -745,7 +786,7 @@ struct HierarchyPass : public Pass {
|
|||
} else {
|
||||
#ifdef YOSYS_ENABLE_VERIFIC
|
||||
if (verific_import_pending)
|
||||
verific_import(design);
|
||||
verific_import(design, parameters);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -846,7 +887,7 @@ struct HierarchyPass : public Pass {
|
|||
std::map<RTLIL::Module*, bool> cache;
|
||||
for (auto mod : design->modules())
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
@ -903,62 +944,178 @@ struct HierarchyPass : public Pass {
|
|||
std::vector<Module*> design_modules = design->modules();
|
||||
|
||||
for (auto module : design_modules)
|
||||
for (auto cell : module->cells())
|
||||
{
|
||||
Module *m = design->module(cell->type);
|
||||
pool<Wire*> wand_wor_index;
|
||||
dict<Wire*, SigSpec> wand_map, wor_map;
|
||||
vector<SigSig> new_connections;
|
||||
|
||||
if (m == nullptr)
|
||||
continue;
|
||||
|
||||
if (m->get_blackbox_attribute() && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) {
|
||||
IdString new_m_name = m->derive(design, cell->parameters, true);
|
||||
if (new_m_name.empty())
|
||||
continue;
|
||||
if (new_m_name != m->name) {
|
||||
m = design->module(new_m_name);
|
||||
blackbox_derivatives.insert(m);
|
||||
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 : cell->connections())
|
||||
for (auto &conn : module->connections())
|
||||
{
|
||||
Wire *w = m->wire(conn.first);
|
||||
SigSig new_conn;
|
||||
int cursor = 0;
|
||||
|
||||
if (w == nullptr || w->port_id == 0)
|
||||
continue;
|
||||
|
||||
if (GetSize(conn.second) == 0)
|
||||
continue;
|
||||
|
||||
SigSpec sig = conn.second;
|
||||
|
||||
if (!keep_portwidths && GetSize(w) != GetSize(conn.second))
|
||||
for (auto c : conn.first.chunks())
|
||||
{
|
||||
if (GetSize(w) < GetSize(conn.second))
|
||||
{
|
||||
int n = GetSize(conn.second) - GetSize(w);
|
||||
if (!w->port_input && w->port_output)
|
||||
module->connect(sig.extract(GetSize(w), n), Const(0, n));
|
||||
sig.remove(GetSize(w), n);
|
||||
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);
|
||||
}
|
||||
}
|
||||
else
|
||||
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())
|
||||
{
|
||||
int n = GetSize(w) - GetSize(conn.second);
|
||||
if (w->port_input && !w->port_output)
|
||||
sig.append(Const(0, n));
|
||||
else
|
||||
sig.append(module->addWire(NEW_ID, n));
|
||||
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 (!conn.second.is_fully_const() || !w->port_input || w->port_output)
|
||||
log_warning("Resizing cell port %s.%s.%s from %d bits to %d bits.\n", log_id(module), log_id(cell),
|
||||
log_id(conn.first), GetSize(conn.second), GetSize(sig));
|
||||
cell->setPort(conn.first, sig);
|
||||
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;
|
||||
}
|
||||
|
||||
if (w->port_output && !w->port_input && sig.has_const())
|
||||
log_error("Output port %s.%s.%s (%s) is connected to constants: %s\n",
|
||||
log_id(module), log_id(cell), log_id(conn.first), log_id(cell->type), log_signal(sig));
|
||||
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())
|
||||
{
|
||||
Module *m = design->module(cell->type);
|
||||
|
||||
if (m == nullptr)
|
||||
continue;
|
||||
|
||||
if (m->get_blackbox_attribute() && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) {
|
||||
IdString new_m_name = m->derive(design, cell->parameters, true);
|
||||
if (new_m_name.empty())
|
||||
continue;
|
||||
if (new_m_name != m->name) {
|
||||
m = design->module(new_m_name);
|
||||
blackbox_derivatives.insert(m);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &conn : cell->connections())
|
||||
{
|
||||
Wire *w = m->wire(conn.first);
|
||||
|
||||
if (w == nullptr || w->port_id == 0)
|
||||
continue;
|
||||
|
||||
if (GetSize(conn.second) == 0)
|
||||
continue;
|
||||
|
||||
SigSpec sig = conn.second;
|
||||
|
||||
if (!keep_portwidths && GetSize(w) != GetSize(conn.second))
|
||||
{
|
||||
if (GetSize(w) < GetSize(conn.second))
|
||||
{
|
||||
int n = GetSize(conn.second) - GetSize(w);
|
||||
if (!w->port_input && w->port_output)
|
||||
module->connect(sig.extract(GetSize(w), n), Const(0, n));
|
||||
sig.remove(GetSize(w), n);
|
||||
}
|
||||
else
|
||||
{
|
||||
int n = GetSize(w) - GetSize(conn.second);
|
||||
if (w->port_input && !w->port_output)
|
||||
sig.append(Const(0, n));
|
||||
else
|
||||
sig.append(module->addWire(NEW_ID, n));
|
||||
}
|
||||
|
||||
if (!conn.second.is_fully_const() || !w->port_input || w->port_output)
|
||||
log_warning("Resizing cell port %s.%s.%s from %d bits to %d bits.\n", log_id(module), log_id(cell),
|
||||
log_id(conn.first), GetSize(conn.second), GetSize(sig));
|
||||
cell->setPort(conn.first, sig);
|
||||
}
|
||||
|
||||
if (w->port_output && !w->port_input && sig.has_const())
|
||||
log_error("Output port %s.%s.%s (%s) is connected to constants: %s\n",
|
||||
log_id(module), log_id(cell), log_id(conn.first), log_id(cell->type), log_signal(sig));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ struct keep_cache_t
|
|||
|
||||
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;
|
||||
|
||||
if (cell->has_keep_attr())
|
||||
|
@ -85,22 +85,34 @@ void rmunused_module_cells(Module *module, bool verbose)
|
|||
{
|
||||
SigMap sigmap(module);
|
||||
pool<Cell*> queue, unused;
|
||||
pool<SigBit> used_raw_bits;
|
||||
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_) {
|
||||
Cell *cell = it.second;
|
||||
for (auto &it2 : cell->connections()) {
|
||||
if (!ct_all.cell_known(cell->type) || ct_all.cell_output(cell->type, it2.first))
|
||||
for (auto raw_bit : it2.second) {
|
||||
if (raw_bit.wire == nullptr)
|
||||
continue;
|
||||
auto bit = sigmap(raw_bit);
|
||||
if (bit.wire == nullptr)
|
||||
log_warning("Driver-driver conflict for %s between cell %s.%s and constant %s in %s: Resolved using constant.\n",
|
||||
log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module));
|
||||
if (bit.wire != nullptr)
|
||||
wire2driver[bit].insert(cell);
|
||||
}
|
||||
if (ct_all.cell_known(cell->type) && !ct_all.cell_output(cell->type, it2.first))
|
||||
continue;
|
||||
for (auto raw_bit : it2.second) {
|
||||
if (raw_bit.wire == nullptr)
|
||||
continue;
|
||||
auto bit = sigmap(raw_bit);
|
||||
if (bit.wire == nullptr && ct_all.cell_known(cell->type))
|
||||
driver_driver_logs[raw_sigmap(raw_bit)].push_back(stringf("Driver-driver conflict "
|
||||
"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)
|
||||
wire2driver[bit].insert(cell);
|
||||
}
|
||||
}
|
||||
if (keep_cache.query(cell))
|
||||
queue.insert(cell);
|
||||
|
@ -114,6 +126,8 @@ void rmunused_module_cells(Module *module, bool verbose)
|
|||
for (auto bit : sigmap(wire))
|
||||
for (auto c : wire2driver[bit])
|
||||
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);
|
||||
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)
|
||||
|
@ -202,7 +232,7 @@ bool check_public_name(RTLIL::IdString id)
|
|||
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 connected_signals;
|
||||
|
@ -245,11 +275,13 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
|
|||
module->connections_.clear();
|
||||
|
||||
SigPool used_signals;
|
||||
SigPool raw_used_signals;
|
||||
SigPool used_signals_nodrivers;
|
||||
for (auto &it : module->cells_) {
|
||||
RTLIL::Cell *cell = it.second;
|
||||
for (auto &it2 : cell->connections_) {
|
||||
assign_map.apply(it2.second);
|
||||
raw_used_signals.add(it2.second);
|
||||
used_signals.add(it2.second);
|
||||
if (!ct_all.cell_output(cell->type, it2.first))
|
||||
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;
|
||||
if (wire->port_id > 0) {
|
||||
RTLIL::SigSpec sig = RTLIL::SigSpec(wire);
|
||||
raw_used_signals.add(sig);
|
||||
assign_map.apply(sig);
|
||||
used_signals.add(sig);
|
||||
if (!wire->port_input)
|
||||
|
@ -271,72 +304,103 @@ 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())
|
||||
{
|
||||
if ((!purge_mode && check_public_name(wire->name)) || wire->port_id != 0 || wire->get_bool_attribute("\\keep") || wire->attributes.count("\\init")) {
|
||||
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));
|
||||
RTLIL::SigSig new_conn;
|
||||
for (int i = 0; i < GetSize(s1); i++)
|
||||
if (s1[i] != s2[i]) {
|
||||
new_conn.first.append_bit(s1[i]);
|
||||
new_conn.second.append_bit(s2[i]);
|
||||
}
|
||||
if (new_conn.first.size() > 0) {
|
||||
used_signals.add(new_conn.first);
|
||||
used_signals.add(new_conn.second);
|
||||
module->connect(new_conn);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!used_signals.check_any(RTLIL::SigSpec(wire)))
|
||||
maybe_del_wires.push_back(wire);
|
||||
SigSpec s1 = SigSpec(wire), s2 = assign_map(s1);
|
||||
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;
|
||||
}
|
||||
|
||||
RTLIL::SigSpec sig = assign_map(RTLIL::SigSpec(wire));
|
||||
if (!used_signals_nodrivers.check_any(sig)) {
|
||||
std::string unused_bits;
|
||||
for (int i = 0; i < GetSize(sig); i++) {
|
||||
if (sig[i].wire == NULL)
|
||||
continue;
|
||||
if (!used_signals_nodrivers.check(sig[i])) {
|
||||
if (!unused_bits.empty())
|
||||
unused_bits += " ";
|
||||
unused_bits += stringf("%d", i);
|
||||
if (0)
|
||||
{
|
||||
delete_this_wire:
|
||||
del_wires_queue.insert(wire);
|
||||
}
|
||||
else
|
||||
{
|
||||
RTLIL::SigSig new_conn;
|
||||
for (int i = 0; i < GetSize(s1); 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.second.append_bit(s2[i]);
|
||||
}
|
||||
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.second);
|
||||
module->connect(new_conn);
|
||||
}
|
||||
if (unused_bits.empty() || wire->port_id != 0)
|
||||
|
||||
if (!used_signals_nodrivers.check_all(s2)) {
|
||||
std::string unused_bits;
|
||||
for (int i = 0; i < GetSize(s2); i++) {
|
||||
if (s2[i].wire == NULL)
|
||||
continue;
|
||||
if (!used_signals_nodrivers.check(s2[i])) {
|
||||
if (!unused_bits.empty())
|
||||
unused_bits += " ";
|
||||
unused_bits += stringf("%d", i);
|
||||
}
|
||||
}
|
||||
if (unused_bits.empty() || wire->port_id != 0)
|
||||
wire->attributes.erase("\\unused_bits");
|
||||
else
|
||||
wire->attributes["\\unused_bits"] = RTLIL::Const(unused_bits);
|
||||
} else {
|
||||
wire->attributes.erase("\\unused_bits");
|
||||
else
|
||||
wire->attributes["\\unused_bits"] = RTLIL::Const(unused_bits);
|
||||
} else {
|
||||
wire->attributes.erase("\\unused_bits");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int del_temp_wires_count = 0;
|
||||
for (auto wire : del_wires_queue) {
|
||||
if (ys_debug() || (check_public_name(wire->name) && verbose))
|
||||
log_debug(" removing unused non-port wire %s.\n", wire->name.c_str());
|
||||
else
|
||||
del_temp_wires_count++;
|
||||
}
|
||||
|
||||
pool<RTLIL::Wire*> del_wires;
|
||||
module->remove(del_wires_queue);
|
||||
count_rm_wires += GetSize(del_wires_queue);
|
||||
|
||||
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());
|
||||
}
|
||||
del_wires.insert(wire);
|
||||
del_wires_count++;
|
||||
}
|
||||
if (verbose && del_temp_wires_count)
|
||||
log_debug(" removed %d unused temporary wires.\n", del_temp_wires_count);
|
||||
|
||||
module->remove(del_wires);
|
||||
count_rm_wires += del_wires.size();
|
||||
|
||||
if (verbose && del_wires_count > 0)
|
||||
log_debug(" removed %d unused temporary wires.\n", del_wires_count);
|
||||
return !del_wires_queue.empty();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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))
|
||||
rmunused_module_signals(module, purge_mode, verbose);
|
||||
while (rmunused_module_signals(module, purge_mode, verbose)) { }
|
||||
}
|
||||
|
||||
struct OptCleanPass : public Pass {
|
||||
|
@ -483,6 +547,9 @@ struct OptCleanPass : public Pass {
|
|||
|
||||
ct_all.setup(design);
|
||||
|
||||
count_rm_cells = 0;
|
||||
count_rm_wires = 0;
|
||||
|
||||
for (auto module : design->selected_whole_modules_warn()) {
|
||||
if (module->has_processes_warn())
|
||||
continue;
|
||||
|
@ -548,7 +615,7 @@ struct CleanPass : public Pass {
|
|||
for (auto module : design->selected_whole_modules()) {
|
||||
if (module->has_processes())
|
||||
continue;
|
||||
rmunused_module(module, purge_mode, false, false);
|
||||
rmunused_module(module, purge_mode, ys_debug(), false);
|
||||
}
|
||||
|
||||
log_suppressed();
|
||||
|
|
|
@ -39,6 +39,9 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
|
|||
SigPool used_signals;
|
||||
SigPool all_signals;
|
||||
|
||||
dict<SigBit, pair<Wire*, State>> initbits;
|
||||
pool<Wire*> revisit_initwires;
|
||||
|
||||
for (auto cell : module->cells())
|
||||
for (auto &conn : cell->connections()) {
|
||||
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()) {
|
||||
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)
|
||||
driven_signals.add(sigmap(wire));
|
||||
if (wire->port_output)
|
||||
if (wire->port_output || wire->get_bool_attribute("\\keep"))
|
||||
used_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)
|
||||
continue;
|
||||
|
||||
log_debug("Setting undriven signal in %s to undef: %s\n", RTLIL::id2cstr(module->name), log_signal(c));
|
||||
module->connect(RTLIL::SigSig(c, RTLIL::SigSpec(RTLIL::State::Sx, c.width)));
|
||||
Const val(RTLIL::State::Sx, GetSize(sig));
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
|
@ -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)" : "");
|
||||
root_mux_rerun.erase(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()) {
|
||||
|
@ -192,9 +196,14 @@ struct OptMuxtreeWorker
|
|||
log_assert(root_enable_muxes.at(mux_idx));
|
||||
root_mux_rerun.erase(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_assert(glob_abort_cnt > 0);
|
||||
|
||||
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)
|
||||
{
|
||||
if (glob_abort_cnt == 0) {
|
||||
log(" Giving up (too many iterations)\n");
|
||||
if (glob_abort_cnt == 0)
|
||||
return;
|
||||
}
|
||||
glob_abort_cnt--;
|
||||
|
||||
muxinfo_t &muxinfo = mux2info[mux_idx];
|
||||
|
@ -454,6 +461,7 @@ struct OptMuxtreeWorker
|
|||
|
||||
void eval_root_mux(int mux_idx)
|
||||
{
|
||||
log_assert(glob_abort_cnt > 0);
|
||||
knowledge_t knowledge;
|
||||
knowledge.known_inactive.resize(GetSize(bit2info));
|
||||
knowledge.known_active.resize(GetSize(bit2info));
|
||||
|
|
|
@ -260,8 +260,8 @@ delete_dlatch:
|
|||
|
||||
bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
|
||||
{
|
||||
RTLIL::SigSpec sig_d, sig_q, sig_c, sig_r;
|
||||
RTLIL::Const val_cp, val_rp, val_rv;
|
||||
RTLIL::SigSpec sig_d, sig_q, sig_c, sig_r, sig_e;
|
||||
RTLIL::Const val_cp, val_rp, val_rv, val_ep;
|
||||
|
||||
if (dff->type == "$_FF_") {
|
||||
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_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") {
|
||||
sig_d = dff->getPort("\\D");
|
||||
sig_q = dff->getPort("\\Q");
|
||||
|
@ -295,6 +305,14 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
|
|||
sig_c = dff->getPort("\\CLK");
|
||||
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") {
|
||||
sig_d = dff->getPort("\\D");
|
||||
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 (val_rv.bits.size() == 0)
|
||||
val_rv = val_init;
|
||||
// Q is permanently reset value or initial value
|
||||
mod->connect(sig_q, val_rv);
|
||||
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)) {
|
||||
// Q is permanently reset value
|
||||
mod->connect(sig_q, val_rv);
|
||||
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) {
|
||||
// Q is permanently initial value
|
||||
mod->connect(sig_q, val_init);
|
||||
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())) {
|
||||
// Q is permanently D
|
||||
mod->connect(sig_q, sig_d);
|
||||
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)) {
|
||||
// Q is permanently reset value or initial value
|
||||
if (sig_r.size())
|
||||
mod->connect(sig_q, val_rv);
|
||||
if (has_init)
|
||||
else if (has_init)
|
||||
mod->connect(sig_q, val_init);
|
||||
goto delete_dff;
|
||||
}
|
||||
|
||||
// If reset signal is present, and is fully constant
|
||||
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()) {
|
||||
// Q is permanently reset value
|
||||
mod->connect(sig_q, val_rv);
|
||||
goto delete_dff;
|
||||
}
|
||||
|
@ -389,6 +428,30 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
|
|||
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;
|
||||
|
||||
delete_dff:
|
||||
|
@ -489,7 +552,8 @@ struct OptRmdffPass : public Pass {
|
|||
if (cell->type.in("$_FF_", "$_DFF_N_", "$_DFF_P_",
|
||||
"$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
|
||||
"$_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);
|
||||
|
||||
if (cell->type.in("$dlatch", "$_DLATCH_P_", "$_DLATCH_N_"))
|
||||
|
|
|
@ -29,6 +29,7 @@ PRIVATE_NAMESPACE_BEGIN
|
|||
struct WreduceConfig
|
||||
{
|
||||
pool<IdString> supported_cell_types;
|
||||
bool keepdc = false;
|
||||
|
||||
WreduceConfig()
|
||||
{
|
||||
|
@ -82,7 +83,7 @@ struct WreduceWorker
|
|||
|
||||
SigBit ref = sig_a[i];
|
||||
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;
|
||||
if (sig_b[k*GetSize(sig_a) + i] != Sx)
|
||||
ref = sig_b[k*GetSize(sig_a) + i];
|
||||
|
@ -180,6 +181,8 @@ struct WreduceWorker
|
|||
}
|
||||
|
||||
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]))) {
|
||||
remove_init_bits.insert(sig_q[i]);
|
||||
sig_d.remove(i);
|
||||
|
@ -462,12 +465,10 @@ struct WreduceWorker
|
|||
SigSpec initsig = init_attr_sigmap(w);
|
||||
int width = std::min(GetSize(initval), GetSize(initsig));
|
||||
for (int i = 0; i < width; i++) {
|
||||
log_dump(initsig[i], remove_init_bits.count(initsig[i]));
|
||||
if (!remove_init_bits.count(initsig[i]))
|
||||
new_initval[i] = initval[i];
|
||||
}
|
||||
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(" flows that use the 'memory_memx' pass.\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
|
||||
{
|
||||
|
@ -509,6 +513,10 @@ struct WreducePass : public Pass {
|
|||
opt_memx = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-keepdc") {
|
||||
config.keepdc = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
@ -531,6 +539,42 @@ struct WreducePass : public Pass {
|
|||
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")) {
|
||||
IdString memid = c->getParam("\\MEMID").decode_string();
|
||||
RTLIL::Memory *mem = module->memories.at(memid);
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
/ice40_dsp_pm.h
|
||||
/peepopt_pm.h
|
||||
|
|
|
@ -1,8 +1,23 @@
|
|||
OBJS += passes/pmgen/ice40_dsp.o
|
||||
OBJS += passes/pmgen/peepopt.o
|
||||
|
||||
# --------------------------------------
|
||||
|
||||
passes/pmgen/ice40_dsp.o: passes/pmgen/ice40_dsp_pm.h
|
||||
EXTRA_OBJS += 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
|
||||
$(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 $<,$^)
|
||||
|
|
|
@ -29,19 +29,25 @@ up in any future matches:
|
|||
|
||||
pm.blacklist(some_cell);
|
||||
|
||||
The `.run(callback_function)` method searches for all matches and calls the
|
||||
callback function for each found match:
|
||||
The `.run_<pattern_name>(callback_function)` method searches for all matches
|
||||
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(" with 'bar' cell: %s\n", log_id(pm.st.bar));
|
||||
});
|
||||
|
||||
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
|
||||
`.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
|
||||
|
@ -52,6 +58,12 @@ lines consist of whitespace-separated tokens.
|
|||
|
||||
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
|
||||
-------------------------
|
||||
|
||||
|
@ -66,7 +78,7 @@ State variables are automatically managed by the generated backtracking algorith
|
|||
and saved and restored as needed.
|
||||
|
||||
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
|
||||
-------------------------
|
||||
|
@ -220,5 +232,5 @@ But in some cases it is more natural to utilize the implicit branch statement:
|
|||
portAB = \B;
|
||||
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.
|
||||
|
|
|
@ -19,47 +19,50 @@
|
|||
|
||||
#include "kernel/yosys.h"
|
||||
#include "kernel/sigtools.h"
|
||||
#include "passes/pmgen/ice40_dsp_pm.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
#include "passes/pmgen/ice40_dsp_pm.h"
|
||||
|
||||
void create_ice40_dsp(ice40_dsp_pm &pm)
|
||||
{
|
||||
auto &st = pm.st_ice40_dsp;
|
||||
|
||||
#if 0
|
||||
log("\n");
|
||||
log("ffA: %s\n", log_id(pm.st.ffA, "--"));
|
||||
log("ffB: %s\n", log_id(pm.st.ffB, "--"));
|
||||
log("mul: %s\n", log_id(pm.st.mul, "--"));
|
||||
log("ffY: %s\n", log_id(pm.st.ffY, "--"));
|
||||
log("addAB: %s\n", log_id(pm.st.addAB, "--"));
|
||||
log("muxAB: %s\n", log_id(pm.st.muxAB, "--"));
|
||||
log("ffS: %s\n", log_id(pm.st.ffS, "--"));
|
||||
log("ffA: %s\n", log_id(st.ffA, "--"));
|
||||
log("ffB: %s\n", log_id(st.ffB, "--"));
|
||||
log("mul: %s\n", log_id(st.mul, "--"));
|
||||
log("ffY: %s\n", log_id(st.ffY, "--"));
|
||||
log("addAB: %s\n", log_id(st.addAB, "--"));
|
||||
log("muxAB: %s\n", log_id(st.muxAB, "--"));
|
||||
log("ffS: %s\n", log_id(st.ffS, "--"));
|
||||
#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) {
|
||||
log(" input A (%s) is too large (%d > 16).\n", log_signal(pm.st.sigA), GetSize(pm.st.sigA));
|
||||
if (GetSize(st.sigA) > 16) {
|
||||
log(" input A (%s) is too large (%d > 16).\n", log_signal(st.sigA), GetSize(st.sigA));
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetSize(pm.st.sigB) > 16) {
|
||||
log(" input B (%s) is too large (%d > 16).\n", log_signal(pm.st.sigB), GetSize(pm.st.sigB));
|
||||
if (GetSize(st.sigB) > 16) {
|
||||
log(" input B (%s) is too large (%d > 16).\n", log_signal(st.sigB), GetSize(st.sigB));
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetSize(pm.st.sigS) > 32) {
|
||||
log(" accumulator (%s) is too large (%d > 32).\n", log_signal(pm.st.sigS), GetSize(pm.st.sigS));
|
||||
if (GetSize(st.sigS) > 32) {
|
||||
log(" accumulator (%s) is too large (%d > 32).\n", log_signal(st.sigS), GetSize(st.sigS));
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetSize(pm.st.sigY) > 32) {
|
||||
log(" output (%s) is too large (%d > 32).\n", log_signal(pm.st.sigY), GetSize(pm.st.sigY));
|
||||
if (GetSize(st.sigY) > 32) {
|
||||
log(" output (%s) is too large (%d > 32).\n", log_signal(st.sigY), GetSize(st.sigY));
|
||||
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) {
|
||||
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");
|
||||
|
||||
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
|
||||
|
||||
SigSpec A = pm.st.sigA;
|
||||
SigSpec A = st.sigA;
|
||||
A.extend_u0(16, mul_signed);
|
||||
|
||||
SigSpec B = pm.st.sigB;
|
||||
SigSpec B = st.sigB;
|
||||
B.extend_u0(16, mul_signed);
|
||||
|
||||
SigSpec CD;
|
||||
if (pm.st.muxA)
|
||||
CD = pm.st.muxA->getPort("\\B");
|
||||
if (pm.st.muxB)
|
||||
CD = pm.st.muxB->getPort("\\A");
|
||||
if (st.muxA)
|
||||
CD = st.muxA->getPort("\\B");
|
||||
if (st.muxB)
|
||||
CD = st.muxB->getPort("\\A");
|
||||
CD.extend_u0(32, mul_signed);
|
||||
|
||||
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("\\D", CD.extract(16, 16));
|
||||
|
||||
cell->setParam("\\A_REG", pm.st.ffA ? State::S1 : State::S0);
|
||||
cell->setParam("\\B_REG", pm.st.ffB ? State::S1 : State::S0);
|
||||
cell->setParam("\\A_REG", st.ffA ? State::S1 : State::S0);
|
||||
cell->setParam("\\B_REG", st.ffB ? State::S1 : State::S0);
|
||||
|
||||
cell->setPort("\\AHOLD", 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("\\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->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)
|
||||
log(" ffA:%s", log_id(pm.st.ffA));
|
||||
if (st.ffA)
|
||||
log(" ffA:%s", log_id(st.ffA));
|
||||
|
||||
if (pm.st.ffB)
|
||||
log(" ffB:%s", log_id(pm.st.ffB));
|
||||
if (st.ffB)
|
||||
log(" ffB:%s", log_id(st.ffB));
|
||||
|
||||
if (pm.st.ffY)
|
||||
log(" ffY:%s", log_id(pm.st.ffY));
|
||||
if (st.ffY)
|
||||
log(" ffY:%s", log_id(st.ffY));
|
||||
|
||||
if (pm.st.ffS)
|
||||
log(" ffS:%s", log_id(pm.st.ffS));
|
||||
if (st.ffS)
|
||||
log(" ffS:%s", log_id(st.ffS));
|
||||
|
||||
log("\n");
|
||||
}
|
||||
|
@ -144,16 +147,16 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
|
|||
|
||||
// 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)
|
||||
O.append(pm.module->addWire(NEW_ID, 32-GetSize(O)));
|
||||
|
||||
cell->setPort("\\O", O);
|
||||
|
||||
if (pm.st.addAB) {
|
||||
log(" accumulator %s (%s)\n", log_id(pm.st.addAB), log_id(pm.st.addAB->type));
|
||||
cell->setPort("\\ADDSUBTOP", pm.st.addAB->type == "$add" ? State::S0 : State::S1);
|
||||
cell->setPort("\\ADDSUBBOT", pm.st.addAB->type == "$add" ? State::S0 : State::S1);
|
||||
if (st.addAB) {
|
||||
log(" accumulator %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type));
|
||||
cell->setPort("\\ADDSUBTOP", st.addAB->type == "$add" ? State::S0 : State::S1);
|
||||
cell->setPort("\\ADDSUBBOT", st.addAB->type == "$add" ? State::S0 : State::S1);
|
||||
} else {
|
||||
cell->setPort("\\ADDSUBTOP", State::S0);
|
||||
cell->setPort("\\ADDSUBBOT", State::S0);
|
||||
|
@ -166,10 +169,10 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
|
|||
cell->setPort("\\OHOLDBOT", State::S0);
|
||||
|
||||
SigSpec acc_reset = State::S0;
|
||||
if (pm.st.muxA)
|
||||
acc_reset = pm.st.muxA->getPort("\\S");
|
||||
if (pm.st.muxB)
|
||||
acc_reset = pm.module->Not(NEW_ID, pm.st.muxB->getPort("\\S"));
|
||||
if (st.muxA)
|
||||
acc_reset = st.muxA->getPort("\\S");
|
||||
if (st.muxB)
|
||||
acc_reset = pm.module->Not(NEW_ID, st.muxB->getPort("\\S"));
|
||||
|
||||
cell->setPort("\\OLOADTOP", 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("\\D_REG", State::S0);
|
||||
|
||||
cell->setParam("\\TOP_8x8_MULT_REG", pm.st.ffY ? State::S1 : State::S0);
|
||||
cell->setParam("\\BOT_8x8_MULT_REG", pm.st.ffY ? State::S1 : State::S0);
|
||||
cell->setParam("\\PIPELINE_16x16_MULT_REG1", 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", 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("\\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_UPPERINPUT", State::S0);
|
||||
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_UPPERINPUT", State::S0);
|
||||
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("\\B_SIGNED", mul_signed ? State::S1 : State::S0);
|
||||
|
||||
pm.autoremove(pm.st.mul);
|
||||
pm.autoremove(pm.st.ffY);
|
||||
pm.autoremove(pm.st.ffS);
|
||||
pm.autoremove(st.mul);
|
||||
pm.autoremove(st.ffY);
|
||||
pm.autoremove(st.ffS);
|
||||
}
|
||||
|
||||
struct Ice40DspPass : public Pass {
|
||||
|
@ -230,7 +233,7 @@ struct Ice40DspPass : public Pass {
|
|||
extra_args(args, argidx, design);
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
pattern ice40_dsp
|
||||
|
||||
state <SigBit> clock
|
||||
state <bool> clock_pol clock_vld
|
||||
state <SigSpec> sigA sigB sigY sigS
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -3,15 +3,42 @@
|
|||
import re
|
||||
import sys
|
||||
import pprint
|
||||
import getopt
|
||||
|
||||
pp = pprint.PrettyPrinter(indent=4)
|
||||
|
||||
pmgfile = sys.argv[1]
|
||||
assert pmgfile.endswith(".pmg")
|
||||
prefix = pmgfile[0:-4]
|
||||
prefix = prefix.split('/')[-1]
|
||||
outfile = sys.argv[2]
|
||||
prefix = None
|
||||
pmgfiles = list()
|
||||
outfile = None
|
||||
debug = False
|
||||
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()
|
||||
udata_types = dict()
|
||||
blocks = list()
|
||||
|
@ -77,7 +104,8 @@ def rewrite_cpp(s):
|
|||
|
||||
return "".join(t)
|
||||
|
||||
with open(pmgfile, "r") as f:
|
||||
def process_pmgfile(f):
|
||||
global current_pattern
|
||||
while True:
|
||||
line = f.readline()
|
||||
if line == "": break
|
||||
|
@ -87,14 +115,31 @@ with open(pmgfile, "r") as f:
|
|||
if len(cmd) == 0 or cmd[0].startswith("//"): continue
|
||||
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":
|
||||
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
|
||||
type_str = m.group(1)
|
||||
states_str = m.group(2)
|
||||
for s in re.split(r"\s+", states_str):
|
||||
assert s not in state_types
|
||||
state_types[s] = type_str
|
||||
assert s not in state_types[current_pattern]
|
||||
state_types[current_pattern][s] = type_str
|
||||
continue
|
||||
|
||||
if cmd == "udata":
|
||||
|
@ -103,19 +148,20 @@ with open(pmgfile, "r") as f:
|
|||
type_str = m.group(1)
|
||||
udatas_str = m.group(2)
|
||||
for s in re.split(r"\s+", udatas_str):
|
||||
assert s not in udata_types
|
||||
udata_types[s] = type_str
|
||||
assert s not in udata_types[current_pattern]
|
||||
udata_types[current_pattern][s] = type_str
|
||||
continue
|
||||
|
||||
if cmd == "match":
|
||||
block = dict()
|
||||
block["type"] = "match"
|
||||
block["pattern"] = current_pattern
|
||||
|
||||
line = line.split()
|
||||
assert len(line) == 2
|
||||
assert line[1] not in state_types
|
||||
assert line[1] not in state_types[current_pattern]
|
||||
block["cell"] = line[1]
|
||||
state_types[line[1]] = "Cell*";
|
||||
state_types[current_pattern][line[1]] = "Cell*";
|
||||
|
||||
block["if"] = list()
|
||||
block["select"] = list()
|
||||
|
@ -158,15 +204,18 @@ with open(pmgfile, "r") as f:
|
|||
assert False
|
||||
|
||||
blocks.append(block)
|
||||
continue
|
||||
|
||||
if cmd == "code":
|
||||
block = dict()
|
||||
block["type"] = "code"
|
||||
block["pattern"] = current_pattern
|
||||
|
||||
block["code"] = list()
|
||||
block["states"] = set()
|
||||
|
||||
for s in line.split()[1:]:
|
||||
assert s in state_types
|
||||
assert s in state_types[current_pattern]
|
||||
block["states"].add(s)
|
||||
|
||||
while True:
|
||||
|
@ -179,17 +228,36 @@ with open(pmgfile, "r") as f:
|
|||
block["code"].append(rewrite_cpp(l.rstrip()))
|
||||
|
||||
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:
|
||||
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("#include \"kernel/yosys.h\"", file=f)
|
||||
print("#include \"kernel/sigtools.h\"", file=f)
|
||||
print("", file=f)
|
||||
|
||||
print("YOSYS_NAMESPACE_BEGIN", file=f)
|
||||
print("", file=f)
|
||||
if genhdr:
|
||||
print("#include \"kernel/yosys.h\"", file=f)
|
||||
print("#include \"kernel/sigtools.h\"", file=f)
|
||||
print("", file=f)
|
||||
print("YOSYS_NAMESPACE_BEGIN", file=f)
|
||||
print("", file=f)
|
||||
|
||||
print("struct {}_pm {{".format(prefix), file=f)
|
||||
print(" Module *module;", file=f)
|
||||
|
@ -212,17 +280,19 @@ with open(outfile, "w") as f:
|
|||
print(" int rollback;", file=f)
|
||||
print("", file=f)
|
||||
|
||||
print(" struct state_t {", file=f)
|
||||
for s, t in sorted(state_types.items()):
|
||||
print(" {} {};".format(t, s), file=f)
|
||||
print(" } st;", file=f)
|
||||
print("", file=f)
|
||||
for current_pattern in sorted(patterns.keys()):
|
||||
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(" }} st_{};".format(current_pattern), file=f)
|
||||
print("", file=f)
|
||||
|
||||
print(" struct udata_t {", file=f)
|
||||
for s, t in sorted(udata_types.items()):
|
||||
print(" {} {};".format(t, s), file=f)
|
||||
print(" } ud;", file=f)
|
||||
print("", file=f)
|
||||
print(" struct udata_{}_t {{".format(current_pattern), file=f)
|
||||
for s, t in sorted(udata_types[current_pattern].items()):
|
||||
print(" {} {};".format(t, s), file=f)
|
||||
print(" }} ud_{};".format(current_pattern), file=f)
|
||||
print("", file=f)
|
||||
current_pattern = None
|
||||
|
||||
for v, n in sorted(ids.items()):
|
||||
if n[0] == "\\":
|
||||
|
@ -258,20 +328,24 @@ with open(outfile, "w") as f:
|
|||
print(" }", file=f)
|
||||
print("", file=f)
|
||||
|
||||
print(" void check_blacklist() {", file=f)
|
||||
print(" if (!blacklist_dirty)", file=f)
|
||||
print(" return;", file=f)
|
||||
print(" blacklist_dirty = false;", file=f)
|
||||
for index in range(len(blocks)):
|
||||
block = blocks[index]
|
||||
if block["type"] == "match":
|
||||
print(" if (st.{} != nullptr && blacklist_cells.count(st.{})) {{".format(block["cell"], block["cell"]), file=f)
|
||||
print(" rollback = {};".format(index+1), file=f)
|
||||
print(" return;", file=f)
|
||||
print(" }", file=f)
|
||||
print(" rollback = 0;", file=f)
|
||||
print(" }", file=f)
|
||||
print("", 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(" return;", file=f)
|
||||
print(" blacklist_dirty = false;", file=f)
|
||||
for index in range(len(blocks)):
|
||||
block = blocks[index]
|
||||
if block["pattern"] != current_pattern:
|
||||
continue
|
||||
if block["type"] == "match":
|
||||
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(" return;", file=f)
|
||||
print(" }", file=f)
|
||||
print(" rollback = 0;", file=f)
|
||||
print(" }", file=f)
|
||||
print("", file=f)
|
||||
current_pattern = None
|
||||
|
||||
print(" SigSpec port(Cell *cell, IdString 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(" module(module), sigmap(module) {", file=f)
|
||||
for s, t in sorted(udata_types.items()):
|
||||
if t.endswith("*"):
|
||||
print(" ud.{} = nullptr;".format(s), file=f)
|
||||
else:
|
||||
print(" ud.{} = {}();".format(s, t), file=f)
|
||||
for current_pattern in sorted(patterns.keys()):
|
||||
for s, t in sorted(udata_types[current_pattern].items()):
|
||||
if t.endswith("*"):
|
||||
print(" ud_{}.{} = nullptr;".format(current_pattern,s), file=f)
|
||||
else:
|
||||
print(" ud_{}.{} = {}();".format(current_pattern, s, t), file=f)
|
||||
current_pattern = None
|
||||
print(" for (auto cell : module->cells()) {", file=f)
|
||||
print(" for (auto &conn : cell->connections())", 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(" void run(std::function<void()> on_accept_f) {", file=f)
|
||||
print(" on_accept = on_accept_f;", file=f)
|
||||
print(" rollback = 0;", file=f)
|
||||
print(" blacklist_dirty = false;", file=f)
|
||||
for s, t in sorted(state_types.items()):
|
||||
if t.endswith("*"):
|
||||
print(" st.{} = nullptr;".format(s), file=f)
|
||||
else:
|
||||
print(" st.{} = {}();".format(s, t), file=f)
|
||||
print(" block_0();", file=f)
|
||||
print(" }", file=f)
|
||||
print("", file=f)
|
||||
|
||||
print(" void run(std::function<void({}_pm&)> on_accept_f) {{".format(prefix), file=f)
|
||||
print(" run([&](){on_accept_f(*this);});", file=f)
|
||||
print(" }", file=f)
|
||||
print("", 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(" rollback = 0;", file=f)
|
||||
print(" blacklist_dirty = false;", file=f)
|
||||
for s, t in sorted(state_types[current_pattern].items()):
|
||||
if t.endswith("*"):
|
||||
print(" st_{}.{} = nullptr;".format(current_pattern, s), file=f)
|
||||
else:
|
||||
print(" st_{}.{} = {}();".format(current_pattern, s, t), file=f)
|
||||
print(" block_{}();".format(patterns[current_pattern]), 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(" run_{}([&](){{on_accept_f(*this);}});".format(current_pattern), 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)):
|
||||
block = blocks[index]
|
||||
|
||||
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()
|
||||
nonconst_st = set()
|
||||
restore_st = set()
|
||||
|
||||
for i in range(index):
|
||||
for i in range(patterns[current_pattern], index):
|
||||
if blocks[i]["type"] == "code":
|
||||
for s in blocks[i]["states"]:
|
||||
const_st.add(s)
|
||||
|
@ -378,27 +472,27 @@ with open(outfile, "w") as f:
|
|||
assert False
|
||||
|
||||
for s in sorted(const_st):
|
||||
t = state_types[s]
|
||||
t = state_types[current_pattern][s]
|
||||
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:
|
||||
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):
|
||||
t = state_types[s]
|
||||
print(" {} &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f)
|
||||
t = state_types[current_pattern][s]
|
||||
print(" {} &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f)
|
||||
|
||||
if len(restore_st):
|
||||
print("", file=f)
|
||||
for s in sorted(restore_st):
|
||||
t = state_types[s]
|
||||
t = state_types[current_pattern][s]
|
||||
print(" {} backup_{} = {};".format(t, s, s), file=f)
|
||||
|
||||
if block["type"] == "code":
|
||||
print("", file=f)
|
||||
print(" do {", file=f)
|
||||
print("#define reject do { check_blacklist(); goto rollback_label; } while(0)", file=f)
|
||||
print("#define accept do { on_accept(); check_blacklist(); if (rollback) 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)".format(current_pattern), file=f)
|
||||
print("#define branch do {{ block_{}(); if (rollback) goto rollback_label; }} while(0)".format(index+1), file=f)
|
||||
|
||||
for line in block["code"]:
|
||||
|
@ -417,11 +511,11 @@ with open(outfile, "w") as f:
|
|||
if len(restore_st) or len(nonconst_st):
|
||||
print("", file=f)
|
||||
for s in sorted(restore_st):
|
||||
t = state_types[s]
|
||||
t = state_types[current_pattern][s]
|
||||
print(" {} = backup_{};".format(s, s), file=f)
|
||||
for s in sorted(nonconst_st):
|
||||
if s not in restore_st:
|
||||
t = state_types[s]
|
||||
t = state_types[current_pattern][s]
|
||||
if t.endswith("*"):
|
||||
print(" {} = nullptr;".format(s), file=f)
|
||||
else:
|
||||
|
@ -470,17 +564,12 @@ with open(outfile, "w") as f:
|
|||
else:
|
||||
assert False
|
||||
|
||||
|
||||
current_pattern = None
|
||||
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)
|
||||
print("YOSYS_NAMESPACE_END", file=f)
|
||||
|
||||
# pp.pprint(blocks)
|
||||
if genhdr:
|
||||
print("", file=f)
|
||||
print("YOSYS_NAMESPACE_END", file=f)
|
||||
|
|
|
@ -508,7 +508,7 @@ struct ExposePass : public Pass {
|
|||
}
|
||||
|
||||
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)
|
||||
|
|
|
@ -26,6 +26,8 @@ PRIVATE_NAMESPACE_BEGIN
|
|||
|
||||
struct opts_t
|
||||
{
|
||||
bool initeq = false;
|
||||
bool anyeq = false;
|
||||
bool fwd = false;
|
||||
bool bwd = false;
|
||||
bool nop = false;
|
||||
|
@ -56,7 +58,7 @@ struct FmcombineWorker
|
|||
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);
|
||||
c->parameters = cell->parameters;
|
||||
|
@ -64,6 +66,8 @@ struct FmcombineWorker
|
|||
|
||||
for (auto &conn : cell->connections())
|
||||
c->setPort(conn.first, import_sig(conn.second, suffix));
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void import_hier_cell(Cell *cell)
|
||||
|
@ -102,8 +106,24 @@ struct FmcombineWorker
|
|||
|
||||
for (auto cell : original->cells()) {
|
||||
if (design->module(cell->type) == nullptr) {
|
||||
import_prim_cell(cell, "_gold");
|
||||
import_prim_cell(cell, "_gate");
|
||||
if (opts.anyeq && cell->type.in("$anyseq", "$anyconst")) {
|
||||
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 {
|
||||
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("a slight difference in input causes in a module.\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(" Insert forward hint assumptions into the combined module.\n");
|
||||
log("\n");
|
||||
|
@ -261,6 +288,14 @@ struct FmcombinePass : public Pass {
|
|||
// filename = args[++argidx];
|
||||
// continue;
|
||||
// }
|
||||
if (args[argidx] == "-initeq") {
|
||||
opts.initeq = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-anyeq") {
|
||||
opts.anyeq = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-fwd") {
|
||||
opts.fwd = true;
|
||||
continue;
|
||||
|
@ -297,7 +332,7 @@ struct FmcombinePass : public Pass {
|
|||
|
||||
gate_cell = module->cell(gate_name);
|
||||
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
|
||||
{
|
||||
|
@ -316,7 +351,7 @@ struct FmcombinePass : public Pass {
|
|||
if (!gold_cell->parameters.empty())
|
||||
log_cmd_error("Gold cell has unresolved instance parameters.\n");
|
||||
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);
|
||||
worker.generate();
|
||||
|
|
|
@ -1169,6 +1169,7 @@ struct SatPass : public Pass {
|
|||
if (args[argidx] == "-tempinduct-def") {
|
||||
tempinduct = true;
|
||||
tempinduct_def = true;
|
||||
enable_undef = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-tempinduct-baseonly") {
|
||||
|
|
|
@ -88,6 +88,8 @@ struct SimInstance
|
|||
SimInstance(SimShared *shared, Module *module, Cell *instance = nullptr, SimInstance *parent = nullptr) :
|
||||
shared(shared), module(module), instance(instance), parent(parent), sigmap(module)
|
||||
{
|
||||
log_assert(module);
|
||||
|
||||
if (parent) {
|
||||
log_assert(parent->children.count(instance) == 0);
|
||||
parent->children[instance] = this;
|
||||
|
@ -848,6 +850,9 @@ struct SimPass : public Pass {
|
|||
|
||||
if (design->full_selection()) {
|
||||
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 {
|
||||
auto mods = design->selected_whole_modules();
|
||||
if (GetSize(mods) != 1)
|
||||
|
|
|
@ -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 abc_sname = abc_name.substr(1);
|
||||
if (abc_sname.substr(0, 5) == "ys__n") {
|
||||
bool inv = abc_sname.back() == 'v';
|
||||
if (inv) abc_sname.pop_back();
|
||||
bool isnew = false;
|
||||
if (abc_sname.substr(0, 4) == "new_")
|
||||
{
|
||||
abc_sname.erase(0, 4);
|
||||
isnew = true;
|
||||
}
|
||||
if (abc_sname.substr(0, 5) == "ys__n")
|
||||
{
|
||||
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);
|
||||
for (auto sig : signal_list) {
|
||||
if (sig.id == sid && sig.bit.wire != nullptr) {
|
||||
size_t postfix_start = abc_sname.find_first_not_of("0123456789");
|
||||
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;
|
||||
sstr << "$abc$" << map_autoidx << "$" << sig.bit.wire->name.substr(1);
|
||||
if (sig.bit.wire->width != 1)
|
||||
sstr << "[" << sig.bit.offset << "]";
|
||||
if (inv)
|
||||
sstr << "_inv";
|
||||
if (isnew)
|
||||
sstr << "_new";
|
||||
sstr << postfix;
|
||||
if (orig_wire != nullptr)
|
||||
*orig_wire = sig.bit.wire;
|
||||
return sstr.str();
|
||||
|
|
|
@ -102,7 +102,8 @@ struct DffinitPass : public Pass {
|
|||
if (wire->attributes.count("\\init")) {
|
||||
Const value = wire->attributes.at("\\init");
|
||||
for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++)
|
||||
init_bits[sigmap(SigBit(wire, i))] = value[i];
|
||||
if (value[i] != State::Sx)
|
||||
init_bits[sigmap(SigBit(wire, i))] = value[i];
|
||||
}
|
||||
if (wire->port_output)
|
||||
for (auto bit : sigmap(wire))
|
||||
|
|
|
@ -397,7 +397,6 @@ struct FlowGraph
|
|||
pool<RTLIL::SigBit> x, xi;
|
||||
|
||||
NodePrime source_prime = {source, true};
|
||||
NodePrime sink_prime = {sink, false};
|
||||
pool<NodePrime> visited;
|
||||
vector<NodePrime> worklist = {source_prime};
|
||||
while (!worklist.empty())
|
||||
|
@ -1382,7 +1381,8 @@ struct FlowmapWorker
|
|||
|
||||
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));
|
||||
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();
|
||||
for (size_t n = 0; n < input_nodes.size(); n++)
|
||||
|
|
|
@ -94,7 +94,7 @@ int LibertyParser::lexer(std::string &str)
|
|||
|
||||
// search for identifiers, numbers, plus or minus.
|
||||
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) {
|
||||
c = f.get();
|
||||
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.')
|
||||
|
|
|
@ -58,12 +58,21 @@ struct MuxcoverWorker
|
|||
bool use_mux16;
|
||||
bool nodecode;
|
||||
|
||||
int cost_mux2;
|
||||
int cost_mux4;
|
||||
int cost_mux8;
|
||||
int cost_mux16;
|
||||
|
||||
MuxcoverWorker(Module *module) : module(module), sigmap(module)
|
||||
{
|
||||
use_mux4 = false;
|
||||
use_mux8 = false;
|
||||
use_mux16 = false;
|
||||
nodecode = false;
|
||||
cost_mux2 = COST_MUX2;
|
||||
cost_mux4 = COST_MUX4;
|
||||
cost_mux8 = COST_MUX8;
|
||||
cost_mux16 = COST_MUX16;
|
||||
decode_mux_counter = 0;
|
||||
}
|
||||
|
||||
|
@ -157,7 +166,7 @@ struct MuxcoverWorker
|
|||
if (std::get<2>(entry))
|
||||
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)
|
||||
|
@ -209,7 +218,7 @@ struct MuxcoverWorker
|
|||
mux.inputs.push_back(B);
|
||||
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, B);
|
||||
|
||||
|
@ -247,7 +256,7 @@ struct MuxcoverWorker
|
|||
mux.selects.push_back(S1);
|
||||
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, B);
|
||||
mux.cost += find_best_cover(tree, C);
|
||||
|
@ -310,7 +319,7 @@ struct MuxcoverWorker
|
|||
mux.selects.push_back(T1);
|
||||
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, B);
|
||||
mux.cost += find_best_cover(tree, C);
|
||||
|
@ -414,7 +423,7 @@ struct MuxcoverWorker
|
|||
mux.selects.push_back(U1);
|
||||
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, B);
|
||||
mux.cost += find_best_cover(tree, C);
|
||||
|
@ -569,9 +578,11 @@ struct MuxcoverPass : public Pass {
|
|||
log("\n");
|
||||
log("Cover trees of $_MUX_ cells with $_MUX{4,8,16}_ cells\n");
|
||||
log("\n");
|
||||
log(" -mux4, -mux8, -mux16\n");
|
||||
log(" Use the specified types of MUXes. If none of those options are used,\n");
|
||||
log(" the effect is the same as if all of them where used.\n");
|
||||
log(" -mux4[=cost], -mux8[=cost], -mux16[=cost]\n");
|
||||
log(" Use the specified types of MUXes (with optional integer costs). If none\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(" -nodecode\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_mux16 = false;
|
||||
bool nodecode = false;
|
||||
int cost_mux4 = COST_MUX4;
|
||||
int cost_mux8 = COST_MUX8;
|
||||
int cost_mux16 = COST_MUX16;
|
||||
|
||||
size_t 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;
|
||||
if (arg.size() > 5) {
|
||||
if (arg[5] != '=') break;
|
||||
cost_mux4 = atoi(arg.substr(5).c_str());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-mux8") {
|
||||
if (arg.size() >= 5 && arg.substr(0,5) == "-mux8") {
|
||||
use_mux8 = true;
|
||||
if (arg.size() > 5) {
|
||||
if (arg[5] != '=') break;
|
||||
cost_mux8 = atoi(arg.substr(5).c_str());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-mux16") {
|
||||
if (arg.size() >= 6 && arg.substr(0,6) == "-mux16") {
|
||||
use_mux16 = true;
|
||||
if (arg.size() > 6) {
|
||||
if (arg[6] != '=') break;
|
||||
cost_mux16 = atoi(arg.substr(6).c_str());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-nodecode") {
|
||||
if (arg == "-nodecode") {
|
||||
nodecode = true;
|
||||
continue;
|
||||
}
|
||||
|
@ -623,6 +650,9 @@ struct MuxcoverPass : public Pass {
|
|||
worker.use_mux4 = use_mux4;
|
||||
worker.use_mux8 = use_mux8;
|
||||
worker.use_mux16 = use_mux16;
|
||||
worker.cost_mux4 = cost_mux4;
|
||||
worker.cost_mux8 = cost_mux8;
|
||||
worker.cost_mux16 = cost_mux16;
|
||||
worker.nodecode = nodecode;
|
||||
worker.run();
|
||||
}
|
||||
|
|
|
@ -178,7 +178,17 @@ struct ShregmapTechXilinx7 : ShregmapTech
|
|||
|
||||
// Only map if $shiftx exclusively covers the shift register
|
||||
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;
|
||||
}
|
||||
else if (shiftx->type == "$mux") {
|
||||
|
@ -596,6 +606,9 @@ struct ShregmapPass : public Pass {
|
|||
log(" -tech greenpak4\n");
|
||||
log(" map to greenpak4 shift registers.\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
|
||||
{
|
||||
|
|
|
@ -46,7 +46,7 @@ struct ZinitPass : public Pass {
|
|||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
{
|
||||
if (args[argidx] == "-singleton") {
|
||||
if (args[argidx] == "-all") {
|
||||
all_mode = true;
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -195,9 +195,11 @@ struct PrepPass : public ScriptPass
|
|||
run(nokeepdc ? "opt" : "opt -keepdc");
|
||||
if (!ifxmode) {
|
||||
if (help_mode)
|
||||
run("wreduce [-memx]");
|
||||
else
|
||||
run("wreduce -keepdc [-memx]");
|
||||
else if (nokeepdc)
|
||||
run(memxmode ? "wreduce -memx" : "wreduce");
|
||||
else
|
||||
run(memxmode ? "wreduce -keepdc -memx" : "wreduce -keepdc");
|
||||
}
|
||||
if (!nomemmode) {
|
||||
run(string("memory_dff") + (help_mode ? " [-nordff]" : nordff ? " -nordff" : ""));
|
||||
|
|
|
@ -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);
|
||||
|
||||
input A, EN;
|
||||
|
@ -1863,4 +2038,5 @@ end
|
|||
endmodule
|
||||
|
||||
`endif
|
||||
|
||||
// --------------------------------------------------------
|
||||
|
|
|
@ -209,6 +209,8 @@ struct SynthPass : public ScriptPass
|
|||
run("check");
|
||||
run("opt");
|
||||
run("wreduce");
|
||||
run("peepopt");
|
||||
run("opt_clean");
|
||||
if (help_mode)
|
||||
run("techmap -map +/cmp2lut.v", " (if -lut)");
|
||||
else
|
||||
|
|
|
@ -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_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
|
||||
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
|
||||
|
||||
|
|
|
@ -253,7 +253,7 @@ struct SynthEcp5Pass : public ScriptPass
|
|||
if (!nodffe)
|
||||
run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*");
|
||||
run("techmap -D NO_LUT -map +/ecp5/cells_map.v");
|
||||
run("opt_expr -mux_undef");
|
||||
run("opt_expr -undriven -mux_undef");
|
||||
run("simplemap");
|
||||
run("ecp5_ffinit");
|
||||
}
|
||||
|
|
|
@ -957,10 +957,21 @@ endmodule
|
|||
|
||||
(* blackbox *)
|
||||
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 CLKHFEN,
|
||||
output CLKHF
|
||||
);
|
||||
parameter TRIM_EN = "0b0";
|
||||
parameter CLKHF_DIV = "0b00";
|
||||
endmodule
|
||||
|
||||
|
@ -989,6 +1000,30 @@ parameter RGB1_CURRENT = "0b000000";
|
|||
parameter RGB2_CURRENT = "0b000000";
|
||||
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 *)
|
||||
module SB_I2C(
|
||||
input SBCLKI,
|
||||
|
|
|
@ -245,11 +245,13 @@ struct SynthIce40Pass : public ScriptPass
|
|||
run("proc");
|
||||
}
|
||||
|
||||
if (flatten && check_label("flatten", "(unless -noflatten)"))
|
||||
if (check_label("flatten", "(unless -noflatten)"))
|
||||
{
|
||||
run("flatten");
|
||||
run("tribuf -logic");
|
||||
run("deminout");
|
||||
if (flatten) {
|
||||
run("flatten");
|
||||
run("tribuf -logic");
|
||||
run("deminout");
|
||||
}
|
||||
}
|
||||
|
||||
if (check_label("coarse"))
|
||||
|
@ -259,6 +261,8 @@ struct SynthIce40Pass : public ScriptPass
|
|||
run("check");
|
||||
run("opt");
|
||||
run("wreduce");
|
||||
run("peepopt");
|
||||
run("opt_clean");
|
||||
run("share");
|
||||
run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4");
|
||||
run("opt_expr");
|
||||
|
|
|
@ -17,254 +17,243 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/celltypes.h"
|
||||
#include "kernel/rtlil.h"
|
||||
#include "kernel/log.h"
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/rtlil.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
struct SynthIntelPass : public ScriptPass {
|
||||
SynthIntelPass() : ScriptPass("synth_intel", "synthesis for Intel (Altera) FPGAs.") { }
|
||||
SynthIntelPass() : ScriptPass("synth_intel", "synthesis for Intel (Altera) FPGAs.") {}
|
||||
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" synth_intel [options]\n");
|
||||
log("\n");
|
||||
log("This command runs synthesis for Intel FPGAs.\n");
|
||||
log("\n");
|
||||
log(" -family < max10 | a10gx | cyclone10 | cyclonev | cycloneiv | cycloneive>\n");
|
||||
log(" generate the synthesis netlist for the specified family.\n");
|
||||
log(" MAX10 is the default target if no family argument specified.\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("\n");
|
||||
log(" -top <module>\n");
|
||||
log(" use the specified module as top module (default='top')\n");
|
||||
log("\n");
|
||||
log(" -vqm <file>\n");
|
||||
log(" write the design to the specified Verilog Quartus Mapping File. Writing of an\n");
|
||||
log(" output file is omitted if this parameter is not specified.\n");
|
||||
log("\n");
|
||||
log(" -vpr <file>\n");
|
||||
log(" write BLIF files for VPR flow experiments. The synthesized BLIF output file is not\n");
|
||||
log(" compatible with the Quartus flow. Writing of an\n");
|
||||
log(" output file is omitted if this parameter is not specified.\n");
|
||||
log("\n");
|
||||
log(" -run <from_label>:<to_label>\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(" synonymous to the end of the command list.\n");
|
||||
log("\n");
|
||||
log(" -noiopads\n");
|
||||
log(" do not use altsyncram cells in output netlist\n");
|
||||
log("\n");
|
||||
log(" -nobram\n");
|
||||
log(" do not use altsyncram cells in output netlist\n");
|
||||
log("\n");
|
||||
log(" -noflatten\n");
|
||||
log(" do not flatten design before synthesis\n");
|
||||
log("\n");
|
||||
log(" -retime\n");
|
||||
log(" run 'abc' with -dff option\n");
|
||||
log("\n");
|
||||
log("The following commands are executed by this synthesis command:\n");
|
||||
help_script();
|
||||
log("\n");
|
||||
}
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" synth_intel [options]\n");
|
||||
log("\n");
|
||||
log("This command runs synthesis for Intel FPGAs.\n");
|
||||
log("\n");
|
||||
log(" -family < max10 | a10gx | cyclone10 | cyclonev | cycloneiv | cycloneive>\n");
|
||||
log(" generate the synthesis netlist for the specified family.\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(" Cyclone V and Arria 10 GX devices are experimental, use it with a10gx argument.\n");
|
||||
log("\n");
|
||||
log(" -top <module>\n");
|
||||
log(" use the specified module as top module (default='top')\n");
|
||||
log("\n");
|
||||
log(" -vqm <file>\n");
|
||||
log(" write the design to the specified Verilog Quartus Mapping File. Writing of an\n");
|
||||
log(" output file is omitted if this parameter is not specified.\n");
|
||||
log("\n");
|
||||
log(" -vpr <file>\n");
|
||||
log(" write BLIF files for VPR flow experiments. The synthesized BLIF output file is not\n");
|
||||
log(" compatible with the Quartus flow. Writing of an\n");
|
||||
log(" output file is omitted if this parameter is not specified.\n");
|
||||
log("\n");
|
||||
log(" -run <from_label>:<to_label>\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(" synonymous to the end of the command list.\n");
|
||||
log("\n");
|
||||
log(" -noiopads\n");
|
||||
log(" do not use altsyncram cells in output netlist\n");
|
||||
log("\n");
|
||||
log(" -nobram\n");
|
||||
log(" do not use altsyncram cells in output netlist\n");
|
||||
log("\n");
|
||||
log(" -noflatten\n");
|
||||
log(" do not flatten design before synthesis\n");
|
||||
log("\n");
|
||||
log(" -retime\n");
|
||||
log(" run 'abc' with -dff option\n");
|
||||
log("\n");
|
||||
log("The following commands are executed by this synthesis command:\n");
|
||||
help_script();
|
||||
log("\n");
|
||||
}
|
||||
|
||||
string top_opt, family_opt, vout_file, blif_file;
|
||||
bool retime, flatten, nobram, noiopads;
|
||||
string top_opt, family_opt, vout_file, blif_file;
|
||||
bool retime, flatten, nobram, noiopads;
|
||||
|
||||
void clear_flags() YS_OVERRIDE
|
||||
{
|
||||
top_opt = "-auto-top";
|
||||
family_opt = "max10";
|
||||
vout_file = "";
|
||||
blif_file = "";
|
||||
retime = false;
|
||||
flatten = true;
|
||||
nobram = false;
|
||||
noiopads = false;
|
||||
}
|
||||
void clear_flags() YS_OVERRIDE
|
||||
{
|
||||
top_opt = "-auto-top";
|
||||
family_opt = "max10";
|
||||
vout_file = "";
|
||||
blif_file = "";
|
||||
retime = false;
|
||||
flatten = true;
|
||||
nobram = false;
|
||||
noiopads = false;
|
||||
}
|
||||
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
string run_from, run_to;
|
||||
clear_flags();
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
string run_from, run_to;
|
||||
clear_flags();
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
{
|
||||
if (args[argidx] == "-family" && argidx+1 < args.size()) {
|
||||
family_opt = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-top" && argidx+1 < args.size()) {
|
||||
top_opt = "-top " + args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-vqm" && argidx+1 < args.size()) {
|
||||
vout_file = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-vpr" && argidx+1 < args.size()) {
|
||||
blif_file = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-run" && argidx+1 < args.size()) {
|
||||
size_t pos = args[argidx+1].find(':');
|
||||
if (pos == std::string::npos)
|
||||
break;
|
||||
run_from = args[++argidx].substr(0, pos);
|
||||
run_to = args[argidx].substr(pos+1);
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-noiopads") {
|
||||
noiopads = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-nobram") {
|
||||
nobram = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-noflatten") {
|
||||
flatten = false;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-retime") {
|
||||
retime = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||
if (args[argidx] == "-family" && argidx + 1 < args.size()) {
|
||||
family_opt = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-top" && argidx + 1 < args.size()) {
|
||||
top_opt = "-top " + args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-vqm" && argidx + 1 < args.size()) {
|
||||
vout_file = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-vpr" && argidx + 1 < args.size()) {
|
||||
blif_file = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-run" && argidx + 1 < args.size()) {
|
||||
size_t pos = args[argidx + 1].find(':');
|
||||
if (pos == std::string::npos)
|
||||
break;
|
||||
run_from = args[++argidx].substr(0, pos);
|
||||
run_to = args[argidx].substr(pos + 1);
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-noiopads") {
|
||||
noiopads = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-nobram") {
|
||||
nobram = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-noflatten") {
|
||||
flatten = false;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-retime") {
|
||||
retime = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
if (!design->full_selection())
|
||||
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")
|
||||
log_cmd_error("Invalid or no family specified: '%s'\n", family_opt.c_str());
|
||||
if (!design->full_selection())
|
||||
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")
|
||||
log_cmd_error("Invalid or not family specified: '%s'\n", family_opt.c_str());
|
||||
|
||||
log_header(design, "Executing SYNTH_INTEL pass.\n");
|
||||
log_push();
|
||||
log_header(design, "Executing SYNTH_INTEL pass.\n");
|
||||
log_push();
|
||||
|
||||
run_script(design, run_from, run_to);
|
||||
run_script(design, run_from, run_to);
|
||||
|
||||
log_pop();
|
||||
}
|
||||
log_pop();
|
||||
}
|
||||
|
||||
void script() YS_OVERRIDE
|
||||
{
|
||||
if (check_label("begin"))
|
||||
{
|
||||
if(check_label("family") && family_opt=="max10")
|
||||
run("read_verilog -sv -lib +/intel/max10/cells_sim.v");
|
||||
else if(check_label("family") && family_opt=="a10gx")
|
||||
run("read_verilog -sv -lib +/intel/a10gx/cells_sim.v");
|
||||
else if(check_label("family") && family_opt=="cyclonev")
|
||||
run("read_verilog -sv -lib +/intel/cyclonev/cells_sim.v");
|
||||
else if(check_label("family") && family_opt=="cyclone10")
|
||||
run("read_verilog -sv -lib +/intel/cyclone10/cells_sim.v");
|
||||
else if(check_label("family") && family_opt=="cycloneiv")
|
||||
run("read_verilog -sv -lib +/intel/cycloneiv/cells_sim.v");
|
||||
else
|
||||
run("read_verilog -sv -lib +/intel/cycloneive/cells_sim.v");
|
||||
// Misc and common cells
|
||||
run("read_verilog -sv -lib +/intel/common/m9k_bb.v");
|
||||
run("read_verilog -sv -lib +/intel/common/altpll_bb.v");
|
||||
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
|
||||
}
|
||||
void script() YS_OVERRIDE
|
||||
{
|
||||
if (check_label("begin")) {
|
||||
if (check_label("family") && family_opt == "max10")
|
||||
run("read_verilog -sv -lib +/intel/max10/cells_sim.v");
|
||||
else if (check_label("family") && family_opt == "a10gx")
|
||||
run("read_verilog -sv -lib +/intel/a10gx/cells_sim.v");
|
||||
else if (check_label("family") && family_opt == "cyclonev")
|
||||
run("read_verilog -sv -lib +/intel/cyclonev/cells_sim.v");
|
||||
else if (check_label("family") && family_opt == "cyclone10")
|
||||
run("read_verilog -sv -lib +/intel/cyclone10/cells_sim.v");
|
||||
else if (check_label("family") && family_opt == "cycloneiv")
|
||||
run("read_verilog -sv -lib +/intel/cycloneiv/cells_sim.v");
|
||||
else
|
||||
run("read_verilog -sv -lib +/intel/cycloneive/cells_sim.v");
|
||||
// Misc and common cells
|
||||
run("read_verilog -sv -lib +/intel/common/m9k_bb.v");
|
||||
run("read_verilog -sv -lib +/intel/common/altpll_bb.v");
|
||||
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
|
||||
}
|
||||
|
||||
if (flatten && check_label("flatten", "(unless -noflatten)"))
|
||||
{
|
||||
run("proc");
|
||||
run("flatten");
|
||||
run("tribuf -logic");
|
||||
run("deminout");
|
||||
}
|
||||
if (flatten && check_label("flatten", "(unless -noflatten)")) {
|
||||
run("proc");
|
||||
run("flatten");
|
||||
run("tribuf -logic");
|
||||
run("deminout");
|
||||
}
|
||||
|
||||
if (check_label("coarse"))
|
||||
{
|
||||
run("synth -run coarse");
|
||||
}
|
||||
if (check_label("coarse")) {
|
||||
run("synth -run coarse");
|
||||
}
|
||||
|
||||
if (!nobram && check_label("bram", "(skip if -nobram)"))
|
||||
{
|
||||
run("memory_bram -rules +/intel/common/brams.txt");
|
||||
run("techmap -map +/intel/common/brams_map.v");
|
||||
}
|
||||
if (!nobram && check_label("bram", "(skip if -nobram)")) {
|
||||
run("memory_bram -rules +/intel/common/brams.txt");
|
||||
run("techmap -map +/intel/common/brams_map.v");
|
||||
}
|
||||
|
||||
if (check_label("fine"))
|
||||
{
|
||||
run("opt -fast -mux_undef -undriven -fine -full");
|
||||
run("memory_map");
|
||||
run("opt -undriven -fine");
|
||||
run("dffsr2dff");
|
||||
run("dff2dffe -direct-match $_DFF_*");
|
||||
run("opt -fine");
|
||||
run("techmap -map +/techmap.v");
|
||||
run("opt -full");
|
||||
run("clean -purge");
|
||||
run("setundef -undriven -zero");
|
||||
if (retime || help_mode)
|
||||
run("abc -markgroups -dff", "(only if -retime)");
|
||||
}
|
||||
if (check_label("fine")) {
|
||||
run("opt -fast -mux_undef -undriven -fine -full");
|
||||
run("memory_map");
|
||||
run("opt -undriven -fine");
|
||||
run("dffsr2dff");
|
||||
run("dff2dffe -direct-match $_DFF_*");
|
||||
run("opt -fine");
|
||||
run("techmap -map +/techmap.v");
|
||||
run("opt -full");
|
||||
run("clean -purge");
|
||||
run("setundef -undriven -zero");
|
||||
if (retime || help_mode)
|
||||
run("abc -markgroups -dff", "(only if -retime)");
|
||||
}
|
||||
|
||||
if (check_label("map_luts"))
|
||||
{
|
||||
if(family_opt=="a10gx" || family_opt=="cyclonev")
|
||||
run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : ""));
|
||||
else
|
||||
run("abc -lut 4" + string(retime ? " -dff" : ""));
|
||||
run("clean");
|
||||
}
|
||||
if (check_label("map_luts")) {
|
||||
if (family_opt == "a10gx" || family_opt == "cyclonev")
|
||||
run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : ""));
|
||||
else
|
||||
run("abc -lut 4" + string(retime ? " -dff" : ""));
|
||||
run("clean");
|
||||
}
|
||||
|
||||
if (check_label("map_cells"))
|
||||
{
|
||||
if (!noiopads)
|
||||
run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(unless -noiopads)");
|
||||
if(family_opt=="max10")
|
||||
run("techmap -map +/intel/max10/cells_map.v");
|
||||
else if(family_opt=="a10gx")
|
||||
run("techmap -map +/intel/a10gx/cells_map.v");
|
||||
else if(family_opt=="cyclonev")
|
||||
run("techmap -map +/intel/cyclonev/cells_map.v");
|
||||
else if(family_opt=="cyclone10")
|
||||
run("techmap -map +/intel/cyclone10/cells_map.v");
|
||||
else if(family_opt=="cycloneiv")
|
||||
run("techmap -map +/intel/cycloneiv/cells_map.v");
|
||||
else
|
||||
run("techmap -map +/intel/cycloneive/cells_map.v");
|
||||
run("dffinit -highlow -ff dffeas q power_up");
|
||||
run("clean -purge");
|
||||
}
|
||||
if (check_label("map_cells")) {
|
||||
if (!noiopads)
|
||||
run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(unless -noiopads)");
|
||||
if (family_opt == "max10")
|
||||
run("techmap -map +/intel/max10/cells_map.v");
|
||||
else if (family_opt == "a10gx")
|
||||
run("techmap -map +/intel/a10gx/cells_map.v");
|
||||
else if (family_opt == "cyclonev")
|
||||
run("techmap -map +/intel/cyclonev/cells_map.v");
|
||||
else if (family_opt == "cyclone10")
|
||||
run("techmap -map +/intel/cyclone10/cells_map.v");
|
||||
else if (family_opt == "cycloneiv")
|
||||
run("techmap -map +/intel/cycloneiv/cells_map.v");
|
||||
else
|
||||
run("techmap -map +/intel/cycloneive/cells_map.v");
|
||||
run("dffinit -highlow -ff dffeas q power_up");
|
||||
run("clean -purge");
|
||||
}
|
||||
|
||||
if (check_label("check"))
|
||||
{
|
||||
run("hierarchy -check");
|
||||
run("stat");
|
||||
run("check -noinit");
|
||||
}
|
||||
if (check_label("check")) {
|
||||
run("hierarchy -check");
|
||||
run("stat");
|
||||
run("check -noinit");
|
||||
}
|
||||
|
||||
if (check_label("vqm"))
|
||||
{
|
||||
if (!vout_file.empty() || help_mode)
|
||||
run(stringf("write_verilog -attr2comment -defparam -nohex -decimal -renameprefix syn_ %s",
|
||||
help_mode ? "<file-name>" : vout_file.c_str()));
|
||||
}
|
||||
if (check_label("vqm")) {
|
||||
if (!vout_file.empty() || help_mode)
|
||||
run(stringf("write_verilog -attr2comment -defparam -nohex -decimal -renameprefix syn_ %s",
|
||||
help_mode ? "<file-name>" : vout_file.c_str()));
|
||||
}
|
||||
|
||||
if (check_label("vpr"))
|
||||
{
|
||||
if (!blif_file.empty() || help_mode)
|
||||
{
|
||||
run(stringf("opt_clean -purge"));
|
||||
run(stringf("write_blif %s", help_mode ? "<file-name>" : blif_file.c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (check_label("vpr")) {
|
||||
if (!blif_file.empty() || help_mode) {
|
||||
run(stringf("opt_clean -purge"));
|
||||
run(stringf("write_blif %s", help_mode ? "<file-name>" : blif_file.c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
} SynthIntelPass;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
||||
|
|
|
@ -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);
|
||||
parameter DEPTH = 0;
|
||||
parameter [DEPTH-1:0] INIT = 0;
|
||||
|
|
|
@ -26,11 +26,15 @@ bram $__XILINX_RAM128X1D
|
|||
endbram
|
||||
|
||||
match $__XILINX_RAM64X1D
|
||||
min bits 5
|
||||
min wports 1
|
||||
make_outreg
|
||||
or_next_if_better
|
||||
endmatch
|
||||
|
||||
match $__XILINX_RAM128X1D
|
||||
min bits 9
|
||||
min wports 1
|
||||
make_outreg
|
||||
endmatch
|
||||
|
||||
|
|
|
@ -22,26 +22,21 @@
|
|||
|
||||
`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_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_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_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_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_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
|
||||
`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
|
||||
|
||||
|
|
|
@ -25,18 +25,9 @@
|
|||
USING_YOSYS_NAMESPACE
|
||||
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)
|
||||
active = true;
|
||||
if (label == run_to)
|
||||
active = false;
|
||||
return active;
|
||||
}
|
||||
|
||||
struct SynthXilinxPass : public Pass
|
||||
{
|
||||
SynthXilinxPass() : Pass("synth_xilinx", "synthesis for Xilinx FPGAs") { }
|
||||
SynthXilinxPass() : ScriptPass("synth_xilinx", "synthesis for Xilinx FPGAs") { }
|
||||
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
|
@ -51,6 +42,10 @@ struct SynthXilinxPass : public Pass
|
|||
log(" -top <module>\n");
|
||||
log(" use the specified module as top module\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(" write the design to the specified edif file. writing of an output file\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(" (this feature is experimental and incomplete)\n");
|
||||
log("\n");
|
||||
log(" -nocarry\n");
|
||||
log(" disable inference of carry chains\n");
|
||||
log("\n");
|
||||
log(" -nobram\n");
|
||||
log(" disable inference of block rams\n");
|
||||
log("\n");
|
||||
|
@ -72,6 +70,9 @@ struct SynthXilinxPass : public Pass
|
|||
log(" -nosrl\n");
|
||||
log(" disable inference of shift registers\n");
|
||||
log("\n");
|
||||
log(" -nomux\n");
|
||||
log(" disable inference of wide multiplexers\n");
|
||||
log("\n");
|
||||
log(" -run <from_label>:<to_label>\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");
|
||||
|
@ -88,80 +89,34 @@ struct SynthXilinxPass : public Pass
|
|||
log("\n");
|
||||
log("\n");
|
||||
log("The following commands are executed by this synthesis command:\n");
|
||||
log("\n");
|
||||
log(" begin:\n");
|
||||
log(" read_verilog -lib +/xilinx/cells_sim.v\n");
|
||||
log(" read_verilog -lib +/xilinx/cells_xtra.v\n");
|
||||
log(" read_verilog -lib +/xilinx/brams_bb.v\n");
|
||||
log(" 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");
|
||||
help_script();
|
||||
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
|
||||
{
|
||||
std::string top_opt = "-auto-top";
|
||||
std::string edif_file;
|
||||
std::string blif_file;
|
||||
std::string run_from, run_to;
|
||||
std::string abc = "abc";
|
||||
bool flatten = false;
|
||||
bool retime = false;
|
||||
bool vpr = false;
|
||||
bool nobram = false;
|
||||
bool nodram = false;
|
||||
bool nosrl = false;
|
||||
clear_flags();
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
|
@ -170,6 +125,10 @@ struct SynthXilinxPass : public Pass
|
|||
top_opt = "-top " + args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-arch" && argidx+1 < args.size()) {
|
||||
arch = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-edif" && argidx+1 < args.size()) {
|
||||
edif_file = args[++argidx];
|
||||
continue;
|
||||
|
@ -198,6 +157,10 @@ struct SynthXilinxPass : public Pass
|
|||
vpr = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-nocarry") {
|
||||
nocarry = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-nobram") {
|
||||
nobram = true;
|
||||
continue;
|
||||
|
@ -209,7 +172,11 @@ struct SynthXilinxPass : public Pass
|
|||
if (args[argidx] == "-nosrl") {
|
||||
nosrl = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (args[argidx] == "-nomux") {
|
||||
nomux = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-abc9") {
|
||||
abc = "abc9";
|
||||
continue;
|
||||
|
@ -218,132 +185,151 @@ struct SynthXilinxPass : public Pass
|
|||
}
|
||||
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())
|
||||
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_push();
|
||||
|
||||
if (check_label(active, run_from, run_to, "begin"))
|
||||
{
|
||||
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()));
|
||||
}
|
||||
run_script(design, run_from, run_to);
|
||||
|
||||
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;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
aig 3 2 0 1 1
|
||||
6
|
||||
|
|
@ -3,3 +3,6 @@ aag 3 2 0 1 1
|
|||
4
|
||||
6
|
||||
6 2 4
|
||||
i0 pi0
|
||||
i1 pi1
|
||||
o0 po0
|
|
@ -0,0 +1,5 @@
|
|||
aig 3 2 0 1 1
|
||||
6
|
||||
i0 pi0
|
||||
i1 pi1
|
||||
o0 po0
|
|
@ -1,3 +1,5 @@
|
|||
aag 1 1 0 1 0
|
||||
2
|
||||
2
|
||||
i0 pi0
|
||||
o0 po0
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
aig 1 1 0 1 0
|
||||
2
|
||||
i0 pi0
|
||||
o0 po0
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
aag 1 0 1 0 0 1
|
||||
2 3
|
||||
2
|
||||
b0 po0
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
aig 1 0 1 0 0 1
|
||||
3
|
||||
2
|
||||
b0 po0
|
||||
|
|
|
@ -6,3 +6,4 @@ aag 5 1 1 0 3 1
|
|||
8 4 2
|
||||
10 9 7
|
||||
b0 AIGER_NEVER
|
||||
i0 po0
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
aig 5 1 1 0 3 1
|
||||
10
|
||||
4
|
||||
b0 AIGER_NEVER
|
||||
i0 po0
|
||||
b0 AIGER_NEVER
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
aag 0 0 0 1 0
|
||||
0
|
||||
o0 po0
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
aig 0 0 0 1 0
|
||||
0
|
||||
o0 po0
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
aag 1 1 0 1 0
|
||||
2
|
||||
3
|
||||
i0 pi0
|
||||
o0 po0
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
aig 1 1 0 1 0
|
||||
3
|
||||
i0 pi0
|
||||
o0 po0
|
||||
|
|
|
@ -6,3 +6,4 @@ aag 5 1 1 0 3 1
|
|||
8 4 2
|
||||
10 9 7
|
||||
b0 AIGER_NEVER
|
||||
i0 pi0
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
aig 5 1 1 0 3 1
|
||||
10
|
||||
5
|
||||
b0 AIGER_NEVER
|
||||
i0 pi0
|
||||
b0 AIGER_NEVER
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue