diff options
author | Eddie Hung <eddie@fpgeh.com> | 2019-05-28 09:30:53 -0700 |
---|---|---|
committer | Eddie Hung <eddie@fpgeh.com> | 2019-05-28 09:30:53 -0700 |
commit | ba9513b325433f9232e1c4312a2b526ca7dacdd4 (patch) | |
tree | 995de7437e31e2c383a0185049e4e844df4d27e0 | |
parent | f745727de5af085412b2e5f8161aa1018cc5e276 (diff) | |
parent | 8e647901ef6ea484bfe41628f258c53590ae4114 (diff) | |
download | yosys-ba9513b325433f9232e1c4312a2b526ca7dacdd4.tar.gz yosys-ba9513b325433f9232e1c4312a2b526ca7dacdd4.tar.bz2 yosys-ba9513b325433f9232e1c4312a2b526ca7dacdd4.zip |
Merge remote-tracking branch 'origin/master' into xc7mux
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | Makefile | 71 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | frontends/ast/ast.cc | 19 | ||||
-rw-r--r-- | frontends/ast/ast.h | 4 | ||||
-rw-r--r-- | frontends/ast/genrtlil.cc | 15 | ||||
-rw-r--r-- | frontends/verilog/const2ast.cc | 26 | ||||
-rw-r--r-- | frontends/verilog/verilog_lexer.l | 4 | ||||
-rw-r--r-- | frontends/verilog/verilog_parser.y | 8 | ||||
-rw-r--r-- | kernel/log.cc | 9 | ||||
-rw-r--r-- | kernel/rtlil.h | 1 | ||||
-rw-r--r-- | passes/hierarchy/hierarchy.cc | 191 | ||||
-rw-r--r-- | passes/opt/opt_clean.cc | 5 | ||||
-rw-r--r-- | passes/opt/opt_rmdff.cc | 57 | ||||
-rw-r--r-- | tests/simple/wandwor.v | 36 | ||||
-rw-r--r-- | tests/various/opt_rmdff.v | 72 | ||||
-rw-r--r-- | tests/various/opt_rmdff.ys | 3 |
17 files changed, 422 insertions, 104 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-* @@ -2,6 +2,7 @@ CONFIG := clang # CONFIG := gcc # CONFIG := gcc-4.8 +# CONFIG := afl-gcc # CONFIG := emcc # CONFIG := mxe # CONFIG := msys2 @@ -21,12 +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_PREFIX := `$(PYTHON_EXECUTABLE)-config --prefix` -PYTHON_DESTDIR := $(PYTHON_PREFIX)/lib/python$(PYTHON_VERSION)/site-packages # other configuration flags ENABLE_GCOV := 0 @@ -90,6 +85,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) @@ -139,6 +137,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++ @@ -186,6 +199,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 @@ -273,30 +292,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 += $(shell $(PYTHON_EXECUTABLE)-config --ldflags) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem +CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON +else +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 += `$(PYTHON_EXECUTABLE)-config --libs` $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem -CXXFLAGS += `$(PYTHON_EXECUTABLE)-config --includes` -D WITH_PYTHON +LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --libs) $(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 --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 @@ -541,7 +581,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 $@) @@ -551,9 +595,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 $@) @@ -788,6 +834,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 @@ -834,5 +883,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 @@ -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 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/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 132468f0c..8244a8f44 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -139,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 @@ -485,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; } | 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.h b/kernel/rtlil.h index 6c860f36c..d3ad57d72 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -607,6 +607,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; 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 bf8020169..7011d4602 100644 --- a/passes/opt/opt_clean.cc +++ b/passes/opt/opt_clean.cc @@ -319,8 +319,9 @@ bool 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 diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc index 3cb8e2b1e..2abffa2a9 100644 --- a/passes/opt/opt_rmdff.cc +++ b/passes/opt/opt_rmdff.cc @@ -338,16 +338,6 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff) val_init.bits.push_back(bit.wire == NULL ? bit.data : RTLIL::State::Sx); } - if (sig_e.size()) { - if (!sig_e.is_fully_const()) - return false; - if (sig_e != val_ep) { - if (has_init) - mod->connect(sig_q, val_init); - goto delete_dff; - } - } - if (dff->type.in("$ff", "$dff") && mux_drivers.has(sig_d)) { std::set<RTLIL::Cell*> muxes; mux_drivers.find(sig_d, muxes); @@ -365,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; } @@ -417,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: 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 index 224b8d418..b1c06703c 100644 --- a/tests/various/opt_rmdff.v +++ b/tests/various/opt_rmdff.v @@ -1,30 +1,50 @@ -module opt_rmdff_test (input C, input D, input E, output reg [16:0] Q); -\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove0 (.CLK(C), .D(D), .EN(1'b0), .Q(Q[0])); -initial Q[1] = 1'b1; -\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove1 (.CLK(C), .D(D), .EN(1'b0), .Q(Q[1])); -\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove2 (.CLK(C), .D(D), .EN(1'bx), .Q(Q[2])); -\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) keep2 (.CLK(C), .D(D), .EN(1'b1), .Q(Q[2])); -initial Q[3] = 1'b0; -\$dffe #(.WIDTH(1), .CLK_POLARITY(0), .EN_POLARITY(1)) keep3 (.CLK(C), .D(D), .EN(1'b1), .Q(Q[3])); -\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) remove4 (.CLK(C), .D(D), .EN(1'b1), .Q(Q[4])); -\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) remove5 (.CLK(C), .D(D), .EN(1'bx), .Q(Q[5])); -initial Q[6] = 1'b0; -\$dffe #(.WIDTH(1), .CLK_POLARITY(0), .EN_POLARITY(0)) keep6 (.CLK(C), .D(D), .EN(E), .Q(Q[6])); +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_ remove7 (.C(C), .D(D), .E(1'b0), .Q(Q[7])); -initial Q[8] = 1'b1; -\$_DFFE_PP_ remove8 (.C(C), .D(D), .E(1'b0), .Q(Q[8])); -\$_DFFE_PP_ remove9 (.C(C), .D(D), .E(1'bx), .Q(Q[9])); -\$_DFFE_PP_ keep10 (.C(C), .D(D), .E(1'b1), .Q(Q[10])); -initial Q[11] = 1'b0; -\$_DFFE_PP_ keep11 (.C(C), .D(D), .E(1'b1), .Q(Q[11])); +\$_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_ remove12 (.C(C), .D(D), .E(1'b1), .Q(Q[12])); -initial Q[13] = 1'b1; -\$_DFFE_NN_ remove13 (.C(C), .D(D), .E(1'b1), .Q(Q[13])); -\$_DFFE_NN_ remove14 (.C(C), .D(D), .E(1'bx), .Q(Q[14])); -\$_DFFE_NN_ keep15 (.C(C), .D(D), .E(1'b0), .Q(Q[15])); -initial Q[16] = 1'b0; -\$_DFFE_NN_ keep16 (.C(C), .D(D), .E(1'b0), .Q(Q[16])); +\$_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 index fffffb4b5..081f81782 100644 --- a/tests/various/opt_rmdff.ys +++ b/tests/various/opt_rmdff.ys @@ -2,12 +2,13 @@ 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 -prep design -stash gate design -import gold -as gold |