aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Makefile82
-rw-r--r--README.md4
-rw-r--r--backends/blif/blif.cc26
-rw-r--r--backends/btor/btor.cc8
-rw-r--r--backends/firrtl/firrtl.cc10
-rw-r--r--frontends/aiger/aigerparse.cc14
-rw-r--r--frontends/ast/ast.cc19
-rw-r--r--frontends/ast/ast.h4
-rw-r--r--frontends/ast/genrtlil.cc15
-rw-r--r--frontends/ilang/ilang_parser.y10
-rw-r--r--frontends/verific/verific.cc11
-rw-r--r--frontends/verilog/Makefile.inc2
-rw-r--r--frontends/verilog/const2ast.cc26
-rw-r--r--frontends/verilog/verilog_lexer.l4
-rw-r--r--frontends/verilog/verilog_parser.y22
-rw-r--r--kernel/log.cc9
-rw-r--r--kernel/rtlil.cc29
-rw-r--r--kernel/rtlil.h61
-rw-r--r--libs/subcircuit/subcircuit.cc10
-rw-r--r--misc/py_wrap_generator.py1
-rw-r--r--passes/cmds/bugpoint.cc3
-rw-r--r--passes/cmds/cover.cc10
-rw-r--r--passes/cmds/setundef.cc118
-rw-r--r--passes/cmds/tee.cc5
-rw-r--r--passes/hierarchy/hierarchy.cc191
-rw-r--r--passes/opt/opt_clean.cc27
-rw-r--r--passes/opt/opt_rmdff.cc72
-rw-r--r--passes/opt/wreduce.cc10
-rw-r--r--passes/pmgen/peepopt_shiftmul.pmg15
-rw-r--r--passes/sat/fmcombine.cc4
-rw-r--r--passes/sat/sim.cc5
-rw-r--r--passes/techmap/libparse.cc2
-rw-r--r--passes/techmap/shregmap.cc3
-rw-r--r--techlibs/common/prep.cc6
-rw-r--r--techlibs/ice40/cells_sim.v11
-rw-r--r--techlibs/xilinx/drams.txt4
-rw-r--r--techlibs/xilinx/synth_xilinx.cc11
-rw-r--r--tests/simple/localparam_attr.v11
-rw-r--r--tests/simple/param_attr.v11
-rw-r--r--tests/simple/peepopt.v4
-rw-r--r--tests/simple/wandwor.v36
-rw-r--r--tests/various/opt_rmdff.v50
-rw-r--r--tests/various/opt_rmdff.ys26
44 files changed, 841 insertions, 164 deletions
diff --git a/.gitignore b/.gitignore
index e24f7975a..76f53cd06 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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-*
diff --git a/Makefile b/Makefile
index b51ffd4c8..76dac48a5 100644
--- a/Makefile
+++ b/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,30 +296,51 @@ 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 "from misc import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).print_includes()")
endif
+endif
ifeq ($(ENABLE_READLINE),1)
CXXFLAGS += -DYOSYS_ENABLE_READLINE
@@ -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 -
+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 "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 misc/__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
diff --git a/README.md b/README.md
index efb74ef4e..94ea9538f 100644
--- a/README.md
+++ b/README.md
@@ -257,7 +257,7 @@ 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`` and ``disable`` keywords and library map files
@@ -413,7 +413,7 @@ 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``, ``$stop`` and ``$display`` are supported in
diff --git a/backends/blif/blif.cc b/backends/blif/blif.cc
index b6dbd84cb..a1761b662 100644
--- a/backends/blif/blif.cc
+++ b/backends/blif/blif.cc
@@ -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");
diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc
index 91f238fa5..511a11942 100644
--- a/backends/btor/btor.cc
+++ b/backends/btor/btor.cc
@@ -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));
diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc
index fe6bdb8f6..1c7a7351f 100644
--- a/backends/firrtl/firrtl.cc
+++ b/backends/firrtl/firrtl.cc
@@ -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());
}
@@ -449,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());
}
@@ -562,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.
@@ -575,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";
}
diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc
index 2e4774dfd..38348cd65 100644
--- a/frontends/aiger/aigerparse.cc
+++ b/frontends/aiger/aigerparse.cc
@@ -55,11 +55,15 @@ void AigerReader::parse_aiger()
// Optional values
B = C = J = F = 0;
- for (auto &i : std::array<std::reference_wrapper<unsigned>,4>{B, C, J, F}) {
- if (f.peek() != ' ') break;
- if (!(f >> i))
- log_error("Invalid AIGER header\n");
- }
+ if (f.peek() != ' ') goto end_of_header;
+ if (!(f >> B)) log_error("Invalid AIGER header\n");
+ if (f.peek() != ' ') goto end_of_header;
+ if (!(f >> C)) log_error("Invalid AIGER header\n");
+ if (f.peek() != ' ') goto end_of_header;
+ if (!(f >> J)) log_error("Invalid AIGER header\n");
+ if (f.peek() != ' ') goto end_of_header;
+ if (!(f >> F)) log_error("Invalid AIGER header\n");
+end_of_header:
std::string line;
std::getline(f, line); // Ignore up to start of next line, as standard
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index 5623541b2..83993eea9 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -194,6 +194,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 +725,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 +739,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 +784,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;
diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h
index 281cbe086..46d482f1a 100644
--- a/frontends/ast/ast.h
+++ b/frontends/ast/ast.h
@@ -173,7 +173,7 @@ namespace AST
// node content - most of it is unused in most node types
std::string str;
std::vector<RTLIL::State> bits;
- bool is_input, is_output, is_reg, is_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 +262,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 +270,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);
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index 379fed641..d2651c9aa 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -904,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);
@@ -919,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;
@@ -963,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));
diff --git a/frontends/ilang/ilang_parser.y b/frontends/ilang/ilang_parser.y
index 0df792997..44c99906a 100644
--- a/frontends/ilang/ilang_parser.y
+++ b/frontends/ilang/ilang_parser.y
@@ -47,6 +47,15 @@ USING_YOSYS_NAMESPACE
%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;
int integer;
@@ -451,4 +460,3 @@ conn_stmt:
delete $2;
delete $3;
};
-
diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc
index 21a1bbbbe..2bf99e58e 100644
--- a/frontends/verific/verific.cc
+++ b/frontends/verific/verific.cc
@@ -48,6 +48,14 @@ USING_YOSYS_NAMESPACE
#include "VhdlUnits.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
#endif
@@ -2016,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
diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc
index 0a1f97ac0..6a8462b41 100644
--- a/frontends/verilog/Makefile.inc
+++ b/frontends/verilog/Makefile.inc
@@ -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
diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc
index 7848c626d..57d366dbf 100644
--- a/frontends/verilog/const2ast.cc
+++ b/frontends/verilog/const2ast.cc
@@ -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;
diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l
index 142d05d45..9558bbfb9 100644
--- a/frontends/verilog/verilog_lexer.l
+++ b/frontends/verilog/verilog_lexer.l
@@ -218,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; }
@@ -232,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;
}
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index d23009e60..8244a8f44 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -112,6 +112,15 @@ struct specify_rise_fall {
%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;
@@ -130,7 +139,7 @@ struct specify_rise_fall {
%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 TOK_VAR
-%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG TOK_LOGIC
+%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_WAND TOK_WOR TOK_REG TOK_LOGIC
%token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL
%token TOK_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
@@ -476,6 +485,12 @@ 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;
} |
@@ -1193,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 ';' {
@@ -1201,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 ';' {
@@ -2418,4 +2433,3 @@ concat_list:
$$ = $3;
$$->children.push_back($1);
};
-
diff --git a/kernel/log.cc b/kernel/log.cc
index 9a9104e26..fa74a6a3c 100644
--- a/kernel/log.cc
+++ b/kernel/log.cc
@@ -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;
}
}
@@ -285,6 +289,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 +305,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();
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index 79ff4a6a6..790ba52a3 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -1514,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;
@@ -1529,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);
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index a0270bd1c..8509670ff 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -601,6 +601,7 @@ struct RTLIL::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;
@@ -1001,6 +1002,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;
@@ -1306,6 +1308,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);
@@ -1324,6 +1327,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;
};
@@ -1337,6 +1341,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;
};
@@ -1347,6 +1352,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;
};
@@ -1359,6 +1365,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;
};
@@ -1421,12 +1428,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)
functor(it);
@@ -1439,6 +1464,17 @@ void RTLIL::CaseRule::rewrite_sigspecs(T &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)
{
functor(signal);
@@ -1447,6 +1483,14 @@ void RTLIL::SwitchRule::rewrite_sigspecs(T &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)
{
functor(signal);
@@ -1457,6 +1501,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)
{
root_case.rewrite_sigspecs(functor);
@@ -1464,6 +1517,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
diff --git a/libs/subcircuit/subcircuit.cc b/libs/subcircuit/subcircuit.cc
index 7c7236833..e8361a67e 100644
--- a/libs/subcircuit/subcircuit.cc
+++ b/libs/subcircuit/subcircuit.cc
@@ -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)
diff --git a/misc/py_wrap_generator.py b/misc/py_wrap_generator.py
index 09f934040..9f2c72915 100644
--- a/misc/py_wrap_generator.py
+++ b/misc/py_wrap_generator.py
@@ -2060,7 +2060,6 @@ namespace YOSYS_PYTHON {
Yosys::log_streams.push_back(&std::cout);
Yosys::log_error_stderr = true;
Yosys::yosys_setup();
- Yosys::yosys_banner();
}
}
diff --git a/passes/cmds/bugpoint.cc b/passes/cmds/bugpoint.cc
index 85e2b0d56..038ab7c7c 100644
--- a/passes/cmds/bugpoint.cc
+++ b/passes/cmds/bugpoint.cc
@@ -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;
diff --git a/passes/cmds/cover.cc b/passes/cmds/cover.cc
index 0ec747671..1128116b4 100644
--- a/passes/cmds/cover.cc
+++ b/passes/cmds/cover.cc
@@ -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;
diff --git a/passes/cmds/setundef.cc b/passes/cmds/setundef.cc
index f6949c820..3eedc86b8 100644
--- a/passes/cmds/setundef.cc
+++ b/passes/cmds/setundef.cc
@@ -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);
+ for (auto wire : initwires)
+ {
+ int weight = 0;
- initwires.insert(wire);
- }
+ for (auto bit : sigmap(wire))
+ weight += ffbits.count(bit) ? +1 : -1;
+
+ wire_weights[wire] = weight;
+ }
+
+ initwires.sort([&](Wire *a, Wire *b) { return wire_weights.at(a) > wire_weights.at(b); });
+
+ for (auto wire : initwires)
+ {
+ Const &initval = wire->attributes["\\init"];
+ initval.bits.resize(GetSize(wire), State::Sx);
+
+ for (int i = 0; i < GetSize(wire); i++) {
+ SigBit bit = sigmap(SigBit(wire, i));
+ if (initval[i] == State::Sx && ffbits.count(bit)) {
+ initval[i] = worker.next_bit();
+ ffbits.erase(bit);
+ }
+ }
+
+ if (initval.is_fully_undef())
+ wire->attributes.erase("\\init");
+ }
+
+ initwires.clear();
+ };
for (int wire_types = 0; wire_types < 2; wire_types++)
- for (auto wire : module->wires())
+ {
+ // prioritize wires that already have an init attribute
+ if (!ffbits.empty())
{
- if (wire->name[0] == (wire_types ? '\\' : '$'))
- next_wire:
- continue;
+ for (auto wire : module->wires())
+ {
+ if (wire->name[0] == (wire_types ? '\\' : '$'))
+ continue;
- for (auto bit : sigmap(wire))
- if (!ffbits.count(bit))
- goto next_wire;
+ if (!wire->attributes.count("\\init"))
+ continue;
- for (auto bit : sigmap(wire))
- ffbits.erase(bit);
+ Const &initval = wire->attributes["\\init"];
+ initval.bits.resize(GetSize(wire), State::Sx);
+
+ if (initval.is_fully_undef()) {
+ wire->attributes.erase("\\init");
+ continue;
+ }
- initwires.insert(wire);
+ for (int i = 0; i < GetSize(wire); i++)
+ if (initval[i] != State::Sx)
+ ffbits.erase(sigmap(SigBit(wire, i)));
+
+ initwires.insert(wire);
+ }
+
+ process_initwires();
}
- for (auto wire : initwires)
- {
- Const &initval = wire->attributes["\\init"];
+ // 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 (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 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);
diff --git a/passes/cmds/tee.cc b/passes/cmds/tee.cc
index ee96ace86..1a44bdaec 100644
--- a/passes/cmds/tee.cc
+++ b/passes/cmds/tee.cc
@@ -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;
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index 72bc2e133..24e64a9b2 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -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");
@@ -943,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;
+ for (auto wire : module->wires())
+ {
+ if (wire->get_bool_attribute("\\wand")) {
+ wand_map[wire] = SigSpec();
+ wand_wor_index.insert(wire);
+ }
+ if (wire->get_bool_attribute("\\wor")) {
+ wor_map[wire] = SigSpec();
+ wand_wor_index.insert(wire);
+ }
+ }
+
+ for (auto &conn : module->connections())
+ {
+ SigSig new_conn;
+ int cursor = 0;
+
+ for (auto c : conn.first.chunks())
+ {
+ Wire *w = c.wire;
+ SigSpec rhs = conn.second.extract(cursor, GetSize(c));
+
+ if (wand_wor_index.count(w) == 0) {
+ new_conn.first.append(c);
+ new_conn.second.append(rhs);
+ } else {
+ if (wand_map.count(w)) {
+ SigSpec sig = SigSpec(State::S1, GetSize(w));
+ sig.replace(c.offset, rhs);
+ wand_map.at(w).append(sig);
+ } else {
+ SigSpec sig = SigSpec(State::S0, GetSize(w));
+ sig.replace(c.offset, rhs);
+ wor_map.at(w).append(sig);
+ }
+ }
+ cursor += GetSize(c);
+ }
+ new_connections.push_back(new_conn);
+ }
+ module->new_connections(new_connections);
- 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())
+ for (auto cell : module->cells())
+ {
+ if (!cell->known())
continue;
- if (new_m_name != m->name) {
- m = design->module(new_m_name);
- blackbox_derivatives.insert(m);
+
+ for (auto &conn : cell->connections())
+ {
+ if (!cell->output(conn.first))
+ continue;
+
+ SigSpec new_sig;
+ bool update_port = false;
+
+ for (auto c : conn.second.chunks())
+ {
+ Wire *w = c.wire;
+
+ if (wand_wor_index.count(w) == 0) {
+ new_sig.append(c);
+ continue;
+ }
+
+ Wire *t = module->addWire(NEW_ID, GetSize(c));
+ new_sig.append(t);
+ update_port = true;
+
+ if (wand_map.count(w)) {
+ SigSpec sig = SigSpec(State::S1, GetSize(w));
+ sig.replace(c.offset, t);
+ wand_map.at(w).append(sig);
+ } else {
+ SigSpec sig = SigSpec(State::S0, GetSize(w));
+ sig.replace(c.offset, t);
+ wor_map.at(w).append(sig);
+ }
+ }
+
+ if (update_port)
+ cell->setPort(conn.first, new_sig);
}
}
- for (auto &conn : cell->connections())
+ for (auto w : wand_wor_index)
{
- Wire *w = m->wire(conn.first);
+ bool wand = wand_map.count(w);
+ SigSpec sigs = wand ? wand_map.at(w) : wor_map.at(w);
- if (w == nullptr || w->port_id == 0)
+ if (GetSize(sigs) == 0)
continue;
- if (GetSize(conn.second) == 0)
+ if (GetSize(w) == 1) {
+ if (wand)
+ module->addReduceAnd(NEW_ID, sigs, w);
+ else
+ module->addReduceOr(NEW_ID, sigs, w);
continue;
+ }
- SigSpec sig = conn.second;
+ 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);
+ }
- 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);
+ 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);
}
- else
+ }
+
+ 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))
{
- int n = GetSize(w) - GetSize(conn.second);
- if (w->port_input && !w->port_output)
- sig.append(Const(0, n));
+ 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
- sig.append(module->addWire(NEW_ID, n));
+ {
+ 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 (!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));
}
-
- 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));
}
}
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index 6ca6ac820..cfb0f788a 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -106,7 +106,7 @@ void rmunused_module_cells(Module *module, bool verbose)
if (raw_bit.wire == nullptr)
continue;
auto bit = sigmap(raw_bit);
- if (bit.wire == nullptr)
+ 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)));
@@ -232,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;
@@ -272,20 +272,17 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
}
}
- SigPool raw_used_signals_noaliases;
- for (auto &it : module->connections_)
- raw_used_signals_noaliases.add(it.second);
-
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);
- raw_used_signals_noaliases.add(it2.second);
if (!ct_all.cell_output(cell->type, it2.first))
used_signals_nodrivers.add(it2.second);
}
@@ -294,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)
@@ -321,8 +319,9 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
wire->attributes.erase("\\init");
if (GetSize(wire) == 0) {
- // delete zero-width wires
- goto delete_this_wire;
+ // 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
@@ -330,11 +329,11 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
if (!purge_mode && check_public_name(wire->name)) {
// do not get rid of public names unless in purge mode
} else
- if (!raw_used_signals_noaliases.check_any(s1)) {
+ if (!raw_used_signals.check_any(s1)) {
// delete wires that aren't used by anything directly
goto delete_this_wire;
} else
- if (!used_signals_nodrivers.check_any(s2)) {
+ 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;
}
@@ -400,6 +399,8 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
if (verbose && del_temp_wires_count)
log_debug(" removed %d unused temporary wires.\n", del_temp_wires_count);
+
+ return !del_wires_queue.empty();
}
bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
@@ -497,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 {
diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc
index e8570f0eb..eeb992a3e 100644
--- a/passes/opt/opt_rmdff.cc
+++ b/passes/opt/opt_rmdff.cc
@@ -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_"))
diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index 58c6e4b4b..1fbc41082 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -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];
@@ -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);
diff --git a/passes/pmgen/peepopt_shiftmul.pmg b/passes/pmgen/peepopt_shiftmul.pmg
index fe861b728..6adab4e5f 100644
--- a/passes/pmgen/peepopt_shiftmul.pmg
+++ b/passes/pmgen/peepopt_shiftmul.pmg
@@ -1,4 +1,7 @@
pattern shiftmul
+//
+// Optimize mul+shift pairs that result from expressions such as foo[s*W+:W]
+//
state <SigSpec> shamt
@@ -49,12 +52,16 @@ code
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_log2 = ceil_log2(const_factor);
- int new_const_factor = 1 << new_const_factor_log2;
-
+ 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;
@@ -73,7 +80,7 @@ code
if (trunc > 0)
new_a.remove(GetSize(new_a)-trunc, trunc);
- SigSpec new_b = {port(mul, const_factor_port == \A ? \B : \A), SigSpec(State::S0, new_const_factor_log2)};
+ SigSpec new_b = {mul_din, SigSpec(State::S0, factor_bits)};
if (param(shift, \B_SIGNED).as_bool())
new_b.append(State::S0);
diff --git a/passes/sat/fmcombine.cc b/passes/sat/fmcombine.cc
index f64d99dc2..00c098542 100644
--- a/passes/sat/fmcombine.cc
+++ b/passes/sat/fmcombine.cc
@@ -332,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
{
@@ -351,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();
diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc
index 53e248adf..4c3022c70 100644
--- a/passes/sat/sim.cc
+++ b/passes/sat/sim.cc
@@ -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)
diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc
index 991cc4498..349ccc115 100644
--- a/passes/techmap/libparse.cc
+++ b/passes/techmap/libparse.cc
@@ -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 == '.')
diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc
index 75eedfbcc..21dfe9619 100644
--- a/passes/techmap/shregmap.cc
+++ b/passes/techmap/shregmap.cc
@@ -606,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
{
diff --git a/techlibs/common/prep.cc b/techlibs/common/prep.cc
index 86fb4d6c6..cdd21c3b3 100644
--- a/techlibs/common/prep.cc
+++ b/techlibs/common/prep.cc
@@ -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" : ""));
diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v
index 00843b97c..e89405b22 100644
--- a/techlibs/ice40/cells_sim.v
+++ b/techlibs/ice40/cells_sim.v
@@ -930,10 +930,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
diff --git a/techlibs/xilinx/drams.txt b/techlibs/xilinx/drams.txt
index e6635d0e2..91632bcee 100644
--- a/techlibs/xilinx/drams.txt
+++ b/techlibs/xilinx/drams.txt
@@ -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
diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc
index c20cac09b..a293081f1 100644
--- a/techlibs/xilinx/synth_xilinx.cc
+++ b/techlibs/xilinx/synth_xilinx.cc
@@ -229,11 +229,6 @@ struct SynthXilinxPass : public ScriptPass
run("dff2dffe");
run("opt -full");
- if (!vpr || help_mode)
- run("techmap -map +/xilinx/arith_map.v");
- else
- run("techmap -map +/xilinx/arith_map.v -D _EXPLICIT_CARRY");
-
if (!nosrl || help_mode) {
// shregmap operates on bit-level flops, not word-level,
// so break those down here
@@ -242,7 +237,11 @@ struct SynthXilinxPass : public ScriptPass
run("shregmap -tech xilinx -minlen 3", "(skip if '-nosrl')");
}
- run("techmap");
+ if (!vpr || help_mode)
+ run("techmap -map +/techmap.v -map +/xilinx/arith_map.v");
+ else
+ run("techmap -map +/techmap.v +/xilinx/arith_map.v -D _EXPLICIT_CARRY");
+
run("opt -fast");
}
diff --git a/tests/simple/localparam_attr.v b/tests/simple/localparam_attr.v
new file mode 100644
index 000000000..2ef76c71c
--- /dev/null
+++ b/tests/simple/localparam_attr.v
@@ -0,0 +1,11 @@
+module uut_localparam_attr (I, O);
+
+(* LOCALPARAM_ATTRIBUTE = "attribute_content" *)
+localparam WIDTH = 1;
+
+input wire [WIDTH-1:0] I;
+output wire [WIDTH-1:0] O;
+
+assign O = I;
+
+endmodule
diff --git a/tests/simple/param_attr.v b/tests/simple/param_attr.v
new file mode 100644
index 000000000..34d63a34e
--- /dev/null
+++ b/tests/simple/param_attr.v
@@ -0,0 +1,11 @@
+module uut_param_attr (I, O);
+
+(* PARAMETER_ATTRIBUTE = "attribute_content" *)
+parameter WIDTH = 1;
+
+input wire [WIDTH-1:0] I;
+output wire [WIDTH-1:0] O;
+
+assign O = I;
+
+endmodule
diff --git a/tests/simple/peepopt.v b/tests/simple/peepopt.v
index b27b9fe57..1bf427897 100644
--- a/tests/simple/peepopt.v
+++ b/tests/simple/peepopt.v
@@ -2,6 +2,10 @@ module peepopt_shiftmul_0 #(parameter N=3, parameter W=3) (input [N*W-1:0] i, in
assign o = i[s*W+:W];
endmodule
+module peepopt_shiftmul_1 (output y, input [2:0] w);
+assign y = 1'b1 >> (w * (3'b110));
+endmodule
+
module peepopt_muldiv_0(input [1:0] i, output [1:0] o);
wire [3:0] t;
assign t = i * 3;
diff --git a/tests/simple/wandwor.v b/tests/simple/wandwor.v
new file mode 100644
index 000000000..34404aa26
--- /dev/null
+++ b/tests/simple/wandwor.v
@@ -0,0 +1,36 @@
+module wandwor_test0 (A, B, C, D, X, Y, Z);
+ input A, B, C, D;
+ output wor X;
+ output wand Y;
+ output Z;
+
+ assign X = A, X = B, Y = C, Y = D;
+ foo foo_0 (C, D, X);
+ foo foo_1 (A, B, Y);
+ foo foo_2 (X, Y, Z);
+endmodule
+
+module wandwor_test1 (A, B, C, D, X, Y, Z);
+ input [3:0] A, B, C, D;
+ output wor [3:0] X;
+ output wand [3:0] Y;
+ output Z;
+
+ bar bar_inst (
+ .I0({A, B}),
+ .I1({B, A}),
+ .O({X, Y})
+ );
+
+ assign X = C, X = D;
+ assign Y = C, Y = D;
+ assign Z = ^{X,Y};
+endmodule
+
+module foo(input I0, I1, output O);
+ assign O = I0 ^ I1;
+endmodule
+
+module bar(input [7:0] I0, I1, output [7:0] O);
+ assign O = I0 + I1;
+endmodule
diff --git a/tests/various/opt_rmdff.v b/tests/various/opt_rmdff.v
new file mode 100644
index 000000000..b1c06703c
--- /dev/null
+++ b/tests/various/opt_rmdff.v
@@ -0,0 +1,50 @@
+module opt_rmdff_test (input C, input D, input E, output [29:0] Q);
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove0 (.CLK(C), .D(D), .EN(1'b0), .Q(Q[0])); // EN is never active
+(* init = "1'b1" *) wire Q1; assign Q[1] = Q1;
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove1 (.CLK(C), .D(D), .EN(1'b0), .Q(Q1)); // EN is never active
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove2 (.CLK(C), .D(D), .EN(1'bx), .Q(Q[2])); // EN is don't care
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) keep3 (.CLK(C), .D(D), .EN(1'b1), .Q(Q[3])); // EN is always active
+(* init = "1'b0" *) wire Q4; assign Q[4] = Q4;
+\$dffe #(.WIDTH(1), .CLK_POLARITY(0), .EN_POLARITY(1)) keep4 (.CLK(C), .D(D), .EN(1'b1), .Q(Q4)); // EN is always active
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) remove5 (.CLK(C), .D(D), .EN(1'b1), .Q(Q[5])); // EN is never active
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) remove6 (.CLK(C), .D(D), .EN(1'bx), .Q(Q[6])); // EN is don't care
+(* init = "1'b0" *) wire Q7; assign Q[7] = Q7;
+\$dffe #(.WIDTH(1), .CLK_POLARITY(0), .EN_POLARITY(0)) keep7 (.CLK(C), .D(D), .EN(E), .Q(Q7)); // EN is non constant
+
+\$_DFFE_PP_ remove8 (.C(C), .D(D), .E(1'b0), .Q(Q[8])); // EN is never active
+(* init = "1'b1" *) wire Q9; assign Q[9] = Q9;
+\$_DFFE_PP_ remove9 (.C(C), .D(D), .E(1'b0), .Q(Q9)); // EN is never active
+\$_DFFE_PP_ remove10 (.C(C), .D(D), .E(1'bx), .Q(Q[10])); // EN is don't care
+\$_DFFE_PP_ keep11 (.C(C), .D(D), .E(1'b1), .Q(Q[11])); // EN is always active
+(* init = "1'b0" *) wire Q12; assign Q[12] = Q12;
+\$_DFFE_PP_ keep12 (.C(C), .D(D), .E(1'b1), .Q(Q12)); // EN is always active
+
+\$_DFFE_NN_ remove13 (.C(C), .D(D), .E(1'b1), .Q(Q[13])); // EN is never active
+(* init = "1'b1" *) wire Q14; assign Q[14] = Q14;
+\$_DFFE_NN_ remove14 (.C(C), .D(D), .E(1'b1), .Q(Q14)); // EN is never active
+\$_DFFE_NN_ remove15 (.C(C), .D(D), .E(1'bx), .Q(Q[15])); // EN is don't care
+\$_DFFE_NN_ keep16 (.C(C), .D(D), .E(1'b0), .Q(Q[16])); // EN is always active
+(* init = "1'b0" *) wire Q17; assign Q[17] = Q17;
+\$_DFFE_NN_ keep17 (.C(C), .D(D), .E(1'b0), .Q(Q17)); // EN is always active
+
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove18 (.CLK(1'b0), .D(D), .EN(E), .Q(Q[18])); // CLK is constant
+(* init = "1'b1" *) wire Q19; assign Q[19] = Q19;
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove19 (.CLK(1'b1), .D(D), .EN(E), .Q(Q19)); // CLK is constant
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove20 (.CLK(C), .D(1'bx), .EN(E), .Q(Q[20])); // D is undriven, Q has no initial value
+(* init = "1'b0" *) wire Q21; assign Q[21] = Q21;
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) keep21 (.CLK(C), .D(1'bx), .EN(E), .Q(Q21)); // D is undriven, Q has initial value
+//\$dffe #(.WIDTH(1), .CLK_POLARITY(0), .EN_POLARITY(1)) remove22 (.CLK(C), .D(1'b0), .EN(1'b1), .Q(Q[22])); // D is constant, no initial Q value, EN is always active
+// // (TODO, Q starts with 1'bx and becomes 1'b0)
+(* init = "1'b0" *) wire Q23; assign Q[23] = Q23;
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) noenable23 (.CLK(C), .D(1'b0), .EN(1'b1), .Q(Q23)); // D is constant, initial Q value same as D, EN is always active
+(* init = "1'b1" *) wire Q24; assign Q[24] = Q24;
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) keep24 (.CLK(C), .D(1'b0), .EN(1'b0), .Q(Q24)); // D is constant, initial Q value NOT same as D, EN is always active
+(* init = "1'b1" *) wire Q25; assign Q[25] = Q25;
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) remove25 (.CLK(C), .D(1'b0), .EN(1'b1), .Q(Q25)); // D is constant, EN is never active
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove26 (.CLK(C), .D(Q[26]), .EN(1'b1), .Q(Q[26])); // D is Q, EN is always active
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) remove27 (.CLK(C), .D(Q[27]), .EN(1'b1), .Q(Q[27])); // D is Q, EN is never active, but no initial value
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) remove28 (.CLK(C), .D(Q[28]), .EN(E), .Q(Q[28])); // EN is nonconst, but no initial value
+(* init = "1'b1" *) wire Q29; assign Q[29] = Q29;
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) keep29 (.CLK(C), .D(Q[29]), .EN(1'b1), .Q(Q29)); // EN is always active, but with initial value
+
+endmodule
diff --git a/tests/various/opt_rmdff.ys b/tests/various/opt_rmdff.ys
new file mode 100644
index 000000000..081f81782
--- /dev/null
+++ b/tests/various/opt_rmdff.ys
@@ -0,0 +1,26 @@
+read_verilog -icells opt_rmdff.v
+prep
+design -stash gold
+read_verilog -icells opt_rmdff.v
+proc
+opt_rmdff
+
+select -assert-count 0 c:remove*
+select -assert-min 7 c:keep*
+select -assert-count 0 t:$dffe 7:$_DFFE_* %u c:noenable* %i
+
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+equiv_make gold gate equiv
+hierarchy -top equiv
+equiv_simple -undef
+equiv_status -assert
+
+design -load gold
+stat
+
+design -load gate
+stat