diff --git a/.github/workflows/extra-builds.yml b/.github/workflows/extra-builds.yml index b22a399db..5d0ac72d4 100644 --- a/.github/workflows/extra-builds.yml +++ b/.github/workflows/extra-builds.yml @@ -5,6 +5,7 @@ on: push: branches: - main + merge_group: # test PRs pull_request: # allow triggering tests, ignores skip check @@ -37,7 +38,7 @@ jobs: persist-credentials: false - run: sudo apt-get install libfl-dev - name: Build - run: make vcxsrc YOSYS_VER=latest + run: make vcxsrc YOSYS_COMPILER="Visual Studio" VCX_DIR_NAME=yosys-win32-vcxsrc-latest - uses: actions/upload-artifact@v4 with: name: vcxsrc diff --git a/.github/workflows/prepare-docs.yml b/.github/workflows/prepare-docs.yml index f19b1c7af..e3d917942 100644 --- a/.github/workflows/prepare-docs.yml +++ b/.github/workflows/prepare-docs.yml @@ -1,6 +1,6 @@ name: Build docs artifact with Verific -on: [push, pull_request] +on: [push, pull_request, merge_group] jobs: check_docs_rebuild: diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 8c1a3bbd2..ab6eb3148 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -5,6 +5,7 @@ on: push: branches: - main + merge_group: # test PRs pull_request: # allow triggering tests, ignores skip check diff --git a/.github/workflows/test-compile.yml b/.github/workflows/test-compile.yml index 31c8bccf6..000d1c400 100644 --- a/.github/workflows/test-compile.yml +++ b/.github/workflows/test-compile.yml @@ -5,6 +5,7 @@ on: push: branches: - main + merge_group: # test PRs pull_request: # allow triggering tests, ignores skip check diff --git a/.github/workflows/test-sanitizers.yml b/.github/workflows/test-sanitizers.yml index 4c8e3ec51..11a339cd3 100644 --- a/.github/workflows/test-sanitizers.yml +++ b/.github/workflows/test-sanitizers.yml @@ -5,6 +5,7 @@ on: push: branches: - main + merge_group: # ignore PRs due to time needed # allow triggering tests, ignores skip check workflow_dispatch: diff --git a/.github/workflows/test-verific.yml b/.github/workflows/test-verific.yml index 6619e1124..adc6f59d8 100644 --- a/.github/workflows/test-verific.yml +++ b/.github/workflows/test-verific.yml @@ -5,6 +5,7 @@ on: push: branches: - main + merge_group: # test PRs pull_request: # allow triggering tests, ignores skip check diff --git a/CHANGELOG b/CHANGELOG index 69f8ab1ce..73c1606da 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,9 +2,22 @@ List of major changes and improvements between releases ======================================================= -Yosys 0.60 .. Yosys 0.61-dev +Yosys 0.61 .. Yosys 0.62-dev -------------------------- +Yosys 0.60 .. Yosys 0.61 +-------------------------- + * Various + - Removed "cover" pass for coverage tracking. + - Avoid merging formal properties with "opt_merge" pass. + - Parallelize "opt_merge" pass. + + * New commands and options + - Added "design_equal" pass to support fuzz-test comparison. + - Added "lut2bmux" pass to convert $lut to $bmux. + - Added "-legalize" option to "read_rtlil" pass to prevent + semantic errors. + Yosys 0.59 .. Yosys 0.60 -------------------------- * Various diff --git a/COPYING b/COPYING index 2d962dddc..a3ca45b42 100644 --- a/COPYING +++ b/COPYING @@ -1,6 +1,6 @@ ISC License -Copyright (C) 2012 - 2025 Claire Xenia Wolf +Copyright (C) 2012 - 2026 Claire Xenia Wolf Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above diff --git a/Makefile b/Makefile index 15aaf870c..2fcc2fd95 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,6 @@ ENABLE_VERIFIC_HIER_TREE := 1 ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS := 0 ENABLE_VERIFIC_EDIF := 0 ENABLE_VERIFIC_LIBERTY := 0 -ENABLE_COVER := 1 ENABLE_LIBYOSYS := 0 ENABLE_LIBYOSYS_STATIC := 0 ENABLE_ZLIB := 1 @@ -162,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.60+0 +YOSYS_VER := 0.61+0 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) @@ -178,14 +177,16 @@ CXXFLAGS += -DYOSYS_VER=\\"$(YOSYS_VER)\\" \ TARBALL_GIT_REV := $(shell cat $(YOSYS_SRC)/.gitcommit) ifneq ($(findstring Format:,$(TARBALL_GIT_REV)),) GIT_REV := $(shell GIT_DIR=$(YOSYS_SRC)/.git git rev-parse --short=9 HEAD || echo UNKNOWN) +GIT_DIRTY := $(shell GIT_DIR=$(YOSYS_SRC)/.git git diff --exit-code --quiet 2>/dev/null; if [ $$? -ne 0 ]; then echo "-dirty"; fi) else GIT_REV := $(TARBALL_GIT_REV) +GIT_DIRTY := "" endif OBJS = kernel/version_$(GIT_REV).o bumpversion: - sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 5bafeb7.. | wc -l`/;" Makefile + sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 5ae48ee.. | wc -l`/;" Makefile ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) @@ -249,9 +250,6 @@ ifneq ($(SANITIZER),) $(info [Clang Sanitizer] $(SANITIZER)) CXXFLAGS += -g -O1 -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=$(SANITIZER) LINKFLAGS += -g -fsanitize=$(SANITIZER) -ifneq ($(findstring address,$(SANITIZER)),) -ENABLE_COVER := 0 -endif ifneq ($(findstring memory,$(SANITIZER)),) CXXFLAGS += -fPIE -fsanitize-memory-track-origins LINKFLAGS += -fPIE -fsanitize-memory-track-origins @@ -548,10 +546,6 @@ LIBS_VERIFIC += -Wl,--whole-archive $(patsubst %,$(VERIFIC_DIR)/%/*-linux.a,$(VE endif endif -ifeq ($(ENABLE_COVER),1) -CXXFLAGS += -DYOSYS_ENABLE_COVER -endif - ifeq ($(ENABLE_CCACHE),1) CXX := ccache $(CXX) else @@ -651,8 +645,6 @@ $(eval $(call add_include_file,libs/sha1/sha1.h)) $(eval $(call add_include_file,libs/json11/json11.hpp)) $(eval $(call add_include_file,passes/fsm/fsmdata.h)) $(eval $(call add_include_file,passes/techmap/libparse.h)) -$(eval $(call add_include_file,frontends/ast/ast.h)) -$(eval $(call add_include_file,frontends/ast/ast_binding.h)) $(eval $(call add_include_file,frontends/blif/blifparse.h)) $(eval $(call add_include_file,backends/rtlil/rtlil_backend.h)) @@ -729,7 +721,6 @@ OBJS += passes/hierarchy/hierarchy.o OBJS += passes/cmds/select.o OBJS += passes/cmds/show.o OBJS += passes/cmds/stat.o -OBJS += passes/cmds/cover.o OBJS += passes/cmds/design.o OBJS += passes/cmds/plugin.o @@ -800,12 +791,13 @@ endif $(Q) mkdir -p $(dir $@) $(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $< -YOSYS_VER_STR := Yosys $(YOSYS_VER) (git sha1 $(GIT_REV), $(notdir $(CXX)) $(shell \ - $(CXX) --version | tr ' ()' '\n' | grep '^[0-9]' | head -n1) $(filter -f% -m% -O% -DNDEBUG,$(CXXFLAGS))) +YOSYS_GIT_STR := $(GIT_REV)$(GIT_DIRTY) +YOSYS_COMPILER := $(notdir $(CXX)) $(shell $(CXX) --version | tr ' ()' '\n' | grep '^[0-9]' | head -n1) $(filter -f% -m% -O% -DNDEBUG,$(CXXFLAGS)) +YOSYS_VER_STR := Yosys $(YOSYS_VER) (git sha1 $(YOSYS_GIT_STR), $(YOSYS_COMPILER)) kernel/version_$(GIT_REV).cc: $(YOSYS_SRC)/Makefile $(P) rm -f kernel/version_*.o kernel/version_*.d kernel/version_*.cc - $(Q) mkdir -p kernel && echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"$(YOSYS_VER_STR)\"; }" > kernel/version_$(GIT_REV).cc + $(Q) mkdir -p kernel && echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"$(YOSYS_VER_STR)\"; const char *yosys_git_hash_str=\"$(YOSYS_GIT_STR)\"; }" > kernel/version_$(GIT_REV).cc ifeq ($(ENABLE_VERIFIC),1) CXXFLAGS_NOVERIFIC = $(foreach v,$(CXXFLAGS),$(if $(findstring $(VERIFIC_DIR),$(v)),,$(v))) @@ -1058,7 +1050,9 @@ ifeq ($(ENABLE_PYOSYS),1) $(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/libyosys.so $(INSTALL_SUDO) cp -r share $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys ifeq ($(ENABLE_ABC),1) - $(INSTALL_SUDO) cp yosys-abc $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/yosys-abc +ifeq ($(ABCEXTERNAL),) + $(INSTALL_SUDO) cp $(PROGRAM_PREFIX)yosys-abc$(EXE) $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/yosys-abc$(EXE) +endif endif endif endif @@ -1209,15 +1203,17 @@ qtcreator: { echo .; find backends frontends kernel libs passes -type f \( -name '*.h' -o -name '*.hh' \) -printf '%h\n' | sort -u; } > qtcreator.includes touch qtcreator.creator -vcxsrc: $(GENFILES) $(EXTRA_TARGETS) - rm -rf yosys-win32-vcxsrc-$(YOSYS_VER){,.zip} +VCX_DIR_NAME := yosys-win32-vcxsrc-$(YOSYS_VER) +vcxsrc: $(GENFILES) $(EXTRA_TARGETS) kernel/version_$(GIT_REV).cc + rm -rf $(VCX_DIR_NAME){,.zip} + cp -f kernel/version_$(GIT_REV).cc kernel/version.cc set -e; for f in `ls $(filter %.cc %.cpp,$(GENFILES)) $(addsuffix .cc,$(basename $(OBJS))) $(addsuffix .cpp,$(basename $(OBJS))) 2> /dev/null`; do \ echo "Analyse: $$f" >&2; cpp -std=c++17 -MM -I. -D_YOSYS_ $$f; done | sed 's,.*:,,; s,//*,/,g; s,/[^/]*/\.\./,/,g; y, \\,\n\n,;' | grep '^[^/]' | sort -u | grep -v kernel/version_ > srcfiles.txt echo "libs/fst/fst_win_unistd.h" >> srcfiles.txt - bash misc/create_vcxsrc.sh yosys-win32-vcxsrc $(YOSYS_VER) $(GIT_REV) - echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"Yosys (Version Information Unavailable)\"; }" > kernel/version.cc - zip yosys-win32-vcxsrc-$(YOSYS_VER)/genfiles.zip $(GENFILES) kernel/version.cc - zip -r yosys-win32-vcxsrc-$(YOSYS_VER).zip yosys-win32-vcxsrc-$(YOSYS_VER)/ + echo "kernel/version.cc" >> srcfiles.txt + bash misc/create_vcxsrc.sh $(VCX_DIR_NAME) $(YOSYS_VER) + zip $(VCX_DIR_NAME)/genfiles.zip $(GENFILES) kernel/version.cc + zip -r $(VCX_DIR_NAME).zip $(VCX_DIR_NAME)/ rm -f srcfiles.txt kernel/version.cc config-clean: clean diff --git a/abc b/abc index 131a50dd7..799ba6322 160000 --- a/abc +++ b/abc @@ -1 +1 @@ -Subproject commit 131a50dd773f21ebbfc51da1d182438382a04209 +Subproject commit 799ba632239b2a4db2bacda81de4e6efdc486b0c diff --git a/backends/aiger2/aiger.cc b/backends/aiger2/aiger.cc index 41e1b91c1..babc29826 100644 --- a/backends/aiger2/aiger.cc +++ b/backends/aiger2/aiger.cc @@ -24,6 +24,7 @@ #include "kernel/register.h" #include "kernel/celltypes.h" +#include "kernel/rtlil.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -845,11 +846,14 @@ struct XAigerAnalysis : Index { return false; int max = 1; - for (auto wire : mod->wires()) - if (wire->port_input && !wire->port_output) - for (int i = 0; i < wire->width; i++) { - int ilevel = visit(cursor, driver->getPort(wire->name)[i]); - max = std::max(max, ilevel + 1); + for (auto wire : mod->wires()) { + if (wire->port_input && !wire->port_output) { + SigSpec port = driver->getPort(wire->name); + for (int i = 0; i < std::min(wire->width, port.size()); i++) { + int ilevel = visit(cursor, port[i]); + max = std::max(max, ilevel + 1); + } + } } lits[idx] = max; diff --git a/backends/cxxrtl/cxxrtl_backend.cc b/backends/cxxrtl/cxxrtl_backend.cc index d575b5879..71913d2db 100644 --- a/backends/cxxrtl/cxxrtl_backend.cc +++ b/backends/cxxrtl/cxxrtl_backend.cc @@ -756,7 +756,7 @@ struct CxxrtlWorker { // 1b. Generated identifiers for internal names (beginning with `$`) start with `i_`. // 2. An underscore is escaped with another underscore, i.e. `__`. // 3. Any other non-alnum character is escaped with underscores around its lowercase hex code, e.g. `@` as `_40_`. - std::string mangle_name(const RTLIL::IdString &name) + std::string mangle_name(RTLIL::IdString name) { std::string mangled; bool first = true; @@ -786,7 +786,7 @@ struct CxxrtlWorker { return mangled; } - std::string mangle_module_name(const RTLIL::IdString &name, bool is_blackbox = false) + std::string mangle_module_name(RTLIL::IdString name, bool is_blackbox = false) { // Class namespace. if (is_blackbox) @@ -794,19 +794,19 @@ struct CxxrtlWorker { return mangle_name(name); } - std::string mangle_memory_name(const RTLIL::IdString &name) + std::string mangle_memory_name(RTLIL::IdString name) { // Class member namespace. return "memory_" + mangle_name(name); } - std::string mangle_cell_name(const RTLIL::IdString &name) + std::string mangle_cell_name(RTLIL::IdString name) { // Class member namespace. return "cell_" + mangle_name(name); } - std::string mangle_wire_name(const RTLIL::IdString &name) + std::string mangle_wire_name(RTLIL::IdString name) { // Class member namespace. return mangle_name(name); diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py index 4e47117b3..9dfbd2a25 100644 --- a/backends/smt2/smtbmc.py +++ b/backends/smt2/smtbmc.py @@ -735,6 +735,12 @@ def ywfile_signal(sig, step, mask=None): output = [] + def ywfile_signal_error(reason, detail=None): + msg = f"Yosys witness signal mismatch for {sig.pretty()}: {reason}" + if detail: + msg += f" ({detail})" + raise ValueError(msg) + if sig.path in smt_wires: for wire in smt_wires[sig.path]: width, offset = wire["width"], wire["offset"] @@ -765,6 +771,12 @@ def ywfile_signal(sig, step, mask=None): for mem in smt_mems[sig.memory_path]: width, size, bv = mem["width"], mem["size"], mem["statebv"] + if sig.memory_addr is not None and sig.memory_addr >= size: + ywfile_signal_error( + "memory address out of bounds", + f"address={sig.memory_addr} size={size}", + ) + smt_expr = smt.net_expr(topmod, f"s{step}", mem["smtpath"]) if bv: @@ -781,18 +793,34 @@ def ywfile_signal(sig, step, mask=None): smt_expr = "((_ extract %d %d) %s)" % (slice_high, sig.offset, smt_expr) output.append((0, sig.width, smt_expr)) + else: + ywfile_signal_error("memory not found in design") output.sort() output = [chunk for chunk in output if chunk[0] != chunk[1]] + if not output: + if sig.memory_path: + ywfile_signal_error("memory signal has no matching bits in design") + else: + ywfile_signal_error("signal not found in design") + pos = 0 for start, end, smt_expr in output: - assert start == pos + if start != pos: + ywfile_signal_error( + "signal width/offset mismatch", + f"expected coverage at bit {pos}", + ) pos = end - assert pos == sig.width + if pos != sig.width: + ywfile_signal_error( + "signal width/offset mismatch", + f"covered {pos} of {sig.width} bits", + ) if len(output) == 1: return output[0][-1] diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 8d77160fd..3d451117c 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -2143,6 +2143,9 @@ void dump_case_actions(std::ostream &f, std::string indent, RTLIL::CaseRule *cs) bool dump_proc_switch_ifelse(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw) { + if (sw->cases.empty()) + return true; + for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) { if ((*it)->compare.size() == 0) { break; diff --git a/docs/source/conf.py b/docs/source/conf.py index 01bb620ea..34f8be029 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -5,8 +5,8 @@ import os project = 'YosysHQ Yosys' author = 'YosysHQ GmbH' -copyright ='2025 YosysHQ GmbH' -yosys_ver = "0.60" +copyright ='2026 YosysHQ GmbH' +yosys_ver = "0.61" # select HTML theme html_theme = 'furo-ys' diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index c26750c98..86ea70b51 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -844,6 +844,7 @@ struct AST_INTERNAL::ProcessGenerator RTLIL::Cell *cell = current_module->addCell(cellname, ID($check)); set_src_attr(cell, ast); + cell->set_bool_attribute(ID(keep)); for (auto &attr : ast->attributes) { if (attr.second->type != AST_CONSTANT) log_file_error(*ast->location.begin.filename, ast->location.begin.line, "Attribute `%s' with non-constant value!\n", attr.first); diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 83174e963..a5b8c77ac 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -879,7 +879,7 @@ static void check_auto_nosync(AstNode *node) } // remove the attributes we've "consumed" - for (const RTLIL::IdString &str : attrs_to_drop) { + for (RTLIL::IdString str : attrs_to_drop) { auto it = node->attributes.find(str); node->attributes.erase(it); } @@ -4690,6 +4690,7 @@ void AstNode::expand_genblock(const std::string &prefix) switch (child->type) { case AST_WIRE: + case AST_AUTOWIRE: case AST_MEMORY: case AST_STRUCT: case AST_UNION: @@ -4718,6 +4719,93 @@ void AstNode::expand_genblock(const std::string &prefix) } break; + case AST_IDENTIFIER: + if (!child->str.empty() && prefix.size() > 0) { + bool is_resolved = false; + std::string identifier_str = child->str; + if (current_ast_mod != nullptr && identifier_str.compare(0, current_ast_mod->str.size(), current_ast_mod->str) == 0) { + if (identifier_str.at(current_ast_mod->str.size()) == '.') { + identifier_str = '\\' + identifier_str.substr(current_ast_mod->str.size()+1, identifier_str.size()); + } + } + // search starting in the innermost scope and then stepping outward + for (size_t ppos = prefix.size() - 1; ppos; --ppos) { + if (prefix.at(ppos) != '.') continue; + + std::string new_prefix = prefix.substr(0, ppos + 1); + auto attempt_resolve = [&new_prefix](const std::string &ident) -> std::string { + std::string new_name = prefix_id(new_prefix, ident); + if (current_scope.count(new_name)) + return new_name; + return {}; + }; + + // attempt to resolve the full identifier + std::string resolved = attempt_resolve(identifier_str); + if (!resolved.empty()) { + is_resolved = true; + break; + } + // attempt to resolve hierarchical prefixes within the identifier, + // as the prefix could refer to a local scope which exists but + // hasn't yet been elaborated + for (size_t spos = identifier_str.size() - 1; spos; --spos) { + if (identifier_str.at(spos) != '.') continue; + resolved = attempt_resolve(identifier_str.substr(0, spos)); + if (!resolved.empty()) { + is_resolved = true; + identifier_str = resolved + identifier_str.substr(spos); + ppos = 1; // break outer loop + break; + } + } + if (current_scope.count(identifier_str) == 0) { + AstNode *current_scope_ast = (current_ast_mod == nullptr) ? current_ast : current_ast_mod; + for (auto& node : current_scope_ast->children) { + switch (node->type) { + case AST_PARAMETER: + case AST_LOCALPARAM: + case AST_WIRE: + case AST_AUTOWIRE: + case AST_GENVAR: + case AST_MEMORY: + case AST_FUNCTION: + case AST_TASK: + case AST_DPI_FUNCTION: + if (prefix_id(new_prefix, identifier_str) == node->str) { + is_resolved = true; + current_scope[node->str] = node.get(); + } + break; + case AST_ENUM: + current_scope[node->str] = node.get(); + for (auto& enum_node : node->children) { + log_assert(enum_node->type==AST_ENUM_ITEM); + if (prefix_id(new_prefix, identifier_str) == enum_node->str) { + is_resolved = true; + current_scope[enum_node->str] = enum_node.get(); + } + } + break; + default: + break; + } + } + } + } + if ((current_scope.count(identifier_str) == 0) && is_resolved == false) { + if (current_ast_mod == nullptr) { + input_error("Identifier `%s' is implicitly declared outside of a module.\n", child->str.c_str()); + } else if (flag_autowire || identifier_str == "\\$global_clock") { + auto auto_wire = std::make_unique(child->location, AST_AUTOWIRE); + auto_wire->str = identifier_str; + children.push_back(std::move(auto_wire)); + } else { + input_error("Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", identifier_str.c_str()); + } + } + } + break; default: break; } diff --git a/frontends/rtlil/rtlil_frontend.cc b/frontends/rtlil/rtlil_frontend.cc index 271962725..a1412d983 100644 --- a/frontends/rtlil/rtlil_frontend.cc +++ b/frontends/rtlil/rtlil_frontend.cc @@ -40,6 +40,7 @@ struct RTLILFrontendWorker { bool flag_nooverwrite = false; bool flag_overwrite = false; bool flag_lib = false; + bool flag_legalize = false; int line_num; std::string line_buf; @@ -322,6 +323,17 @@ struct RTLILFrontendWorker { return val; } + RTLIL::Wire *legalize_wire(RTLIL::IdString id) + { + int wires_size = current_module->wires_size(); + if (wires_size == 0) + error("No wires found for legalization"); + int hash = hash_ops::hash(id).yield(); + RTLIL::Wire *wire = current_module->wire_at(abs(hash % wires_size)); + log("Legalizing wire `%s' to `%s'.\n", log_id(id), log_id(wire->name)); + return wire; + } + RTLIL::SigSpec parse_sigspec() { RTLIL::SigSpec sig; @@ -339,8 +351,12 @@ struct RTLILFrontendWorker { std::optional id = try_parse_id(); if (id.has_value()) { RTLIL::Wire *wire = current_module->wire(*id); - if (wire == nullptr) - error("Wire `%s' not found.", *id); + if (wire == nullptr) { + if (flag_legalize) + wire = legalize_wire(*id); + else + error("Wire `%s' not found.", *id); + } sig = RTLIL::SigSpec(wire); } else { sig = RTLIL::SigSpec(parse_const()); @@ -349,17 +365,44 @@ struct RTLILFrontendWorker { while (try_parse_char('[')) { int left = parse_integer(); - if (left >= sig.size() || left < 0) - error("bit index %d out of range", left); + if (left >= sig.size() || left < 0) { + if (flag_legalize) { + int legalized; + if (sig.size() == 0) + legalized = 0; + else + legalized = std::max(0, std::min(left, sig.size() - 1)); + log("Legalizing bit index %d to %d.\n", left, legalized); + left = legalized; + } else { + error("bit index %d out of range", left); + } + } if (try_parse_char(':')) { int right = parse_integer(); - if (right < 0) - error("bit index %d out of range", right); - if (left < right) - error("invalid slice [%d:%d]", left, right); - sig = sig.extract(right, left-right+1); + if (right < 0) { + if (flag_legalize) { + log("Legalizing bit index %d to %d.\n", right, 0); + right = 0; + } else + error("bit index %d out of range", right); + } + if (left < right) { + if (flag_legalize) { + log("Legalizing bit index %d to %d.\n", left, right); + left = right; + } else + error("invalid slice [%d:%d]", left, right); + } + if (flag_legalize && left >= sig.size()) + log("Legalizing slice %d:%d by igoring it\n", left, right); + else + sig = sig.extract(right, left - right + 1); } else { - sig = sig.extract(left); + if (flag_legalize && left >= sig.size()) + log("Legalizing slice %d by igoring it\n", left); + else + sig = sig.extract(left); } expect_char(']'); } @@ -476,8 +519,14 @@ struct RTLILFrontendWorker { { std::optional id = try_parse_id(); if (id.has_value()) { - if (current_module->wire(*id) != nullptr) - error("RTLIL error: redefinition of wire %s.", *id); + if (current_module->wire(*id) != nullptr) { + if (flag_legalize) { + log("Legalizing redefinition of wire %s.\n", *id); + pool wires = {current_module->wire(*id)}; + current_module->remove(wires); + } else + error("RTLIL error: redefinition of wire %s.", *id); + } wire = current_module->addWire(std::move(*id)); break; } @@ -528,8 +577,13 @@ struct RTLILFrontendWorker { { std::optional id = try_parse_id(); if (id.has_value()) { - if (current_module->memories.count(*id) != 0) - error("RTLIL error: redefinition of memory %s.", *id); + if (current_module->memories.count(*id) != 0) { + if (flag_legalize) { + log("Legalizing redefinition of memory %s.\n", *id); + current_module->remove(current_module->memories.at(*id)); + } else + error("RTLIL error: redefinition of memory %s.", *id); + } memory->name = std::move(*id); break; } @@ -551,14 +605,36 @@ struct RTLILFrontendWorker { expect_eol(); } + void legalize_width_parameter(RTLIL::Cell *cell, RTLIL::IdString port_name) + { + std::string width_param_name = port_name.str() + "_WIDTH"; + if (cell->parameters.count(width_param_name) == 0) + return; + RTLIL::Const ¶m = cell->parameters.at(width_param_name); + if (param.as_int() != 0) + return; + cell->parameters[width_param_name] = RTLIL::Const(cell->getPort(port_name).size()); + } + void parse_cell() { RTLIL::IdString cell_type = parse_id(); RTLIL::IdString cell_name = parse_id(); expect_eol(); - if (current_module->cell(cell_name) != nullptr) - error("RTLIL error: redefinition of cell %s.", cell_name); + if (current_module->cell(cell_name) != nullptr) { + if (flag_legalize) { + RTLIL::IdString new_name; + int suffix = 1; + do { + new_name = RTLIL::IdString(cell_name.str() + "_" + std::to_string(suffix)); + ++suffix; + } while (current_module->cell(new_name) != nullptr); + log("Legalizing redefinition of cell %s by renaming to %s.\n", cell_name, new_name); + cell_name = new_name; + } else + error("RTLIL error: redefinition of cell %s.", cell_name); + } RTLIL::Cell *cell = current_module->addCell(cell_name, cell_type); cell->attributes = std::move(attrbuf); @@ -587,9 +663,15 @@ struct RTLILFrontendWorker { expect_eol(); } else if (try_parse_keyword("connect")) { RTLIL::IdString port_name = parse_id(); - if (cell->hasPort(port_name)) - error("RTLIL error: redefinition of cell port %s.", port_name); + if (cell->hasPort(port_name)) { + if (flag_legalize) + log("Legalizing redefinition of cell port %s.", port_name); + else + error("RTLIL error: redefinition of cell port %s.", port_name); + } cell->setPort(std::move(port_name), parse_sigspec()); + if (flag_legalize) + legalize_width_parameter(cell, port_name); expect_eol(); } else if (try_parse_keyword("end")) { expect_eol(); @@ -606,6 +688,11 @@ struct RTLILFrontendWorker { error("dangling attribute"); RTLIL::SigSpec s1 = parse_sigspec(); RTLIL::SigSpec s2 = parse_sigspec(); + if (flag_legalize) { + int min_size = std::min(s1.size(), s2.size()); + s1 = s1.extract(0, min_size); + s2 = s2.extract(0, min_size); + } current_module->connect(std::move(s1), std::move(s2)); expect_eol(); } @@ -682,8 +769,13 @@ struct RTLILFrontendWorker { RTLIL::IdString proc_name = parse_id(); expect_eol(); - if (current_module->processes.count(proc_name) != 0) - error("RTLIL error: redefinition of process %s.", proc_name); + if (current_module->processes.count(proc_name) != 0) { + if (flag_legalize) { + log("Legalizing redefinition of process %s.\n", proc_name); + current_module->remove(current_module->processes.at(proc_name)); + } else + error("RTLIL error: redefinition of process %s.", proc_name); + } RTLIL::Process *proc = current_module->addProcess(std::move(proc_name)); proc->attributes = std::move(attrbuf); @@ -804,6 +896,11 @@ struct RTLILFrontend : public Frontend { log(" -lib\n"); log(" only create empty blackbox modules\n"); log("\n"); + log(" -legalize\n"); + log(" prevent semantic errors (e.g. reference to unknown wire, redefinition of wire/cell)\n"); + log(" by deterministically rewriting the input into something valid. Useful when using\n"); + log(" fuzzing to generate random but valid RTLIL.\n"); + log("\n"); } void execute(std::istream *&f, std::string filename, std::vector args, RTLIL::Design *design) override { @@ -828,6 +925,10 @@ struct RTLILFrontend : public Frontend { worker.flag_lib = true; continue; } + if (arg == "-legalize") { + worker.flag_legalize = true; + continue; + } break; } extra_args(f, filename, args, argidx); diff --git a/frontends/verific/verificsva.cc b/frontends/verific/verificsva.cc index dffe6e8e0..c2cfe7e75 100644 --- a/frontends/verific/verificsva.cc +++ b/frontends/verific/verificsva.cc @@ -1846,7 +1846,10 @@ struct VerificSvaImporter if (mode_assume) c = module->addAssume(root_name, sig_a_q, sig_en_q); if (mode_cover) c = module->addCover(root_name, sig_a_q, sig_en_q); - if (c) importer->import_attributes(c->attributes, root); + if (c) { + c->set_bool_attribute(ID(keep)); + importer->import_attributes(c->attributes, root); + } } } catch (ParserErrorException) diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index 6c9e67dc5..29a739f81 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -500,7 +500,6 @@ struct VerilogFrontend : public Frontend { log("Parsing %s%s input from `%s' to AST representation.\n", parse_mode.formal ? "formal " : "", parse_mode.sv ? "SystemVerilog" : "Verilog", filename.c_str()); - log("verilog frontend filename %s\n", filename.c_str()); if (flag_relative_share) { auto share_path = proc_share_dirname(); if (filename.substr(0, share_path.length()) == share_path) diff --git a/kernel/cellaigs.cc b/kernel/cellaigs.cc index fd3c7bb67..0f897cd58 100644 --- a/kernel/cellaigs.cc +++ b/kernel/cellaigs.cc @@ -185,50 +185,68 @@ struct AigMaker int or_gate(int A, int B) { - return nand_gate(not_gate(A), not_gate(B)); + int not_a = not_gate(A); + int not_b = not_gate(B); + return nand_gate(not_a, not_b); } int nor_gate(int A, int B) { - return and_gate(not_gate(A), not_gate(B)); + int not_a = not_gate(A); + int not_b = not_gate(B); + return and_gate(not_a, not_b); } int xor_gate(int A, int B) { - return nor_gate(and_gate(A, B), nor_gate(A, B)); + int a_and_b = and_gate(A, B); + int a_nor_b = nor_gate(A, B); + return nor_gate(a_and_b, a_nor_b); } int xnor_gate(int A, int B) { - return or_gate(and_gate(A, B), nor_gate(A, B)); + int a_and_b = and_gate(A, B); + int a_nor_b = nor_gate(A, B); + return or_gate(a_and_b, a_nor_b); } int andnot_gate(int A, int B) { - return and_gate(A, not_gate(B)); + int not_b = not_gate(B); + return and_gate(A, not_b); } int ornot_gate(int A, int B) { - return or_gate(A, not_gate(B)); + int not_b = not_gate(B); + return or_gate(A, not_b); } int mux_gate(int A, int B, int S) { - return or_gate(and_gate(A, not_gate(S)), and_gate(B, S)); + int not_s = not_gate(S); + int a_active = and_gate(A, not_s); + int b_active = and_gate(B, S); + return or_gate(a_active, b_active); } - vector adder(const vector &A, const vector &B, int carry, vector *X = nullptr, vector *CO = nullptr) + vector adder(const vector &A, const vector &B, int carry_in, vector *X = nullptr, vector *CO = nullptr) { vector Y(GetSize(A)); log_assert(GetSize(A) == GetSize(B)); for (int i = 0; i < GetSize(A); i++) { - Y[i] = xor_gate(xor_gate(A[i], B[i]), carry); - carry = or_gate(and_gate(A[i], B[i]), and_gate(or_gate(A[i], B[i]), carry)); + int a_xor_b = xor_gate(A[i], B[i]); + int a_or_b = or_gate(A[i], B[i]); + int a_and_b = and_gate(A[i], B[i]); + Y[i] = xor_gate(a_xor_b, carry_in); + int tmp = and_gate(a_or_b, carry_in); + int carry_out = or_gate(a_and_b, tmp); if (X != nullptr) - X->at(i) = xor_gate(A[i], B[i]); + X->at(i) = a_xor_b; if (CO != nullptr) - CO->at(i) = carry; + CO->at(i) = carry_out; + carry_in = carry_out; } return Y; } @@ -307,13 +325,13 @@ Aig::Aig(Cell *cell) int A = mk.inport(ID::A, i); int B = mk.inport(ID::B, i); int Y = cell->type.in(ID($and), ID($_AND_)) ? mk.and_gate(A, B) : - cell->type.in(ID($_NAND_)) ? mk.nand_gate(A, B) : + cell->type.in(ID($_NAND_)) ? mk.nand_gate(A, B) : cell->type.in(ID($or), ID($_OR_)) ? mk.or_gate(A, B) : - cell->type.in(ID($_NOR_)) ? mk.nor_gate(A, B) : + cell->type.in(ID($_NOR_)) ? mk.nor_gate(A, B) : cell->type.in(ID($xor), ID($_XOR_)) ? mk.xor_gate(A, B) : cell->type.in(ID($xnor), ID($_XNOR_)) ? mk.xnor_gate(A, B) : - cell->type.in(ID($_ANDNOT_)) ? mk.andnot_gate(A, B) : - cell->type.in(ID($_ORNOT_)) ? mk.ornot_gate(A, B) : -1; + cell->type.in(ID($_ANDNOT_)) ? mk.andnot_gate(A, B) : + cell->type.in(ID($_ORNOT_)) ? mk.ornot_gate(A, B) : -1; mk.outport(Y, ID::Y, i); } goto optimize; @@ -465,7 +483,8 @@ Aig::Aig(Cell *cell) int B = mk.inport(ID::B); int C = mk.inport(ID::C); int D = mk.inport(ID::D); - int Y = mk.nor_gate(mk.and_gate(A, B), mk.and_gate(C, D)); + int a_and_b = mk.and_gate(A, B); + int Y = mk.nor_gate(a_and_b, mk.and_gate(C, D)); mk.outport(Y, ID::Y); goto optimize; } @@ -476,7 +495,8 @@ Aig::Aig(Cell *cell) int B = mk.inport(ID::B); int C = mk.inport(ID::C); int D = mk.inport(ID::D); - int Y = mk.nand_gate(mk.or_gate(A, B), mk.or_gate(C, D)); + int a_or_b = mk.or_gate(A, B); + int Y = mk.nand_gate(a_or_b, mk.or_gate(C, D)); mk.outport(Y, ID::Y); goto optimize; } diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 2c3535eac..34b013dd9 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -305,18 +305,18 @@ struct CellTypes cell_types.clear(); } - bool cell_known(const RTLIL::IdString &type) const + bool cell_known(RTLIL::IdString type) const { return cell_types.count(type) != 0; } - bool cell_output(const RTLIL::IdString &type, const RTLIL::IdString &port) const + bool cell_output(RTLIL::IdString type, RTLIL::IdString port) const { auto it = cell_types.find(type); return it != cell_types.end() && it->second.outputs.count(port) != 0; } - bool cell_input(const RTLIL::IdString &type, const RTLIL::IdString &port) const + bool cell_input(RTLIL::IdString type, RTLIL::IdString port) const { auto it = cell_types.find(type); return it != cell_types.end() && it->second.inputs.count(port) != 0; @@ -332,7 +332,7 @@ struct CellTypes return RTLIL::PortDir(is_input + is_output * 2); } - bool cell_evaluable(const RTLIL::IdString &type) const + bool cell_evaluable(RTLIL::IdString type) const { auto it = cell_types.find(type); return it != cell_types.end() && it->second.is_evaluable; diff --git a/kernel/driver.cc b/kernel/driver.cc index 4097411b4..fa78bad59 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -255,6 +255,7 @@ int main(int argc, char **argv) ("h,help", "print this help message. If given, print help for .", cxxopts::value(), "[]") ("V,version", "print version information and exit") + ("git-hash", "print git commit hash and exit") ("infile", "input files", cxxopts::value>()) ; options.add_options("logging") @@ -332,6 +333,10 @@ int main(int argc, char **argv) std::cout << yosys_version_str << std::endl; exit(0); } + if (result.count("git-hash")) { + std::cout << yosys_git_hash_str << std::endl; + exit(0); + } if (result.count("S")) { passes_commands.push_back("synth"); run_shell = false; @@ -764,33 +769,6 @@ int main(int argc, char **argv) } } -#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__)) - if (getenv("YOSYS_COVER_DIR") || getenv("YOSYS_COVER_FILE")) - { - string filename; - FILE *f; - - if (getenv("YOSYS_COVER_DIR")) { - filename = stringf("%s/yosys_cover_%d_XXXXXX.txt", getenv("YOSYS_COVER_DIR"), getpid()); - filename = make_temp_file(filename); - } else { - filename = getenv("YOSYS_COVER_FILE"); - } - - f = fopen(filename.c_str(), "a+"); - - if (f == NULL) - log_error("Can't create coverage file `%s'.\n", filename); - - log("\n", filename); - - for (auto &it : get_coverage_data()) - fprintf(f, "%-60s %10d %s\n", it.second.first.c_str(), it.second.second, it.first.c_str()); - - fclose(f); - } -#endif - log_check_expected(); yosys_atexit(); diff --git a/kernel/hashlib.h b/kernel/hashlib.h index ca600231a..b43a68abf 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -1321,6 +1321,12 @@ public: return i < 0 ? 0 : 1; } + int lookup(const K &key) const + { + Hasher::hash_t hash = database.do_hash(key); + return database.do_lookup_no_rehash(key, hash); + } + void expect(const K &key, int i) { int j = (*this)(key); diff --git a/kernel/io.cc b/kernel/io.cc index 4f805e43b..078fa139c 100644 --- a/kernel/io.cc +++ b/kernel/io.cc @@ -602,7 +602,7 @@ void format_emit_string_view(std::string &result, std::string_view spec, int *dy } void format_emit_idstring(std::string &result, std::string_view spec, int *dynamic_ints, - DynamicIntCount num_dynamic_ints, const IdString &arg) + DynamicIntCount num_dynamic_ints, const RTLIL::IdString &arg) { if (spec == "%s") { // Format checking will have guaranteed num_dynamic_ints == 0. diff --git a/kernel/log.cc b/kernel/log.cc index d712eda2c..018a19081 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -90,11 +90,11 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) QueryPerformanceFrequency(&freq); QueryPerformanceCounter(&counter); - counter.QuadPart *= 1000000; + counter.QuadPart *= 1'000'000; counter.QuadPart /= freq.QuadPart; tv->tv_sec = long(counter.QuadPart / 1000000); - tv->tv_usec = counter.QuadPart % 1000000; + tv->tv_usec = counter.QuadPart % 1'000'000; return 0; } @@ -135,7 +135,7 @@ static void logv_string(std::string_view format, std::string str) { initial_tv = tv; if (tv.tv_usec < initial_tv.tv_usec) { tv.tv_sec--; - tv.tv_usec += 1000000; + tv.tv_usec += 1'000'000; } tv.tv_sec -= initial_tv.tv_sec; tv.tv_usec -= initial_tv.tv_usec; @@ -203,6 +203,8 @@ static void logv_string(std::string_view format, std::string str) { void log_formatted_string(std::string_view format, std::string str) { + log_assert(!Multithreading::active()); + if (log_make_debug && !ys_debug(1)) return; logv_string(format, std::move(str)); @@ -210,6 +212,8 @@ void log_formatted_string(std::string_view format, std::string str) void log_formatted_header(RTLIL::Design *design, std::string_view format, std::string str) { + log_assert(!Multithreading::active()); + bool pop_errfile = false; log_spacer(); @@ -249,6 +253,8 @@ void log_formatted_header(RTLIL::Design *design, std::string_view format, std::s void log_formatted_warning(std::string_view prefix, std::string message) { + log_assert(!Multithreading::active()); + bool suppressed = false; for (auto &re : log_nowarn_regexes) @@ -681,55 +687,4 @@ void log_check_expected() check_err("prefixed error", pattern, item); } -// --------------------------------------------------- -// This is the magic behind the code coverage counters -// --------------------------------------------------- -#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__)) - -dict> extra_coverage_data; - -void cover_extra(std::string parent, std::string id, bool increment) { - if (extra_coverage_data.count(id) == 0) { - for (CoverData *p = __start_yosys_cover_list; p != __stop_yosys_cover_list; p++) - if (p->id == parent) - extra_coverage_data[id].first = stringf("%s:%d:%s", p->file, p->line, p->func); - log_assert(extra_coverage_data.count(id)); - } - if (increment) - extra_coverage_data[id].second++; -} - -dict> get_coverage_data() -{ - dict> coverage_data; - - for (auto &it : pass_register) { - std::string key = stringf("passes.%s", it.first); - coverage_data[key].first = stringf("%s:%d:%s", __FILE__, __LINE__, __FUNCTION__); - coverage_data[key].second += it.second->call_counter; - } - - for (auto &it : extra_coverage_data) { - if (coverage_data.count(it.first)) - log_warning("found duplicate coverage id \"%s\".\n", it.first); - coverage_data[it.first].first = it.second.first; - coverage_data[it.first].second += it.second.second; - } - - for (CoverData *p = __start_yosys_cover_list; p != __stop_yosys_cover_list; p++) { - if (coverage_data.count(p->id)) - log_warning("found duplicate coverage id \"%s\".\n", p->id); - coverage_data[p->id].first = stringf("%s:%d:%s", p->file, p->line, p->func); - coverage_data[p->id].second += p->counter.load(std::memory_order_relaxed); - } - - for (auto &it : coverage_data) - if (!it.second.first.compare(0, strlen(YOSYS_SRC "/"), YOSYS_SRC "/")) - it.second.first = it.second.first.substr(strlen(YOSYS_SRC "/")); - - return coverage_data; -} - -#endif - YOSYS_NAMESPACE_END diff --git a/kernel/log.h b/kernel/log.h index 197cfab8d..63faf7091 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -291,54 +291,6 @@ void log_abort_internal(const char *file, int line); #define log_ping() YOSYS_NAMESPACE_PREFIX log("-- %s:%d %s --\n", __FILE__, __LINE__, __PRETTY_FUNCTION__) -// --------------------------------------------------- -// This is the magic behind the code coverage counters -// --------------------------------------------------- - -#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__)) - -#define cover(_id) do { \ - static CoverData __d __attribute__((section("yosys_cover_list"), aligned(1), used)) = { __FILE__, __FUNCTION__, _id, __LINE__, 0 }; \ - __d.counter.fetch_add(1, std::memory_order_relaxed); \ -} while (0) - -struct CoverData { - const char *file, *func, *id; - int line; - std::atomic counter; -}; - -// this two symbols are created by the linker __start_yosys_cover_listfor the "yosys_cover_list" ELF section -extern "C" struct CoverData __start_yosys_cover_list[]; -extern "C" struct CoverData __stop_yosys_cover_list[]; - -extern dict> extra_coverage_data; - -void cover_extra(std::string parent, std::string id, bool increment = true); -dict> get_coverage_data(); - -#define cover_list(_id, ...) do { cover(_id); \ - std::string r = cover_list_worker(_id, __VA_ARGS__); \ - log_assert(r.empty()); \ -} while (0) - -static inline std::string cover_list_worker(std::string, std::string last) { - return last; -} - -template -std::string cover_list_worker(std::string prefix, std::string first, T... rest) { - std::string selected = cover_list_worker(prefix, rest...); - cover_extra(prefix, prefix + "." + first, first == selected); - return first == selected ? "" : selected; -} - -#else -# define cover(...) do { } while (0) -# define cover_list(...) do { } while (0) -#endif - - // ------------------------------------------------------------ // everything below this line are utilities for troubleshooting // ------------------------------------------------------------ diff --git a/kernel/modtools.h b/kernel/modtools.h index 27ba98d7d..a081c7556 100644 --- a/kernel/modtools.h +++ b/kernel/modtools.h @@ -161,7 +161,7 @@ struct ModIndex : public RTLIL::Monitor #endif } - void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, const RTLIL::SigSpec &sig) override + void notify_connect(RTLIL::Cell *cell, RTLIL::IdString port, const RTLIL::SigSpec &old_sig, const RTLIL::SigSpec &sig) override { log_assert(module == cell->module); diff --git a/kernel/register.cc b/kernel/register.cc index 3f5aa49ca..abde8f47e 100644 --- a/kernel/register.cc +++ b/kernel/register.cc @@ -1204,7 +1204,7 @@ struct LicensePass : public Pass { log(" | |\n"); log(" | yosys -- Yosys Open SYnthesis Suite |\n"); log(" | |\n"); - log(" | Copyright (C) 2012 - 2025 Claire Xenia Wolf |\n"); + log(" | Copyright (C) 2012 - 2026 Claire Xenia Wolf |\n"); log(" | |\n"); log(" | Permission to use, copy, modify, and/or distribute this software for any |\n"); log(" | purpose with or without fee is hereby granted, provided that the above |\n"); diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 6960b7620..0dbe8bb13 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -883,8 +883,6 @@ RTLIL::State RTLIL::Const::const_iterator::operator*() const { bool RTLIL::Const::is_fully_zero() const { - cover("kernel.rtlil.const.is_fully_zero"); - if (auto str = get_if_str()) { for (char ch : *str) if (ch != 0) @@ -903,8 +901,6 @@ bool RTLIL::Const::is_fully_zero() const bool RTLIL::Const::is_fully_ones() const { - cover("kernel.rtlil.const.is_fully_ones"); - if (auto str = get_if_str()) { for (char ch : *str) if (ch != (char)0xff) @@ -922,8 +918,6 @@ bool RTLIL::Const::is_fully_ones() const bool RTLIL::Const::is_fully_def() const { - cover("kernel.rtlil.const.is_fully_def"); - if (is_str()) return true; @@ -937,8 +931,6 @@ bool RTLIL::Const::is_fully_def() const bool RTLIL::Const::is_fully_undef() const { - cover("kernel.rtlil.const.is_fully_undef"); - if (auto str = get_if_str()) return str->empty(); @@ -952,8 +944,6 @@ bool RTLIL::Const::is_fully_undef() const bool RTLIL::Const::is_fully_undef_x_only() const { - cover("kernel.rtlil.const.is_fully_undef_x_only"); - if (auto str = get_if_str()) return str->empty(); @@ -967,8 +957,6 @@ bool RTLIL::Const::is_fully_undef_x_only() const bool RTLIL::Const::is_onehot(int *pos) const { - cover("kernel.rtlil.const.is_onehot"); - bool found = false; int size = GetSize(*this); for (int i = 0; i < size; i++) { @@ -1029,12 +1017,12 @@ RTLIL::Const RTLIL::Const::extract(int offset, int len, RTLIL::State padding) co } #undef check /* check(condition) for Const */ -bool RTLIL::AttrObject::has_attribute(const RTLIL::IdString &id) const +bool RTLIL::AttrObject::has_attribute(RTLIL::IdString id) const { return attributes.count(id); } -void RTLIL::AttrObject::set_bool_attribute(const RTLIL::IdString &id, bool value) +void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id, bool value) { if (value) attributes[id] = RTLIL::Const(1); @@ -1042,7 +1030,7 @@ void RTLIL::AttrObject::set_bool_attribute(const RTLIL::IdString &id, bool value attributes.erase(id); } -bool RTLIL::AttrObject::get_bool_attribute(const RTLIL::IdString &id) const +bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const { const auto it = attributes.find(id); if (it == attributes.end()) @@ -1050,7 +1038,7 @@ bool RTLIL::AttrObject::get_bool_attribute(const RTLIL::IdString &id) const return it->second.as_bool(); } -void RTLIL::AttrObject::set_string_attribute(const RTLIL::IdString& id, string value) +void RTLIL::AttrObject::set_string_attribute(RTLIL::IdString id, string value) { if (value.empty()) attributes.erase(id); @@ -1058,7 +1046,7 @@ void RTLIL::AttrObject::set_string_attribute(const RTLIL::IdString& id, string v attributes[id] = value; } -string RTLIL::AttrObject::get_string_attribute(const RTLIL::IdString &id) const +string RTLIL::AttrObject::get_string_attribute(RTLIL::IdString id) const { std::string value; const auto it = attributes.find(id); @@ -1067,7 +1055,7 @@ string RTLIL::AttrObject::get_string_attribute(const RTLIL::IdString &id) const return value; } -void RTLIL::AttrObject::set_strpool_attribute(const RTLIL::IdString& id, const pool &data) +void RTLIL::AttrObject::set_strpool_attribute(RTLIL::IdString id, const pool &data) { string attrval; for (const auto &s : data) { @@ -1078,7 +1066,7 @@ void RTLIL::AttrObject::set_strpool_attribute(const RTLIL::IdString& id, const p set_string_attribute(id, attrval); } -void RTLIL::AttrObject::add_strpool_attribute(const RTLIL::IdString& id, const pool &data) +void RTLIL::AttrObject::add_strpool_attribute(RTLIL::IdString id, const pool &data) { pool union_data = get_strpool_attribute(id); union_data.insert(data.begin(), data.end()); @@ -1086,7 +1074,7 @@ void RTLIL::AttrObject::add_strpool_attribute(const RTLIL::IdString& id, const p set_strpool_attribute(id, union_data); } -pool RTLIL::AttrObject::get_strpool_attribute(const RTLIL::IdString &id) const +pool RTLIL::AttrObject::get_strpool_attribute(RTLIL::IdString id) const { pool data; if (attributes.count(id) != 0) @@ -1111,7 +1099,7 @@ vector RTLIL::AttrObject::get_hdlname_attribute() const return split_tokens(get_string_attribute(ID::hdlname), " "); } -void RTLIL::AttrObject::set_intvec_attribute(const RTLIL::IdString& id, const vector &data) +void RTLIL::AttrObject::set_intvec_attribute(RTLIL::IdString id, const vector &data) { std::stringstream attrval; for (auto &i : data) { @@ -1122,7 +1110,7 @@ void RTLIL::AttrObject::set_intvec_attribute(const RTLIL::IdString& id, const ve attributes[id] = RTLIL::Const(attrval.str()); } -vector RTLIL::AttrObject::get_intvec_attribute(const RTLIL::IdString &id) const +vector RTLIL::AttrObject::get_intvec_attribute(RTLIL::IdString id) const { vector data; auto it = attributes.find(id); @@ -1140,7 +1128,7 @@ vector RTLIL::AttrObject::get_intvec_attribute(const RTLIL::IdString &id) c return data; } -bool RTLIL::Selection::boxed_module(const RTLIL::IdString &mod_name) const +bool RTLIL::Selection::boxed_module(RTLIL::IdString mod_name) const { if (current_design != nullptr) { auto module = current_design->module(mod_name); @@ -1151,7 +1139,7 @@ bool RTLIL::Selection::boxed_module(const RTLIL::IdString &mod_name) const } } -bool RTLIL::Selection::selected_module(const RTLIL::IdString &mod_name) const +bool RTLIL::Selection::selected_module(RTLIL::IdString mod_name) const { if (complete_selection) return true; @@ -1166,7 +1154,7 @@ bool RTLIL::Selection::selected_module(const RTLIL::IdString &mod_name) const return false; } -bool RTLIL::Selection::selected_whole_module(const RTLIL::IdString &mod_name) const +bool RTLIL::Selection::selected_whole_module(RTLIL::IdString mod_name) const { if (complete_selection) return true; @@ -1179,7 +1167,7 @@ bool RTLIL::Selection::selected_whole_module(const RTLIL::IdString &mod_name) co return false; } -bool RTLIL::Selection::selected_member(const RTLIL::IdString &mod_name, const RTLIL::IdString &memb_name) const +bool RTLIL::Selection::selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const { if (complete_selection) return true; @@ -1306,12 +1294,12 @@ RTLIL::ObjRange RTLIL::Design::modules() return RTLIL::ObjRange(&modules_, &refcount_modules_); } -RTLIL::Module *RTLIL::Design::module(const RTLIL::IdString& name) +RTLIL::Module *RTLIL::Design::module(RTLIL::IdString name) { return modules_.count(name) ? modules_.at(name) : NULL; } -const RTLIL::Module *RTLIL::Design::module(const RTLIL::IdString& name) const +const RTLIL::Module *RTLIL::Design::module(RTLIL::IdString name) const { return modules_.count(name) ? modules_.at(name) : NULL; } @@ -1500,21 +1488,21 @@ void RTLIL::Design::optimize() it.second.optimize(this); } -bool RTLIL::Design::selected_module(const RTLIL::IdString& mod_name) const +bool RTLIL::Design::selected_module(RTLIL::IdString mod_name) const { if (!selected_active_module.empty() && mod_name != selected_active_module) return false; return selection().selected_module(mod_name); } -bool RTLIL::Design::selected_whole_module(const RTLIL::IdString& mod_name) const +bool RTLIL::Design::selected_whole_module(RTLIL::IdString mod_name) const { if (!selected_active_module.empty() && mod_name != selected_active_module) return false; return selection().selected_whole_module(mod_name); } -bool RTLIL::Design::selected_member(const RTLIL::IdString& mod_name, const RTLIL::IdString& memb_name) const +bool RTLIL::Design::selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const { if (!selected_active_module.empty() && mod_name != selected_active_module) return false; @@ -1705,7 +1693,7 @@ RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, const dictname.c_str(), cell->type.c_str(), __FILE__, linenr, buf.str().c_str()); } - int param(const RTLIL::IdString& name) + int param(RTLIL::IdString name) { auto it = cell->parameters.find(name); if (it == cell->parameters.end()) @@ -1739,7 +1727,7 @@ namespace { return it->second.as_int(); } - int param_bool(const RTLIL::IdString& name) + int param_bool(RTLIL::IdString name) { int v = param(name); if (GetSize(cell->parameters.at(name)) > 32) @@ -1749,7 +1737,7 @@ namespace { return v; } - int param_bool(const RTLIL::IdString& name, bool expected) + int param_bool(RTLIL::IdString name, bool expected) { int v = param_bool(name); if (v != expected) @@ -1757,20 +1745,20 @@ namespace { return v; } - void param_bits(const RTLIL::IdString& name, int width) + void param_bits(RTLIL::IdString name, int width) { param(name); if (GetSize(cell->parameters.at(name)) != width) error(__LINE__); } - std::string param_string(const RTLIL::IdString &name) + std::string param_string(RTLIL::IdString name) { param(name); return cell->parameters.at(name).decode_string(); } - void port(const RTLIL::IdString& name, int width) + void port(RTLIL::IdString name, int width) { auto it = cell->connections_.find(name); if (it == cell->connections_.end()) @@ -3051,6 +3039,13 @@ void RTLIL::Module::remove(RTLIL::Cell *cell) } } +void RTLIL::Module::remove(RTLIL::Memory *memory) +{ + log_assert(memories.count(memory->name) != 0); + memories.erase(memory->name); + delete memory; +} + void RTLIL::Module::remove(RTLIL::Process *process) { log_assert(processes.count(process->name) != 0); @@ -4378,14 +4373,14 @@ std::map *RTLIL::Cell::get_all_cells(void) } #endif -bool RTLIL::Cell::hasPort(const RTLIL::IdString& portname) const +bool RTLIL::Cell::hasPort(RTLIL::IdString portname) const { return connections_.count(portname) != 0; } // bufnorm -const RTLIL::SigSpec &RTLIL::Cell::getPort(const RTLIL::IdString& portname) const +const RTLIL::SigSpec &RTLIL::Cell::getPort(RTLIL::IdString portname) const { return connections_.at(portname); } @@ -4404,7 +4399,7 @@ bool RTLIL::Cell::known() const return false; } -bool RTLIL::Cell::input(const RTLIL::IdString& portname) const +bool RTLIL::Cell::input(RTLIL::IdString portname) const { if (yosys_celltypes.cell_known(type)) return yosys_celltypes.cell_input(type, portname); @@ -4416,7 +4411,7 @@ bool RTLIL::Cell::input(const RTLIL::IdString& portname) const return false; } -bool RTLIL::Cell::output(const RTLIL::IdString& portname) const +bool RTLIL::Cell::output(RTLIL::IdString portname) const { if (yosys_celltypes.cell_known(type)) return yosys_celltypes.cell_output(type, portname); @@ -4428,7 +4423,7 @@ bool RTLIL::Cell::output(const RTLIL::IdString& portname) const return false; } -RTLIL::PortDir RTLIL::Cell::port_dir(const RTLIL::IdString& portname) const +RTLIL::PortDir RTLIL::Cell::port_dir(RTLIL::IdString portname) const { if (yosys_celltypes.cell_known(type)) return yosys_celltypes.cell_port_dir(type, portname); @@ -4444,22 +4439,22 @@ RTLIL::PortDir RTLIL::Cell::port_dir(const RTLIL::IdString& portname) const return PortDir::PD_UNKNOWN; } -bool RTLIL::Cell::hasParam(const RTLIL::IdString& paramname) const +bool RTLIL::Cell::hasParam(RTLIL::IdString paramname) const { return parameters.count(paramname) != 0; } -void RTLIL::Cell::unsetParam(const RTLIL::IdString& paramname) +void RTLIL::Cell::unsetParam(RTLIL::IdString paramname) { parameters.erase(paramname); } -void RTLIL::Cell::setParam(const RTLIL::IdString& paramname, RTLIL::Const value) +void RTLIL::Cell::setParam(RTLIL::IdString paramname, RTLIL::Const value) { parameters[paramname] = std::move(value); } -const RTLIL::Const &RTLIL::Cell::getParam(const RTLIL::IdString& paramname) const +const RTLIL::Const &RTLIL::Cell::getParam(RTLIL::IdString paramname) const { const auto &it = parameters.find(paramname); if (it != parameters.end()) @@ -4648,8 +4643,6 @@ bool RTLIL::SigChunk::operator !=(const RTLIL::SigChunk &other) const RTLIL::SigSpec::SigSpec(std::initializer_list parts) { - cover("kernel.rtlil.sigspec.init.list"); - init_empty_bits(); log_assert(parts.size() > 0); auto ie = parts.begin(); @@ -4660,8 +4653,6 @@ RTLIL::SigSpec::SigSpec(std::initializer_list parts) RTLIL::SigSpec::SigSpec(const RTLIL::Const &value) { - cover("kernel.rtlil.sigspec.init.const"); - if (GetSize(value) != 0) { rep_ = CHUNK; new (&chunk_) RTLIL::SigChunk(value); @@ -4673,8 +4664,6 @@ RTLIL::SigSpec::SigSpec(const RTLIL::Const &value) RTLIL::SigSpec::SigSpec(RTLIL::Const &&value) { - cover("kernel.rtlil.sigspec.init.const.move"); - if (GetSize(value) != 0) { rep_ = CHUNK; new (&chunk_) RTLIL::SigChunk(value); @@ -4686,8 +4675,6 @@ RTLIL::SigSpec::SigSpec(RTLIL::Const &&value) RTLIL::SigSpec::SigSpec(const RTLIL::SigChunk &chunk) { - cover("kernel.rtlil.sigspec.init.chunk"); - if (chunk.width != 0) { rep_ = CHUNK; new (&chunk_) RTLIL::SigChunk(chunk); @@ -4699,8 +4686,6 @@ RTLIL::SigSpec::SigSpec(const RTLIL::SigChunk &chunk) RTLIL::SigSpec::SigSpec(RTLIL::SigChunk &&chunk) { - cover("kernel.rtlil.sigspec.init.chunk.move"); - if (chunk.width != 0) { rep_ = CHUNK; new (&chunk_) RTLIL::SigChunk(chunk); @@ -4712,8 +4697,6 @@ RTLIL::SigSpec::SigSpec(RTLIL::SigChunk &&chunk) RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire) { - cover("kernel.rtlil.sigspec.init.wire"); - if (wire->width != 0) { rep_ = CHUNK; new (&chunk_) RTLIL::SigChunk(wire); @@ -4725,8 +4708,6 @@ RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire) RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire, int offset, int width) { - cover("kernel.rtlil.sigspec.init.wire_part"); - if (width != 0) { rep_ = CHUNK; new (&chunk_) RTLIL::SigChunk(wire, offset, width); @@ -4738,8 +4719,6 @@ RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire, int offset, int width) RTLIL::SigSpec::SigSpec(const std::string &str) { - cover("kernel.rtlil.sigspec.init.str"); - if (str.size() != 0) { rep_ = CHUNK; new (&chunk_) RTLIL::SigChunk(str); @@ -4751,8 +4730,6 @@ RTLIL::SigSpec::SigSpec(const std::string &str) RTLIL::SigSpec::SigSpec(int val, int width) { - cover("kernel.rtlil.sigspec.init.int"); - if (width != 0) { rep_ = CHUNK; new (&chunk_) RTLIL::SigChunk(val, width); @@ -4763,8 +4740,6 @@ RTLIL::SigSpec::SigSpec(int val, int width) RTLIL::SigSpec::SigSpec(RTLIL::State bit, int width) { - cover("kernel.rtlil.sigspec.init.state"); - if (width != 0) { rep_ = CHUNK; new (&chunk_) RTLIL::SigChunk(bit, width); @@ -4775,8 +4750,6 @@ RTLIL::SigSpec::SigSpec(RTLIL::State bit, int width) RTLIL::SigSpec::SigSpec(const RTLIL::SigBit &bit, int width) { - cover("kernel.rtlil.sigspec.init.bit"); - if (width != 0) { if (bit.wire == NULL) { rep_ = CHUNK; @@ -4797,8 +4770,6 @@ RTLIL::SigSpec::SigSpec(const RTLIL::SigBit &bit, int width) RTLIL::SigSpec::SigSpec(const std::vector &chunks) { - cover("kernel.rtlil.sigspec.init.stdvec_chunks"); - init_empty_bits(); for (const auto &c : chunks) append(c); @@ -4807,8 +4778,6 @@ RTLIL::SigSpec::SigSpec(const std::vector &chunks) RTLIL::SigSpec::SigSpec(const std::vector &bits) { - cover("kernel.rtlil.sigspec.init.stdvec_bits"); - init_empty_bits(); for (const auto &bit : bits) append(bit); @@ -4817,8 +4786,6 @@ RTLIL::SigSpec::SigSpec(const std::vector &bits) RTLIL::SigSpec::SigSpec(const pool &bits) { - cover("kernel.rtlil.sigspec.init.pool_bits"); - init_empty_bits(); for (const auto &bit : bits) append(bit); @@ -4827,8 +4794,6 @@ RTLIL::SigSpec::SigSpec(const pool &bits) RTLIL::SigSpec::SigSpec(const std::set &bits) { - cover("kernel.rtlil.sigspec.init.stdset_bits"); - init_empty_bits(); for (const auto &bit : bits) append(bit); @@ -4837,8 +4802,6 @@ RTLIL::SigSpec::SigSpec(const std::set &bits) RTLIL::SigSpec::SigSpec(bool bit) { - cover("kernel.rtlil.sigspec.init.bool"); - rep_ = CHUNK; new (&chunk_) RTLIL::SigChunk(bit ? RTLIL::S1 : RTLIL::S0); check(); @@ -4874,8 +4837,6 @@ void RTLIL::SigSpec::unpack() if (rep_ == BITS) return; - cover("kernel.rtlil.sigspec.convert.unpack"); - std::vector bits; bits.reserve(chunk_.width); for (int i = 0; i < chunk_.width; i++) @@ -4891,8 +4852,6 @@ void RTLIL::SigSpec::try_repack() if (rep_ != BITS) return; - cover("kernel.rtlil.sigspec.convert.try_repack"); - int bits_size = GetSize(bits_); if (bits_size == 0) return; @@ -4921,8 +4880,6 @@ void RTLIL::SigSpec::try_repack() Hasher::hash_t RTLIL::SigSpec::updhash() const { - cover("kernel.rtlil.sigspec.hash"); - Hasher h; for (auto &c : chunks()) if (c.wire == NULL) { @@ -4943,7 +4900,6 @@ Hasher::hash_t RTLIL::SigSpec::updhash() const void RTLIL::SigSpec::sort() { unpack(); - cover("kernel.rtlil.sigspec.sort"); std::sort(bits_.begin(), bits_.end()); hash_.clear(); try_repack(); @@ -4952,8 +4908,6 @@ void RTLIL::SigSpec::sort() void RTLIL::SigSpec::sort_and_unify() { unpack(); - cover("kernel.rtlil.sigspec.sort_and_unify"); - // A copy of the bits vector is used to prevent duplicating the logic from // SigSpec::SigSpec(std::vector). This incurrs an extra copy but // that isn't showing up as significant in profiles. @@ -5009,8 +4963,6 @@ void RTLIL::SigSpec::replace(const dict &rules) void RTLIL::SigSpec::replace(const dict &rules, RTLIL::SigSpec *other) const { - cover("kernel.rtlil.sigspec.replace_dict"); - log_assert(other != NULL); log_assert(size() == other->size()); @@ -5038,8 +4990,6 @@ void RTLIL::SigSpec::replace(const std::map &rules void RTLIL::SigSpec::replace(const std::map &rules, RTLIL::SigSpec *other) const { - cover("kernel.rtlil.sigspec.replace_map"); - log_assert(other != NULL); log_assert(size() == other->size()); @@ -5073,11 +5023,6 @@ void RTLIL::SigSpec::remove(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other) { - if (other) - cover("kernel.rtlil.sigspec.remove_other"); - else - cover("kernel.rtlil.sigspec.remove"); - unpack(); if (other != NULL) { log_assert(size() == other->size()); @@ -5128,11 +5073,6 @@ void RTLIL::SigSpec::remove(const pool &pattern, RTLIL::SigSpec * void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec *other) { - if (other) - cover("kernel.rtlil.sigspec.remove_other"); - else - cover("kernel.rtlil.sigspec.remove"); - unpack(); if (other != NULL) { @@ -5166,11 +5106,6 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec void RTLIL::SigSpec::remove2(const std::set &pattern, RTLIL::SigSpec *other) { - if (other) - cover("kernel.rtlil.sigspec.remove_other"); - else - cover("kernel.rtlil.sigspec.remove"); - unpack(); if (other != NULL) { @@ -5204,11 +5139,6 @@ void RTLIL::SigSpec::remove2(const std::set &pattern, RTLIL::SigS void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec *other) { - if (other) - cover("kernel.rtlil.sigspec.remove_other"); - else - cover("kernel.rtlil.sigspec.remove"); - unpack(); if (other != NULL) { @@ -5242,11 +5172,6 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec * RTLIL::SigSpec RTLIL::SigSpec::extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other) const { - if (other) - cover("kernel.rtlil.sigspec.extract_other"); - else - cover("kernel.rtlil.sigspec.extract"); - log_assert(other == NULL || size() == other->size()); RTLIL::SigSpec ret; @@ -5280,11 +5205,6 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(const RTLIL::SigSpec &pattern, const RTLI RTLIL::SigSpec RTLIL::SigSpec::extract(const pool &pattern, const RTLIL::SigSpec *other) const { - if (other) - cover("kernel.rtlil.sigspec.extract_other"); - else - cover("kernel.rtlil.sigspec.extract"); - log_assert(other == NULL || size() == other->size()); std::vector bits_match = to_sigbit_vector(); @@ -5310,8 +5230,6 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(const pool &pattern, const void RTLIL::SigSpec::replace(int offset, const RTLIL::SigSpec &with) { - cover("kernel.rtlil.sigspec.replace_pos"); - if (with.size() == 0) return; @@ -5336,8 +5254,6 @@ void RTLIL::SigSpec::remove_const() { if (rep_ == CHUNK) { - cover("kernel.rtlil.sigspec.remove_const.packed"); - if (chunk_.wire == NULL) { chunk_.~SigChunk(); init_empty_bits(); @@ -5346,8 +5262,6 @@ void RTLIL::SigSpec::remove_const() } else { - cover("kernel.rtlil.sigspec.remove_const.unpacked"); - std::vector new_bits; new_bits.reserve(bits_.size()); for (auto &bit : bits_) @@ -5365,8 +5279,6 @@ void RTLIL::SigSpec::remove_const() void RTLIL::SigSpec::remove(int offset, int length) { - cover("kernel.rtlil.sigspec.remove_pos"); - if (length == 0) return; @@ -5389,8 +5301,6 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(int offset, int length) const log_assert(length >= 0); log_assert(offset + length <= size()); - cover("kernel.rtlil.sigspec.extract_pos"); - SigSpec extracted; Chunks cs = chunks(); auto it = cs.begin(); @@ -5444,8 +5354,6 @@ void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) return; } - cover("kernel.rtlil.sigspec.append"); - hash_.clear(); if (rep_ == CHUNK && signal.rep_ == CHUNK && chunk_.wire == signal.chunk_.wire) { if (chunk_.wire == NULL) { @@ -5477,8 +5385,6 @@ void RTLIL::SigSpec::append(const RTLIL::SigBit &bit) } if (rep_ == CHUNK && chunk_.wire == bit.wire) { - cover("kernel.rtlil.sigspec.append_bit.packed"); - if (chunk_.wire == NULL) { chunk_.data.push_back(bit.data); chunk_.width++; @@ -5492,15 +5398,12 @@ void RTLIL::SigSpec::append(const RTLIL::SigBit &bit) unpack(); - cover("kernel.rtlil.sigspec.append_bit.unpacked"); bits_.push_back(bit); check(); } void RTLIL::SigSpec::extend_u0(int width, bool is_signed) { - cover("kernel.rtlil.sigspec.extend_u0"); - if (size() > width) remove(width, size() - width); @@ -5515,8 +5418,6 @@ void RTLIL::SigSpec::extend_u0(int width, bool is_signed) RTLIL::SigSpec RTLIL::SigSpec::repeat(int num) const { - cover("kernel.rtlil.sigspec.repeat"); - RTLIL::SigSpec sig; for (int i = 0; i < num; i++) sig.append(*this); @@ -5528,8 +5429,6 @@ void RTLIL::SigSpec::check(Module *mod) const { if (rep_ == CHUNK) { - cover("kernel.rtlil.sigspec.check.packed"); - log_assert(chunk_.width != 0); if (chunk_.wire == NULL) { log_assert(chunk_.offset == 0); @@ -5543,14 +5442,8 @@ void RTLIL::SigSpec::check(Module *mod) const log_assert(chunk_.wire->module == mod); } } - else if (size() > 64) + else if (size() <= 64) { - cover("kernel.rtlil.sigspec.check.skip"); - } - else - { - cover("kernel.rtlil.sigspec.check.unpacked"); - if (mod != nullptr) { for (const RTLIL::SigBit &bit : bits_) if (bit.wire != nullptr) @@ -5562,8 +5455,6 @@ void RTLIL::SigSpec::check(Module *mod) const bool RTLIL::SigSpec::operator <(const RTLIL::SigSpec &other) const { - cover("kernel.rtlil.sigspec.comp_lt"); - if (this == &other) return false; @@ -5577,14 +5468,11 @@ bool RTLIL::SigSpec::operator <(const RTLIL::SigSpec &other) const ++other_it; } - cover("kernel.rtlil.sigspec.comp_lt.equal"); return false; } bool RTLIL::SigSpec::operator ==(const RTLIL::SigSpec &other) const { - cover("kernel.rtlil.sigspec.comp_eq"); - if (this == &other) return true; @@ -5598,14 +5486,11 @@ bool RTLIL::SigSpec::operator ==(const RTLIL::SigSpec &other) const ++other_it; } - cover("kernel.rtlil.sigspec.comp_eq.equal"); return true; } bool RTLIL::SigSpec::is_wire() const { - cover("kernel.rtlil.sigspec.is_wire"); - Chunks cs = chunks(); auto it = cs.begin(); if (it == cs.end()) @@ -5616,8 +5501,6 @@ bool RTLIL::SigSpec::is_wire() const bool RTLIL::SigSpec::is_chunk() const { - cover("kernel.rtlil.sigspec.is_chunk"); - Chunks cs = chunks(); auto it = cs.begin(); if (it == cs.end()) @@ -5635,8 +5518,6 @@ bool RTLIL::SigSpec::known_driver() const bool RTLIL::SigSpec::is_fully_const() const { - cover("kernel.rtlil.sigspec.is_fully_const"); - for (auto &chunk : chunks()) if (chunk.width > 0 && chunk.wire != NULL) return false; @@ -5645,8 +5526,6 @@ bool RTLIL::SigSpec::is_fully_const() const bool RTLIL::SigSpec::is_fully_zero() const { - cover("kernel.rtlil.sigspec.is_fully_zero"); - for (auto &chunk : chunks()) { if (chunk.width > 0 && chunk.wire != NULL) return false; @@ -5659,8 +5538,6 @@ bool RTLIL::SigSpec::is_fully_zero() const bool RTLIL::SigSpec::is_fully_ones() const { - cover("kernel.rtlil.sigspec.is_fully_ones"); - for (auto &chunk : chunks()) { if (chunk.width > 0 && chunk.wire != NULL) return false; @@ -5673,8 +5550,6 @@ bool RTLIL::SigSpec::is_fully_ones() const bool RTLIL::SigSpec::is_fully_def() const { - cover("kernel.rtlil.sigspec.is_fully_def"); - for (auto &chunk : chunks()) { if (chunk.width > 0 && chunk.wire != NULL) return false; @@ -5687,8 +5562,6 @@ bool RTLIL::SigSpec::is_fully_def() const bool RTLIL::SigSpec::is_fully_undef() const { - cover("kernel.rtlil.sigspec.is_fully_undef"); - for (auto &chunk : chunks()) { if (chunk.width > 0 && chunk.wire != NULL) return false; @@ -5701,8 +5574,6 @@ bool RTLIL::SigSpec::is_fully_undef() const bool RTLIL::SigSpec::has_const() const { - cover("kernel.rtlil.sigspec.has_const"); - for (auto &chunk : chunks()) if (chunk.width > 0 && chunk.wire == NULL) return true; @@ -5711,8 +5582,6 @@ bool RTLIL::SigSpec::has_const() const bool RTLIL::SigSpec::has_const(State state) const { - cover("kernel.rtlil.sigspec.has_const"); - for (auto &chunk : chunks()) if (chunk.width > 0 && chunk.wire == NULL && std::find(chunk.data.begin(), chunk.data.end(), state) != chunk.data.end()) return true; @@ -5722,8 +5591,6 @@ bool RTLIL::SigSpec::has_const(State state) const bool RTLIL::SigSpec::has_marked_bits() const { - cover("kernel.rtlil.sigspec.has_marked_bits"); - for (auto &chunk : chunks()) if (chunk.width > 0 && chunk.wire == NULL) { for (RTLIL::State d : chunk.data) @@ -5735,8 +5602,6 @@ bool RTLIL::SigSpec::has_marked_bits() const bool RTLIL::SigSpec::is_onehot(int *pos) const { - cover("kernel.rtlil.sigspec.is_onehot"); - if (std::optional c = try_as_const()) return c->is_onehot(pos); return false; @@ -5744,8 +5609,6 @@ bool RTLIL::SigSpec::is_onehot(int *pos) const bool RTLIL::SigSpec::as_bool() const { - cover("kernel.rtlil.sigspec.as_bool"); - std::optional c = try_as_const(); log_assert(c.has_value()); return c->as_bool(); @@ -5753,8 +5616,6 @@ bool RTLIL::SigSpec::as_bool() const int RTLIL::SigSpec::as_int(bool is_signed) const { - cover("kernel.rtlil.sigspec.as_int"); - std::optional c = try_as_const(); log_assert(c.has_value()); return c->as_int(is_signed); @@ -5762,8 +5623,6 @@ int RTLIL::SigSpec::as_int(bool is_signed) const bool RTLIL::SigSpec::convertible_to_int(bool is_signed) const { - cover("kernel.rtlil.sigspec.convertible_to_int"); - std::optional c = try_as_const(); if (!c.has_value()) return false; @@ -5772,8 +5631,6 @@ bool RTLIL::SigSpec::convertible_to_int(bool is_signed) const std::optional RTLIL::SigSpec::try_as_int(bool is_signed) const { - cover("kernel.rtlil.sigspec.try_as_int"); - std::optional c = try_as_const(); if (!c.has_value()) return std::nullopt; @@ -5782,8 +5639,6 @@ std::optional RTLIL::SigSpec::try_as_int(bool is_signed) const int RTLIL::SigSpec::as_int_saturating(bool is_signed) const { - cover("kernel.rtlil.sigspec.try_as_int"); - std::optional c = try_as_const(); log_assert(c.has_value()); return c->as_int_saturating(is_signed); @@ -5791,8 +5646,6 @@ int RTLIL::SigSpec::as_int_saturating(bool is_signed) const std::string RTLIL::SigSpec::as_string() const { - cover("kernel.rtlil.sigspec.as_string"); - std::string str; str.reserve(size()); std::vector chunks = *this; @@ -5808,8 +5661,6 @@ std::string RTLIL::SigSpec::as_string() const std::optional RTLIL::SigSpec::try_as_const() const { - cover("kernel.rtlil.sigspec.as_const"); - Chunks cs = chunks(); auto it = cs.begin(); if (it == cs.end()) @@ -5822,8 +5673,6 @@ std::optional RTLIL::SigSpec::try_as_const() const RTLIL::Const RTLIL::SigSpec::as_const() const { - cover("kernel.rtlil.sigspec.as_const"); - std::optional c = try_as_const(); log_assert(c.has_value()); return *c; @@ -5831,8 +5680,6 @@ RTLIL::Const RTLIL::SigSpec::as_const() const RTLIL::Wire *RTLIL::SigSpec::as_wire() const { - cover("kernel.rtlil.sigspec.as_wire"); - Chunks cs = chunks(); auto it = cs.begin(); log_assert(it != cs.end()); @@ -5843,8 +5690,6 @@ RTLIL::Wire *RTLIL::SigSpec::as_wire() const RTLIL::SigChunk RTLIL::SigSpec::as_chunk() const { - cover("kernel.rtlil.sigspec.as_chunk"); - Chunks cs = chunks(); auto it = cs.begin(); log_assert(it != cs.end()); @@ -5855,14 +5700,11 @@ RTLIL::SigChunk RTLIL::SigSpec::as_chunk() const RTLIL::SigBit RTLIL::SigSpec::as_bit() const { - cover("kernel.rtlil.sigspec.as_bit"); return RTLIL::SigBit(*this); } bool RTLIL::SigSpec::match(const char* pattern) const { - cover("kernel.rtlil.sigspec.match"); - int pattern_len = strlen(pattern); log_assert(pattern_len == size()); @@ -5892,8 +5734,6 @@ bool RTLIL::SigSpec::match(const char* pattern) const std::set RTLIL::SigSpec::to_sigbit_set() const { - cover("kernel.rtlil.sigspec.to_sigbit_set"); - std::set sigbits; for (auto &c : chunks()) for (int i = 0; i < c.width; i++) @@ -5903,8 +5743,6 @@ std::set RTLIL::SigSpec::to_sigbit_set() const pool RTLIL::SigSpec::to_sigbit_pool() const { - cover("kernel.rtlil.sigspec.to_sigbit_pool"); - pool sigbits; sigbits.reserve(size()); for (auto &c : chunks()) @@ -5915,8 +5753,6 @@ pool RTLIL::SigSpec::to_sigbit_pool() const std::vector RTLIL::SigSpec::to_sigbit_vector() const { - cover("kernel.rtlil.sigspec.to_sigbit_vector"); - std::vector result; result.reserve(size()); for (SigBit bit : *this) @@ -5926,8 +5762,6 @@ std::vector RTLIL::SigSpec::to_sigbit_vector() const std::map RTLIL::SigSpec::to_sigbit_map(const RTLIL::SigSpec &other) const { - cover("kernel.rtlil.sigspec.to_sigbit_map"); - int this_size = size(); log_assert(this_size == other.size()); @@ -5940,8 +5774,6 @@ std::map RTLIL::SigSpec::to_sigbit_map(const RTLIL dict RTLIL::SigSpec::to_sigbit_dict(const RTLIL::SigSpec &other) const { - cover("kernel.rtlil.sigspec.to_sigbit_dict"); - int this_size = size(); log_assert(this_size == other.size()); @@ -5965,9 +5797,6 @@ static void sigspec_parse_split(std::vector &tokens, const std::str bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str) { - cover("kernel.rtlil.sigspec.parse"); - - std::vector tokens; sigspec_parse_split(tokens, str, ','); @@ -5981,7 +5810,6 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri continue; if (('0' <= netname[0] && netname[0] <= '9') || netname[0] == '\'') { - cover("kernel.rtlil.sigspec.parse.const"); VERILOG_FRONTEND::ConstParser p{Location()}; auto ast = p.const2ast(netname); if (ast == nullptr) @@ -5993,8 +5821,6 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri if (module == NULL) return false; - cover("kernel.rtlil.sigspec.parse.net"); - if (netname[0] != '$' && netname[0] != '\\') netname = "\\" + netname; @@ -6023,13 +5849,11 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri std::vector index_tokens; sigspec_parse_split(index_tokens, indices.substr(1, indices.size()-2), ':'); if (index_tokens.size() == 1) { - cover("kernel.rtlil.sigspec.parse.bit_sel"); int a = atoi(index_tokens.at(0).c_str()); if (a < 0 || a >= wire->width) return false; sig.append(RTLIL::SigSpec(wire, a)); } else { - cover("kernel.rtlil.sigspec.parse.part_sel"); int a = atoi(index_tokens.at(0).c_str()); int b = atoi(index_tokens.at(1).c_str()); if (a > b) { @@ -6054,8 +5878,6 @@ bool RTLIL::SigSpec::parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL if (str.empty() || str[0] != '@') return parse(sig, module, str); - cover("kernel.rtlil.sigspec.parse.sel"); - str = RTLIL::escape_id(str.substr(1)); if (design->selection_vars.count(str) == 0) return false; @@ -6072,13 +5894,11 @@ bool RTLIL::SigSpec::parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL bool RTLIL::SigSpec::parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str) { if (str == "0") { - cover("kernel.rtlil.sigspec.parse.rhs_zeros"); sig = RTLIL::SigSpec(RTLIL::State::S0, lhs.size()); return true; } if (str == "~0") { - cover("kernel.rtlil.sigspec.parse.rhs_ones"); sig = RTLIL::SigSpec(RTLIL::State::S1, lhs.size()); return true; } @@ -6088,7 +5908,6 @@ bool RTLIL::SigSpec::parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, R long int val = strtol(p, &endptr, 10); if (endptr && endptr != p && *endptr == 0) { sig = RTLIL::SigSpec(val, lhs.size()); - cover("kernel.rtlil.sigspec.parse.rhs_dec"); return true; } } diff --git a/kernel/rtlil.h b/kernel/rtlil.h index f841df1ed..e3a5a3bf8 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -223,8 +223,8 @@ struct RTLIL::IdString constexpr inline IdString() : index_(0) { } inline IdString(const char *str) : index_(insert(std::string_view(str))) { } - constexpr inline IdString(const IdString &str) : index_(str.index_) { } - inline IdString(IdString &&str) : index_(str.index_) { str.index_ = 0; } + constexpr IdString(const IdString &str) = default; + IdString(IdString &&str) = default; inline IdString(const std::string &str) : index_(insert(std::string_view(str))) { } inline IdString(std::string_view str) : index_(insert(str)) { } constexpr inline IdString(StaticId id) : index_(static_cast(id)) {} @@ -241,8 +241,6 @@ struct RTLIL::IdString *this = id; } - constexpr inline const IdString &id_string() const { return *this; } - inline const char *c_str() const { if (index_ >= 0) return global_id_storage_.at(index_).buf; @@ -372,7 +370,7 @@ struct RTLIL::IdString return Substrings(global_autoidx_id_storage_.at(index_).prefix, -index_); } - inline bool lt_by_name(const IdString &rhs) const { + inline bool lt_by_name(IdString rhs) const { Substrings lhs_it = substrings(); Substrings rhs_it = rhs.substrings(); std::string_view lhs_substr = lhs_it.first(); @@ -399,12 +397,12 @@ struct RTLIL::IdString } } - inline bool operator<(const IdString &rhs) const { + inline bool operator<(IdString rhs) const { return index_ < rhs.index_; } - inline bool operator==(const IdString &rhs) const { return index_ == rhs.index_; } - inline bool operator!=(const IdString &rhs) const { return index_ != rhs.index_; } + inline bool operator==(IdString rhs) const { return index_ == rhs.index_; } + inline bool operator!=(IdString rhs) const { return index_ != rhs.index_; } // The methods below are just convenience functions for better compatibility with std::string. @@ -528,7 +526,7 @@ struct RTLIL::IdString return (... || in(args)); } - bool in(const IdString &rhs) const { return *this == rhs; } + bool in(IdString rhs) const { return *this == rhs; } bool in(const char *rhs) const { return *this == rhs; } bool in(const std::string &rhs) const { return *this == rhs; } inline bool in(const pool &rhs) const; @@ -646,13 +644,13 @@ private: namespace hashlib { template <> struct hash_ops { - static inline bool cmp(const RTLIL::IdString &a, const RTLIL::IdString &b) { + static inline bool cmp(RTLIL::IdString a, RTLIL::IdString b) { return a == b; } - [[nodiscard]] static inline Hasher hash(const RTLIL::IdString &id) { + [[nodiscard]] static inline Hasher hash(RTLIL::IdString id) { return id.hash_top(); } - [[nodiscard]] static inline Hasher hash_into(const RTLIL::IdString &id, Hasher h) { + [[nodiscard]] static inline Hasher hash_into(RTLIL::IdString id, Hasher h) { return id.hash_into(h); } }; @@ -759,11 +757,11 @@ namespace RTLIL { return str.substr(1); } - static inline std::string unescape_id(const RTLIL::IdString &str) { + static inline std::string unescape_id(RTLIL::IdString str) { return unescape_id(str.str()); } - static inline const char *id2cstr(const RTLIL::IdString &str) { + static inline const char *id2cstr(RTLIL::IdString str) { return log_id(str); } @@ -780,7 +778,7 @@ namespace RTLIL { }; struct sort_by_id_str { - bool operator()(const RTLIL::IdString &a, const RTLIL::IdString &b) const { + bool operator()(RTLIL::IdString a, RTLIL::IdString b) const { return a.lt_by_name(b); } }; @@ -1246,22 +1244,22 @@ struct RTLIL::AttrObject { dict attributes; - bool has_attribute(const RTLIL::IdString &id) const; + bool has_attribute(RTLIL::IdString id) const; - void set_bool_attribute(const RTLIL::IdString &id, bool value=true); - bool get_bool_attribute(const RTLIL::IdString &id) const; + void set_bool_attribute(RTLIL::IdString id, bool value=true); + bool get_bool_attribute(RTLIL::IdString id) const; [[deprecated("Use Module::get_blackbox_attribute() instead.")]] bool get_blackbox_attribute(bool ignore_wb=false) const { return get_bool_attribute(ID::blackbox) || (!ignore_wb && get_bool_attribute(ID::whitebox)); } - void set_string_attribute(const RTLIL::IdString& id, string value); - string get_string_attribute(const RTLIL::IdString &id) const; + void set_string_attribute(RTLIL::IdString id, string value); + string get_string_attribute(RTLIL::IdString id) const; - void set_strpool_attribute(const RTLIL::IdString& id, const pool &data); - void add_strpool_attribute(const RTLIL::IdString& id, const pool &data); - pool get_strpool_attribute(const RTLIL::IdString &id) const; + void set_strpool_attribute(RTLIL::IdString id, const pool &data); + void add_strpool_attribute(RTLIL::IdString id, const pool &data); + pool get_strpool_attribute(RTLIL::IdString id) const; void set_src_attribute(const std::string &src) { set_string_attribute(ID::src, src); @@ -1273,8 +1271,8 @@ struct RTLIL::AttrObject void set_hdlname_attribute(const vector &hierarchy); vector get_hdlname_attribute() const; - void set_intvec_attribute(const RTLIL::IdString& id, const vector &data); - vector get_intvec_attribute(const RTLIL::IdString &id) const; + void set_intvec_attribute(RTLIL::IdString id, const vector &data); + vector get_intvec_attribute(RTLIL::IdString id) const; }; struct RTLIL::NamedObject : public RTLIL::AttrObject @@ -1781,18 +1779,18 @@ struct RTLIL::Selection // checks if the given module exists in the current design and is a // boxed module, warning the user if the current design is not set - bool boxed_module(const RTLIL::IdString &mod_name) const; + bool boxed_module(RTLIL::IdString mod_name) const; // checks if the given module is included in this selection - bool selected_module(const RTLIL::IdString &mod_name) const; + bool selected_module(RTLIL::IdString mod_name) const; // checks if the given module is wholly included in this selection, // i.e. not partially selected - bool selected_whole_module(const RTLIL::IdString &mod_name) const; + bool selected_whole_module(RTLIL::IdString mod_name) const; // checks if the given member from the given module is included in this // selection - bool selected_member(const RTLIL::IdString &mod_name, const RTLIL::IdString &memb_name) const; + bool selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const; // optimizes this selection for the given design by: // - removing non-existent modules and members, any boxed modules and @@ -1862,7 +1860,7 @@ struct RTLIL::Monitor virtual ~Monitor() { } virtual void notify_module_add(RTLIL::Module*) { } virtual void notify_module_del(RTLIL::Module*) { } - virtual void notify_connect(RTLIL::Cell*, const RTLIL::IdString&, const RTLIL::SigSpec&, const RTLIL::SigSpec&) { } + virtual void notify_connect(RTLIL::Cell*, RTLIL::IdString, const RTLIL::SigSpec&, const RTLIL::SigSpec&) { } virtual void notify_connect(RTLIL::Module*, const RTLIL::SigSig&) { } virtual void notify_connect(RTLIL::Module*, const std::vector&) { } virtual void notify_blackout(RTLIL::Module*) { } @@ -1897,11 +1895,11 @@ struct RTLIL::Design ~Design(); RTLIL::ObjRange modules(); - RTLIL::Module *module(const RTLIL::IdString &name); - const RTLIL::Module *module(const RTLIL::IdString &name) const; + RTLIL::Module *module(RTLIL::IdString name); + const RTLIL::Module *module(RTLIL::IdString name) const; RTLIL::Module *top_module() const; - bool has(const RTLIL::IdString &id) const { + bool has(RTLIL::IdString id) const { return modules_.count(id) != 0; } @@ -1928,15 +1926,15 @@ struct RTLIL::Design void optimize(); // checks if the given module is included in the current selection - bool selected_module(const RTLIL::IdString &mod_name) const; + bool selected_module(RTLIL::IdString mod_name) const; // checks if the given module is wholly included in the current // selection, i.e. not partially selected - bool selected_whole_module(const RTLIL::IdString &mod_name) const; + bool selected_whole_module(RTLIL::IdString mod_name) const; // checks if the given member from the given module is included in the // current selection - bool selected_member(const RTLIL::IdString &mod_name, const RTLIL::IdString &memb_name) const; + bool selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const; // checks if the given module is included in the current selection bool selected_module(RTLIL::Module *mod) const; @@ -2068,7 +2066,7 @@ public: virtual ~Module(); virtual RTLIL::IdString derive(RTLIL::Design *design, const dict ¶meters, bool mayfail = false); virtual RTLIL::IdString derive(RTLIL::Design *design, const dict ¶meters, const dict &interfaces, const dict &modports, bool mayfail = false); - virtual size_t count_id(const RTLIL::IdString& id); + virtual size_t count_id(RTLIL::IdString id); virtual void expand_interfaces(RTLIL::Design *design, const dict &local_interfaces); virtual bool reprocess_if_necessary(RTLIL::Design *design); @@ -2120,32 +2118,37 @@ public: return design->selected_member(name, member->name); } - RTLIL::Wire* wire(const RTLIL::IdString &id) { + RTLIL::Wire* wire(RTLIL::IdString id) { auto it = wires_.find(id); return it == wires_.end() ? nullptr : it->second; } - RTLIL::Cell* cell(const RTLIL::IdString &id) { + RTLIL::Cell* cell(RTLIL::IdString id) { auto it = cells_.find(id); return it == cells_.end() ? nullptr : it->second; } - const RTLIL::Wire* wire(const RTLIL::IdString &id) const{ + const RTLIL::Wire* wire(RTLIL::IdString id) const{ auto it = wires_.find(id); return it == wires_.end() ? nullptr : it->second; } - const RTLIL::Cell* cell(const RTLIL::IdString &id) const { + const RTLIL::Cell* cell(RTLIL::IdString id) const { auto it = cells_.find(id); return it == cells_.end() ? nullptr : it->second; } RTLIL::ObjRange wires() { return RTLIL::ObjRange(&wires_, &refcount_wires_); } + int wires_size() const { return wires_.size(); } + RTLIL::Wire* wire_at(int index) const { return wires_.element(index)->second; } RTLIL::ObjRange cells() { return RTLIL::ObjRange(&cells_, &refcount_cells_); } + int cells_size() const { return cells_.size(); } + RTLIL::Cell* cell_at(int index) const { return cells_.element(index)->second; } void add(RTLIL::Binding *binding); // Removing wires is expensive. If you have to remove wires, remove them all at once. void remove(const pool &wires); void remove(RTLIL::Cell *cell); + void remove(RTLIL::Memory *memory); void remove(RTLIL::Process *process); void rename(RTLIL::Wire *wire, RTLIL::IdString new_name); @@ -2490,23 +2493,23 @@ public: dict parameters; // access cell ports - bool hasPort(const RTLIL::IdString &portname) const; - void unsetPort(const RTLIL::IdString &portname); - void setPort(const RTLIL::IdString &portname, RTLIL::SigSpec signal); - const RTLIL::SigSpec &getPort(const RTLIL::IdString &portname) const; + bool hasPort(RTLIL::IdString portname) const; + void unsetPort(RTLIL::IdString portname); + void setPort(RTLIL::IdString portname, RTLIL::SigSpec signal); + const RTLIL::SigSpec &getPort(RTLIL::IdString portname) const; const dict &connections() const; // information about cell ports bool known() const; - bool input(const RTLIL::IdString &portname) const; - bool output(const RTLIL::IdString &portname) const; - PortDir port_dir(const RTLIL::IdString &portname) const; + bool input(RTLIL::IdString portname) const; + bool output(RTLIL::IdString portname) const; + PortDir port_dir(RTLIL::IdString portname) const; // access cell parameters - bool hasParam(const RTLIL::IdString ¶mname) const; - void unsetParam(const RTLIL::IdString ¶mname); - void setParam(const RTLIL::IdString ¶mname, RTLIL::Const value); - const RTLIL::Const &getParam(const RTLIL::IdString ¶mname) const; + bool hasParam(RTLIL::IdString paramname) const; + void unsetParam(RTLIL::IdString paramname); + void setParam(RTLIL::IdString paramname, RTLIL::Const value); + const RTLIL::Const &getParam(RTLIL::IdString paramname) const; void sort(); void check(); diff --git a/kernel/rtlil_bufnorm.cc b/kernel/rtlil_bufnorm.cc index d0561f880..5f74b3380 100644 --- a/kernel/rtlil_bufnorm.cc +++ b/kernel/rtlil_bufnorm.cc @@ -526,7 +526,7 @@ void RTLIL::Module::bufNormalize() pending_deleted_cells.clear(); } -void RTLIL::Cell::unsetPort(const RTLIL::IdString& portname) +void RTLIL::Cell::unsetPort(RTLIL::IdString portname) { RTLIL::SigSpec signal; auto conn_it = connections_.find(portname); @@ -586,7 +586,7 @@ void RTLIL::Cell::unsetPort(const RTLIL::IdString& portname) } } -void RTLIL::Cell::setPort(const RTLIL::IdString& portname, RTLIL::SigSpec signal) +void RTLIL::Cell::setPort(RTLIL::IdString portname, RTLIL::SigSpec signal) { auto r = connections_.insert(portname); auto conn_it = r.first; diff --git a/kernel/scopeinfo.cc b/kernel/scopeinfo.cc index 7ed9ebf33..59dd746b5 100644 --- a/kernel/scopeinfo.cc +++ b/kernel/scopeinfo.cc @@ -97,13 +97,13 @@ static const char *attr_prefix(ScopeinfoAttrs attrs) } } -bool scopeinfo_has_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, const RTLIL::IdString &id) +bool scopeinfo_has_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, RTLIL::IdString id) { log_assert(scopeinfo->type == ID($scopeinfo)); return scopeinfo->has_attribute(attr_prefix(attrs) + RTLIL::unescape_id(id)); } -RTLIL::Const scopeinfo_get_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, const RTLIL::IdString &id) +RTLIL::Const scopeinfo_get_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, RTLIL::IdString id) { log_assert(scopeinfo->type == ID($scopeinfo)); auto found = scopeinfo->attributes.find(attr_prefix(attrs) + RTLIL::unescape_id(id)); diff --git a/kernel/scopeinfo.h b/kernel/scopeinfo.h index 3bc1a8162..a3939b903 100644 --- a/kernel/scopeinfo.h +++ b/kernel/scopeinfo.h @@ -433,10 +433,10 @@ enum class ScopeinfoAttrs { }; // Check whether the flattened module or flattened cell corresponding to a $scopeinfo cell had a specific attribute. -bool scopeinfo_has_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, const RTLIL::IdString &id); +bool scopeinfo_has_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, RTLIL::IdString id); // Get a specific attribute from the flattened module or flattened cell corresponding to a $scopeinfo cell. -RTLIL::Const scopeinfo_get_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, const RTLIL::IdString &id); +RTLIL::Const scopeinfo_get_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, RTLIL::IdString id); // Get all attribute from the flattened module or flattened cell corresponding to a $scopeinfo cell. dict scopeinfo_attributes(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs); diff --git a/kernel/threading.cc b/kernel/threading.cc index 49fddaa7c..dcc044c89 100644 --- a/kernel/threading.cc +++ b/kernel/threading.cc @@ -3,6 +3,20 @@ YOSYS_NAMESPACE_BEGIN +static int init_max_threads() +{ + const char *v = getenv("YOSYS_MAX_THREADS"); + if (v == nullptr) + return INT32_MAX; + return atoi(v); +} + +static int get_max_threads() +{ + static int max_threads = init_max_threads(); + return max_threads; +} + void DeferredLogs::flush() { for (auto &m : logs) @@ -12,10 +26,11 @@ void DeferredLogs::flush() YOSYS_NAMESPACE_PREFIX log("%s", m.text.c_str()); } -int ThreadPool::pool_size(int reserved_cores, int max_threads) +int ThreadPool::pool_size(int reserved_cores, int max_worker_threads) { #ifdef YOSYS_ENABLE_THREADS - int num_threads = std::min(std::thread::hardware_concurrency() - reserved_cores, max_threads); + int available_threads = std::min(std::thread::hardware_concurrency(), get_max_threads()); + int num_threads = std::min(available_threads - reserved_cores, max_worker_threads); return std::max(0, num_threads); #else return 0; diff --git a/kernel/threading.h b/kernel/threading.h index c34abf850..b8cd62f87 100644 --- a/kernel/threading.h +++ b/kernel/threading.h @@ -127,9 +127,9 @@ class ThreadPool public: // Computes the number of worker threads to use. // `reserved_cores` cores are set aside for other threads (e.g. work on the main thread). - // `max_threads` --- don't return more workers than this. + // `max_worker_threads` --- don't return more workers than this. // The result may be 0. - static int pool_size(int reserved_cores, int max_threads); + static int pool_size(int reserved_cores, int max_worker_threads); // Create a pool of threads running the given closure (parameterized by thread number). // `pool_size` must be the result of a `pool_size()` call. diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 2c9b8304d..4264cb772 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -173,7 +173,7 @@ void yosys_banner() log("\n"); log(" /----------------------------------------------------------------------------\\\n"); log(" | yosys -- Yosys Open SYnthesis Suite |\n"); - log(" | Copyright (C) 2012 - 2025 Claire Xenia Wolf |\n"); + log(" | Copyright (C) 2012 - 2026 Claire Xenia Wolf |\n"); log(" | Distributed under an ISC-like license, type \"license\" to see terms |\n"); log(" \\----------------------------------------------------------------------------/\n"); log(" %s\n", yosys_maybe_version()); diff --git a/kernel/yosys.h b/kernel/yosys.h index b455ad496..9f5a16a9c 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -81,6 +81,7 @@ extern std::set yosys_input_files, yosys_output_files; // from kernel/version_*.o (cc source generated from Makefile) extern const char *yosys_version_str; +extern const char *yosys_git_hash_str; const char* yosys_maybe_version(); // from passes/cmds/design.cc diff --git a/kernel/yosys_common.h b/kernel/yosys_common.h index 55e7b71eb..47dae5473 100644 --- a/kernel/yosys_common.h +++ b/kernel/yosys_common.h @@ -299,8 +299,8 @@ RTLIL::IdString new_id_suffix(std::string_view file, int line, std::string_view #define NEW_ID \ YOSYS_NAMESPACE_PREFIX RTLIL::IdString::new_autoidx_with_prefix([](std::string_view func) -> const std::string * { \ - static const std::string *prefix = YOSYS_NAMESPACE_PREFIX create_id_prefix(__FILE__, __LINE__, func); \ - return prefix; \ + static std::unique_ptr prefix(YOSYS_NAMESPACE_PREFIX create_id_prefix(__FILE__, __LINE__, func)); \ + return prefix.get(); \ }(__FUNCTION__)) #define NEW_ID_SUFFIX(suffix) \ YOSYS_NAMESPACE_PREFIX new_id_suffix(__FILE__, __LINE__, __FUNCTION__, suffix) diff --git a/misc/create_vcxsrc.sh b/misc/create_vcxsrc.sh index 228003bad..42a690ce6 100644 --- a/misc/create_vcxsrc.sh +++ b/misc/create_vcxsrc.sh @@ -1,9 +1,8 @@ #!/bin/bash set -ex -vcxsrc="$1-$2" +vcxsrc="$1" yosysver="$2" -gitsha="$3" rm -rf YosysVS-Tpl-v2.zip YosysVS wget https://github.com/YosysHQ/yosys/releases/download/resources/YosysVS-Tpl-v2.zip @@ -33,7 +32,6 @@ popd head -n$n "$vcxsrc"/YosysVS/YosysVS.vcxproj egrep '\.(h|hh|hpp|inc)$' srcfiles.txt | sed 's,.*,,' egrep -v '\.(h|hh|hpp|inc)$' srcfiles.txt | sed 's,.*,,' - echo '' tail -n +$((n+1)) "$vcxsrc"/YosysVS/YosysVS.vcxproj } > "$vcxsrc"/YosysVS/YosysVS.vcxproj.new @@ -48,9 +46,6 @@ mkdir -p "$vcxsrc"/yosys tar -cf - -T srcfiles.txt | tar -xf - -C "$vcxsrc"/yosys cp -r share "$vcxsrc"/ -echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"Yosys" \ - "$yosysver (git sha1 $gitsha, Visual Studio)\"; }" > "$vcxsrc"/yosys/kernel/version.cc - cat > "$vcxsrc"/readme-git.txt << EOT Want to use a git working copy for the yosys source code? Open "Git Bash" in this directory and run: diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc index 14ea9c52a..dc12c92c2 100644 --- a/passes/cmds/Makefile.inc +++ b/passes/cmds/Makefile.inc @@ -5,6 +5,7 @@ endif OBJS += passes/cmds/add.o OBJS += passes/cmds/delete.o OBJS += passes/cmds/design.o +OBJS += passes/cmds/design_equal.o OBJS += passes/cmds/select.o OBJS += passes/cmds/show.o OBJS += passes/cmds/viz.o @@ -27,7 +28,6 @@ OBJS += passes/cmds/logcmd.o OBJS += passes/cmds/tee.o OBJS += passes/cmds/write_file.o OBJS += passes/cmds/connwrappers.o -OBJS += passes/cmds/cover.o OBJS += passes/cmds/trace.o OBJS += passes/cmds/plugin.o OBJS += passes/cmds/check.o diff --git a/passes/cmds/cover.cc b/passes/cmds/cover.cc deleted file mode 100644 index 7f217329c..000000000 --- a/passes/cmds/cover.cc +++ /dev/null @@ -1,163 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2014 Claire Xenia Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/yosys.h" -#include "kernel/log_help.h" -#include - -#ifndef _WIN32 -# include -#else -# include -#endif - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -struct CoverPass : public Pass { - CoverPass() : Pass("cover", "print code coverage counters") { - internal(); - } - bool formatted_help() override { - auto *help = PrettyHelp::get_current(); - help->set_group("passes/status"); - return false; - } - void help() override - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" cover [options] [pattern]\n"); - log("\n"); - log("Print the code coverage counters collected using the cover() macro in the Yosys\n"); - log("C++ code. This is useful to figure out what parts of Yosys are utilized by a\n"); - log("test bench.\n"); - log("\n"); - log(" -q\n"); - log(" Do not print output to the normal destination (console and/or log file)\n"); - log("\n"); - log(" -o file\n"); - log(" Write output to this file, truncate if exists.\n"); - log("\n"); - log(" -a file\n"); - log(" Write output to this file, append if exists.\n"); - log("\n"); - log(" -d dir\n"); - log(" Write output to a newly created file in the specified directory.\n"); - log("\n"); - log("When one or more pattern (shell wildcards) are specified, then only counters\n"); - log("matching at least one pattern are printed.\n"); - log("\n"); - log("\n"); - log("It is also possible to instruct Yosys to print the coverage counters on program\n"); - log("exit to a file using environment variables:\n"); - log("\n"); - log(" YOSYS_COVER_DIR=\"{dir-name}\" yosys {args}\n"); - log("\n"); - log(" This will create a file (with an auto-generated name) in this\n"); - log(" directory and write the coverage counters to it.\n"); - log("\n"); - log(" YOSYS_COVER_FILE=\"{file-name}\" yosys {args}\n"); - log("\n"); - log(" This will append the coverage counters to the specified file.\n"); - log("\n"); - log("\n"); - log("Hint: Use the following AWK command to consolidate Yosys coverage files:\n"); - log("\n"); - log(" gawk '{ p[$3] = $1; c[$3] += $2; } END { for (i in p)\n"); - log(" printf \"%%-60s %%10d %%s\\n\", p[i], c[i], i; }' {files} | sort -k3\n"); - log("\n"); - log("\n"); - log("Coverage counters are only available in Yosys for Linux.\n"); - log("\n"); - } - void execute(std::vector args, RTLIL::Design *design) override - { - std::vector out_files; - std::vector patterns; - bool do_log = true; - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - if (args[argidx] == "-q") { - do_log = false; - continue; - } - if ((args[argidx] == "-o" || args[argidx] == "-a" || args[argidx] == "-d") && argidx+1 < args.size()) { - const char *open_mode = args[argidx] == "-a" ? "a+" : "w"; - const std::string &filename = args[++argidx]; - FILE *f = nullptr; - if (args[argidx-1] == "-d") { - #if defined(_WIN32) || defined(__wasm) - log_cmd_error("The 'cover -d' option is not supported on this platform.\n"); - #else - char filename_buffer[4096]; - snprintf(filename_buffer, 4096, "%s/yosys_cover_%d_XXXXXX.txt", filename.c_str(), getpid()); - f = fdopen(mkstemps(filename_buffer, 4), "w"); - #endif - } else { - 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%s.\n", args[argidx-1] == "-d" ? "in directory " : "", args[argidx]); - } - out_files.push_back(f); - continue; - } - break; - } - while (argidx < args.size() && args[argidx].compare(0, 1, "-") != 0) - patterns.push_back(args[argidx++]); - extra_args(args, argidx, design); - - if (do_log) { - log_header(design, "Printing code coverage counters.\n"); - log("\n"); - } - -#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__)) - for (auto &it : get_coverage_data()) { - if (!patterns.empty()) { - for (auto &p : patterns) - if (patmatch(p.c_str(), it.first.c_str())) - goto pattern_match; - continue; - } - pattern_match: - for (auto f : out_files) - fprintf(f, "%-60s %10d %s\n", it.second.first.c_str(), it.second.second, it.first.c_str()); - if (do_log) - log("%-60s %10d %s\n", it.second.first, it.second.second, it.first); - } -#else - for (auto f : out_files) - fclose(f); - - log_cmd_error("This version of Yosys was not built with support for code coverage counters.\n"); -#endif - - for (auto f : out_files) - fclose(f); - } -} CoverPass; - -PRIVATE_NAMESPACE_END diff --git a/passes/cmds/design_equal.cc b/passes/cmds/design_equal.cc new file mode 100644 index 000000000..a949db9ff --- /dev/null +++ b/passes/cmds/design_equal.cc @@ -0,0 +1,352 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Claire Xenia Wolf + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/rtlil.h" + +YOSYS_NAMESPACE_BEGIN + +class ModuleComparator +{ + RTLIL::Module *mod_a; + RTLIL::Module *mod_b; + +public: + ModuleComparator(RTLIL::Module *mod_a, RTLIL::Module *mod_b) : mod_a(mod_a), mod_b(mod_b) {} + + bool compare_sigbit(const RTLIL::SigBit &a, const RTLIL::SigBit &b) + { + if (a.wire == nullptr && b.wire == nullptr) + return a.data == b.data; + if (a.wire != nullptr && b.wire != nullptr) + return a.wire->name == b.wire->name && a.offset == b.offset; + return false; + } + + bool compare_sigspec(const RTLIL::SigSpec &a, const RTLIL::SigSpec &b) + { + if (a.size() != b.size()) return false; + auto it_a = a.begin(), it_b = b.begin(); + for (; it_a != a.end(); ++it_a, ++it_b) { + if (!compare_sigbit(*it_a, *it_b)) return false; + } + return true; + } + + std::string compare_attributes(const RTLIL::AttrObject *a, const RTLIL::AttrObject *b) + { + for (const auto &it : a->attributes) { + if (b->attributes.count(it.first) == 0) + return "missing attribute " + std::string(log_id(it.first)) + " in second design"; + if (it.second != b->attributes.at(it.first)) + return "attribute " + std::string(log_id(it.first)) + " mismatch: " + log_const(it.second) + " != " + log_const(b->attributes.at(it.first)); + } + for (const auto &it : b->attributes) + if (a->attributes.count(it.first) == 0) + return "missing attribute " + std::string(log_id(it.first)) + " in first design"; + return ""; + } + + std::string compare_wires(const RTLIL::Wire *a, const RTLIL::Wire *b) + { + if (a->name != b->name) + return "name mismatch: " + std::string(log_id(a->name)) + " != " + log_id(b->name); + if (a->width != b->width) + return "width mismatch: " + std::to_string(a->width) + " != " + std::to_string(b->width); + if (a->start_offset != b->start_offset) + return "start_offset mismatch: " + std::to_string(a->start_offset) + " != " + std::to_string(b->start_offset); + if (a->port_id != b->port_id) + return "port_id mismatch: " + std::to_string(a->port_id) + " != " + std::to_string(b->port_id); + if (a->port_input != b->port_input) + return "port_input mismatch: " + std::to_string(a->port_input) + " != " + std::to_string(b->port_input); + if (a->port_output != b->port_output) + return "port_output mismatch: " + std::to_string(a->port_output) + " != " + std::to_string(b->port_output); + if (a->upto != b->upto) + return "upto mismatch: " + std::to_string(a->upto) + " != " + std::to_string(b->upto); + if (a->is_signed != b->is_signed) + return "is_signed mismatch: " + std::to_string(a->is_signed) + " != " + std::to_string(b->is_signed); + if (std::string mismatch = compare_attributes(a, b); !mismatch.empty()) + return mismatch; + return ""; + } + + void check_wires() + { + for (const auto &it : mod_a->wires_) { + if (mod_b->wires_.count(it.first) == 0) + log_error("Module %s missing wire %s in second design.\n", log_id(mod_a->name), log_id(it.first)); + if (std::string mismatch = compare_wires(it.second, mod_b->wires_.at(it.first)); !mismatch.empty()) + log_error("Module %s wire %s %s.\n", log_id(mod_a->name), log_id(it.first), mismatch); + } + for (const auto &it : mod_b->wires_) + if (mod_a->wires_.count(it.first) == 0) + log_error("Module %s missing wire %s in first design.\n", log_id(mod_b->name), log_id(it.first)); + } + + std::string compare_memories(const RTLIL::Memory *a, const RTLIL::Memory *b) + { + if (a->name != b->name) + return "name mismatch: " + std::string(log_id(a->name)) + " != " + log_id(b->name); + if (a->width != b->width) + return "width mismatch: " + std::to_string(a->width) + " != " + std::to_string(b->width); + if (a->start_offset != b->start_offset) + return "start_offset mismatch: " + std::to_string(a->start_offset) + " != " + std::to_string(b->start_offset); + if (a->size != b->size) + return "size mismatch: " + std::to_string(a->size) + " != " + std::to_string(b->size); + if (std::string mismatch = compare_attributes(a, b); !mismatch.empty()) + return mismatch; + return ""; + } + + std::string compare_cells(const RTLIL::Cell *a, const RTLIL::Cell *b) + { + if (a->name != b->name) + return "name mismatch: " + std::string(log_id(a->name)) + " != " + log_id(b->name); + if (a->type != b->type) + return "type mismatch: " + std::string(log_id(a->type)) + " != " + log_id(b->type); + if (std::string mismatch = compare_attributes(a, b); !mismatch.empty()) + return mismatch; + + for (const auto &it : a->parameters) { + if (b->parameters.count(it.first) == 0) + return "parameter mismatch: missing parameter " + std::string(log_id(it.first)) + " in second design"; + if (it.second != b->parameters.at(it.first)) + return "parameter mismatch: " + std::string(log_id(it.first)) + " mismatch: " + log_const(it.second) + " != " + log_const(b->parameters.at(it.first)); + } + for (const auto &it : b->parameters) + if (a->parameters.count(it.first) == 0) + return "parameter mismatch: missing parameter " + std::string(log_id(it.first)) + " in first design"; + + for (const auto &it : a->connections()) { + if (b->connections().count(it.first) == 0) + return "connection mismatch: missing connection " + std::string(log_id(it.first)) + " in second design"; + if (!compare_sigspec(it.second, b->connections().at(it.first))) + return "connection " + std::string(log_id(it.first)) + " mismatch: " + log_signal(it.second) + " != " + log_signal(b->connections().at(it.first)); + } + for (const auto &it : b->connections()) + if (a->connections().count(it.first) == 0) + return "connection mismatch: missing connection " + std::string(log_id(it.first)) + " in first design"; + + return ""; + } + + void check_cells() + { + for (const auto &it : mod_a->cells_) { + if (mod_b->cells_.count(it.first) == 0) + log_error("Module %s missing cell %s in second design.\n", log_id(mod_a->name), log_id(it.first)); + if (std::string mismatch = compare_cells(it.second, mod_b->cells_.at(it.first)); !mismatch.empty()) + log_error("Module %s cell %s %s.\n", log_id(mod_a->name), log_id(it.first), mismatch); + } + for (const auto &it : mod_b->cells_) + if (mod_a->cells_.count(it.first) == 0) + log_error("Module %s missing cell %s in first design.\n", log_id(mod_b->name), log_id(it.first)); + } + + void check_memories() + { + for (const auto &it : mod_a->memories) { + if (mod_b->memories.count(it.first) == 0) + log_error("Module %s missing memory %s in second design.\n", log_id(mod_a->name), log_id(it.first)); + if (std::string mismatch = compare_memories(it.second, mod_b->memories.at(it.first)); !mismatch.empty()) + log_error("Module %s memory %s %s.\n", log_id(mod_a->name), log_id(it.first), mismatch); + } + for (const auto &it : mod_b->memories) + if (mod_a->memories.count(it.first) == 0) + log_error("Module %s missing memory %s in first design.\n", log_id(mod_b->name), log_id(it.first)); + } + + std::string compare_case_rules(const RTLIL::CaseRule *a, const RTLIL::CaseRule *b) + { + if (std::string mismatch = compare_attributes(a, b); !mismatch.empty()) return mismatch; + + if (a->compare.size() != b->compare.size()) + return "compare size mismatch: " + std::to_string(a->compare.size()) + " != " + std::to_string(b->compare.size()); + for (size_t i = 0; i < a->compare.size(); i++) + if (!compare_sigspec(a->compare[i], b->compare[i])) + return "compare " + std::to_string(i) + " mismatch: " + log_signal(a->compare[i]) + " != " + log_signal(b->compare[i]); + + if (a->actions.size() != b->actions.size()) + return "actions size mismatch: " + std::to_string(a->actions.size()) + " != " + std::to_string(b->actions.size()); + for (size_t i = 0; i < a->actions.size(); i++) { + if (!compare_sigspec(a->actions[i].first, b->actions[i].first)) + return "action " + std::to_string(i) + " first mismatch: " + log_signal(a->actions[i].first) + " != " + log_signal(b->actions[i].first); + if (!compare_sigspec(a->actions[i].second, b->actions[i].second)) + return "action " + std::to_string(i) + " second mismatch: " + log_signal(a->actions[i].second) + " != " + log_signal(b->actions[i].second); + } + + if (a->switches.size() != b->switches.size()) + return "switches size mismatch: " + std::to_string(a->switches.size()) + " != " + std::to_string(b->switches.size()); + for (size_t i = 0; i < a->switches.size(); i++) + if (std::string mismatch = compare_switch_rules(a->switches[i], b->switches[i]); !mismatch.empty()) + return "switch " + std::to_string(i) + " " + mismatch; + + return ""; + } + + std::string compare_switch_rules(const RTLIL::SwitchRule *a, const RTLIL::SwitchRule *b) + { + if (std::string mismatch = compare_attributes(a, b); !mismatch.empty()) + return mismatch; + if (!compare_sigspec(a->signal, b->signal)) + return "signal mismatch: " + log_signal(a->signal) + " != " + log_signal(b->signal); + + if (a->cases.size() != b->cases.size()) + return "cases size mismatch: " + std::to_string(a->cases.size()) + " != " + std::to_string(b->cases.size()); + for (size_t i = 0; i < a->cases.size(); i++) + if (std::string mismatch = compare_case_rules(a->cases[i], b->cases[i]); !mismatch.empty()) + return "case " + std::to_string(i) + " " + mismatch; + + return ""; + } + + std::string compare_sync_rules(const RTLIL::SyncRule *a, const RTLIL::SyncRule *b) + { + if (a->type != b->type) + return "type mismatch: " + std::to_string(a->type) + " != " + std::to_string(b->type); + if (!compare_sigspec(a->signal, b->signal)) + return "signal mismatch: " + log_signal(a->signal) + " != " + log_signal(b->signal); + if (a->actions.size() != b->actions.size()) + return "actions size mismatch: " + std::to_string(a->actions.size()) + " != " + std::to_string(b->actions.size()); + for (size_t i = 0; i < a->actions.size(); i++) { + if (!compare_sigspec(a->actions[i].first, b->actions[i].first)) + return "action " + std::to_string(i) + " first mismatch: " + log_signal(a->actions[i].first) + " != " + log_signal(b->actions[i].first); + if (!compare_sigspec(a->actions[i].second, b->actions[i].second)) + return "action " + std::to_string(i) + " second mismatch: " + log_signal(a->actions[i].second) + " != " + log_signal(b->actions[i].second); + } + if (a->mem_write_actions.size() != b->mem_write_actions.size()) + return "mem_write_actions size mismatch: " + std::to_string(a->mem_write_actions.size()) + " != " + std::to_string(b->mem_write_actions.size()); + for (size_t i = 0; i < a->mem_write_actions.size(); i++) { + const auto &ma = a->mem_write_actions[i]; + const auto &mb = b->mem_write_actions[i]; + if (ma.memid != mb.memid) + return "mem_write_actions " + std::to_string(i) + " memid mismatch: " + log_id(ma.memid) + " != " + log_id(mb.memid); + if (!compare_sigspec(ma.address, mb.address)) + return "mem_write_actions " + std::to_string(i) + " address mismatch: " + log_signal(ma.address) + " != " + log_signal(mb.address); + if (!compare_sigspec(ma.data, mb.data)) + return "mem_write_actions " + std::to_string(i) + " data mismatch: " + log_signal(ma.data) + " != " + log_signal(mb.data); + if (!compare_sigspec(ma.enable, mb.enable)) + return "mem_write_actions " + std::to_string(i) + " enable mismatch: " + log_signal(ma.enable) + " != " + log_signal(mb.enable); + if (ma.priority_mask != mb.priority_mask) + return "mem_write_actions " + std::to_string(i) + " priority_mask mismatch: " + log_const(ma.priority_mask) + " != " + log_const(mb.priority_mask); + if (std::string mismatch = compare_attributes(&ma, &mb); !mismatch.empty()) + return "mem_write_actions " + std::to_string(i) + " " + mismatch; + } + return ""; + } + + std::string compare_processes(const RTLIL::Process *a, const RTLIL::Process *b) + { + if (a->name != b->name) return "name mismatch: " + std::string(log_id(a->name)) + " != " + log_id(b->name); + if (std::string mismatch = compare_attributes(a, b); !mismatch.empty()) + return mismatch; + if (std::string mismatch = compare_case_rules(&a->root_case, &b->root_case); !mismatch.empty()) + return "case rule " + mismatch; + if (a->syncs.size() != b->syncs.size()) + return "sync count mismatch: " + std::to_string(a->syncs.size()) + " != " + std::to_string(b->syncs.size()); + for (size_t i = 0; i < a->syncs.size(); i++) + if (std::string mismatch = compare_sync_rules(a->syncs[i], b->syncs[i]); !mismatch.empty()) + return "sync " + std::to_string(i) + " " + mismatch; + return ""; + } + + void check_processes() + { + for (auto &it : mod_a->processes) { + if (mod_b->processes.count(it.first) == 0) + log_error("Module %s missing process %s in second design.\n", log_id(mod_a->name), log_id(it.first)); + if (std::string mismatch = compare_processes(it.second, mod_b->processes.at(it.first)); !mismatch.empty()) + log_error("Module %s process %s %s.\n", log_id(mod_a->name), log_id(it.first), mismatch.c_str()); + } + for (auto &it : mod_b->processes) + if (mod_a->processes.count(it.first) == 0) + log_error("Module %s missing process %s in first design.\n", log_id(mod_b->name), log_id(it.first)); + } + + void check_connections() + { + const auto &conns_a = mod_a->connections(); + const auto &conns_b = mod_b->connections(); + if (conns_a.size() != conns_b.size()) { + log_error("Module %s connection count differs: %zu != %zu\n", log_id(mod_a->name), conns_a.size(), conns_b.size()); + } else { + for (size_t i = 0; i < conns_a.size(); i++) { + if (!compare_sigspec(conns_a[i].first, conns_b[i].first)) + log_error("Module %s connection %zu LHS %s != %s.\n", log_id(mod_a->name), i, log_signal(conns_a[i].first), log_signal(conns_b[i].first)); + if (!compare_sigspec(conns_a[i].second, conns_b[i].second)) + log_error("Module %s connection %zu RHS %s != %s.\n", log_id(mod_a->name), i, log_signal(conns_a[i].second), log_signal(conns_b[i].second)); + } + } + } + + void check() + { + if (mod_a->name != mod_b->name) + log_error("Modules have different names: %s != %s\n", log_id(mod_a->name), log_id(mod_b->name)); + if (std::string mismatch = compare_attributes(mod_a, mod_b); !mismatch.empty()) + log_error("Module %s %s.\n", log_id(mod_a->name), mismatch); + check_wires(); + check_cells(); + check_memories(); + check_connections(); + check_processes(); + } +}; + +struct DesignEqualPass : public Pass { + DesignEqualPass() : Pass("design_equal", "check if two designs are the same") { } + void help() override + { + log("\n"); + log(" design_equal \n"); + log("\n"); + log("Compare the current design with the design previously saved under the given\n"); + log("name. Abort with an error if the designs are different.\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) override + { + if (args.size() != 2) + log_cmd_error("Missing argument.\n"); + + std::string check_name = args[1]; + if (saved_designs.count(check_name) == 0) + log_cmd_error("No saved design '%s' found!\n", check_name.c_str()); + + RTLIL::Design *other = saved_designs.at(check_name); + + for (auto &it : design->modules_) { + RTLIL::Module *mod = it.second; + if (!other->has(mod->name)) + log_error("Second design missing module %s.\n", log_id(mod->name)); + + ModuleComparator cmp(mod, other->module(mod->name)); + cmp.check(); + } + for (auto &it : other->modules_) { + RTLIL::Module *mod = it.second; + if (!design->has(mod->name)) + log_error("First design missing module %s.\n", log_id(mod->name)); + } + + log("Designs are identical.\n"); + } +} DesignEqualPass; + +YOSYS_NAMESPACE_END diff --git a/passes/cmds/example_dt.cc b/passes/cmds/example_dt.cc index 7d1c42a79..b10f50502 100644 --- a/passes/cmds/example_dt.cc +++ b/passes/cmds/example_dt.cc @@ -77,7 +77,7 @@ struct ExampleDtPass : public Pass auto enqueue = [&](DriveSpec const &spec) { int index = queue(spec); if (index == GetSize(graph_nodes)) - graph_nodes.emplace_back(compute_graph.add(ID($pending).id_string(), index).index()); + graph_nodes.emplace_back(compute_graph.add(ID($pending), index).index()); //if (index >= GetSize(graph_nodes)) return compute_graph[graph_nodes[index]]; }; diff --git a/passes/cmds/icell_liberty.cc b/passes/cmds/icell_liberty.cc index d49cd360a..a928e5d58 100644 --- a/passes/cmds/icell_liberty.cc +++ b/passes/cmds/icell_liberty.cc @@ -163,7 +163,6 @@ struct IcellLiberty : Pass { log_header(d, "Executing ICELL_LIBERTY pass.\n"); size_t argidx; - IdString naming_attr; std::string liberty_filename; auto liberty_file = std::make_unique(); diff --git a/passes/cmds/printattrs.cc b/passes/cmds/printattrs.cc index e4e78b0ea..6a1fab072 100644 --- a/passes/cmds/printattrs.cc +++ b/passes/cmds/printattrs.cc @@ -45,7 +45,7 @@ struct PrintAttrsPass : public Pass { return stringf("%*s", indent, ""); } - static void log_const(const RTLIL::IdString &s, const RTLIL::Const &x, const unsigned int indent) { + static void log_const(RTLIL::IdString s, const RTLIL::Const &x, const unsigned int indent) { if (x.flags & RTLIL::CONST_FLAG_STRING) log("%s(* %s=\"%s\" *)\n", get_indent_str(indent), log_id(s), x.decode_string()); else if (x.flags == RTLIL::CONST_FLAG_NONE || x.flags == RTLIL::CONST_FLAG_SIGNED) diff --git a/passes/cmds/sdc/sdc.cc b/passes/cmds/sdc/sdc.cc index fad001e50..635aad016 100644 --- a/passes/cmds/sdc/sdc.cc +++ b/passes/cmds/sdc/sdc.cc @@ -165,7 +165,12 @@ struct SdcObjects { if (!top) log_error("Top module couldn't be determined. Check 'top' attribute usage"); for (auto port : top->ports) { - design_ports.push_back(std::make_pair(port.str().substr(1), top->wire(port))); + RTLIL::Wire *wire = top->wire(port); + if (!wire) { + // This should not be possible. See https://github.com/YosysHQ/yosys/pull/5594#issue-3791198573 + log_error("Port %s doesn't exist", log_id(port)); + } + design_ports.push_back(std::make_pair(port.str().substr(1), wire)); } std::list hierarchy{}; sniff_module(hierarchy, top); diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc index 6da15c19a..0df47664f 100644 --- a/passes/cmds/select.cc +++ b/passes/cmds/select.cc @@ -570,7 +570,7 @@ static void select_op_expand(RTLIL::Design *design, const std::string &arg, char ct.setup(design); if (pos < int(arg.size()) && arg[pos] == '*') { - levels = 1000000; + levels = 1'000'000; pos++; } else if (pos < int(arg.size()) && '0' <= arg[pos] && arg[pos] <= '9') { diff --git a/passes/cmds/trace.cc b/passes/cmds/trace.cc index 39ed8e60e..df7b665d5 100644 --- a/passes/cmds/trace.cc +++ b/passes/cmds/trace.cc @@ -36,7 +36,7 @@ struct TraceMonitor : public RTLIL::Monitor log("#TRACE# Module delete: %s\n", log_id(module)); } - void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, const RTLIL::SigSpec &sig) override + void notify_connect(RTLIL::Cell *cell, RTLIL::IdString port, const RTLIL::SigSpec &old_sig, const RTLIL::SigSpec &sig) override { log("#TRACE# Cell connect: %s.%s.%s = %s (was: %s)\n", log_id(cell->module), log_id(cell), log_id(port), log_signal(sig), log_signal(old_sig)); } diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 86d96ea7a..ffe678d2f 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -297,8 +297,6 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ log_debug("\n"); } - cover_list("opt.opt_expr.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell->type.str()); - module->remove(cell); did_something = true; return true; @@ -520,7 +518,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons for (auto cell : cells.sorted) { -#define ACTION_DO(_p_, _s_) do { cover("opt.opt_expr.action_" S__LINE__); replace_cell(assign_map, module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0) +#define ACTION_DO(_p_, _s_) do { replace_cell(assign_map, module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0) #define ACTION_DO_Y(_v_) ACTION_DO(ID::Y, RTLIL::SigSpec(RTLIL::State::S ## _v_)) bool detect_const_and = false; @@ -567,19 +565,16 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } if (detect_const_and && (found_zero || found_inv || (found_undef && consume_x))) { - cover("opt.opt_expr.const_and"); replace_cell(assign_map, module, cell, "const_and", ID::Y, RTLIL::State::S0); goto next_cell; } if (detect_const_or && (found_one || found_inv || (found_undef && consume_x))) { - cover("opt.opt_expr.const_or"); replace_cell(assign_map, module, cell, "const_or", ID::Y, RTLIL::State::S1); goto next_cell; } if (non_const_input != State::Sm && !found_undef) { - cover("opt.opt_expr.and_or_buffer"); replace_cell(assign_map, module, cell, "and_or_buffer", ID::Y, non_const_input); goto next_cell; } @@ -591,12 +586,10 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons SigBit sig_b = assign_map(cell->getPort(ID::B)); if (!keepdc && (sig_a == sig_b || sig_a == State::Sx || sig_a == State::Sz || sig_b == State::Sx || sig_b == State::Sz)) { if (cell->type.in(ID($xor), ID($_XOR_))) { - cover("opt.opt_expr.const_xor"); replace_cell(assign_map, module, cell, "const_xor", ID::Y, RTLIL::State::S0); goto next_cell; } if (cell->type.in(ID($xnor), ID($_XNOR_))) { - cover("opt.opt_expr.const_xnor"); // For consistency since simplemap does $xnor -> $_XOR_ + $_NOT_ int width = GetSize(cell->getPort(ID::Y)); replace_cell(assign_map, module, cell, "const_xnor", ID::Y, SigSpec(RTLIL::State::S1, width)); @@ -609,7 +602,6 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons std::swap(sig_a, sig_b); if (sig_b == State::S0 || sig_b == State::S1) { if (cell->type.in(ID($xor), ID($_XOR_))) { - cover("opt.opt_expr.xor_buffer"); SigSpec sig_y; if (cell->type == ID($xor)) sig_y = (sig_b == State::S1 ? module->Not(NEW_ID, sig_a).as_bit() : sig_a); @@ -620,7 +612,6 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons goto next_cell; } if (cell->type.in(ID($xnor), ID($_XNOR_))) { - cover("opt.opt_expr.xnor_buffer"); SigSpec sig_y; if (cell->type == ID($xnor)) { sig_y = (sig_b == State::S1 ? sig_a : module->Not(NEW_ID, sig_a).as_bit()); @@ -641,13 +632,11 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons GetSize(cell->getPort(ID::A)) == 1 && GetSize(cell->getPort(ID::Y)) == 1) { if (cell->type == ID($reduce_xnor)) { - cover("opt.opt_expr.reduce_xnor_not"); log_debug("Replacing %s cell `%s' in module `%s' with $not cell.\n", log_id(cell->type), log_id(cell->name), log_id(module)); cell->type = ID($not); did_something = true; } else { - cover("opt.opt_expr.unary_buffer"); replace_cell(assign_map, module, cell, "unary_buffer", ID::Y, cell->getPort(ID::A)); } goto next_cell; @@ -663,7 +652,6 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (a_fully_const != b_fully_const) { - cover("opt.opt_expr.bitwise_logic_one_const"); log_debug("Replacing %s cell `%s' in module `%s' having one fully constant input\n", log_id(cell->type), log_id(cell->name), log_id(module)); RTLIL::SigSpec sig_y = assign_map(cell->getPort(ID::Y)); @@ -815,7 +803,6 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons new_sig_a.append(neutral_bit); if (GetSize(new_sig_a) < GetSize(sig_a)) { - cover_list("opt.opt_expr.fine.neutral_A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_and", "$reduce_bool", cell->type.str()); log_debug("Replacing port A of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_sig_a)); cell->setPort(ID::A, new_sig_a); @@ -838,7 +825,6 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons new_sig_b.append(neutral_bit); if (GetSize(new_sig_b) < GetSize(sig_b)) { - cover_list("opt.opt_expr.fine.neutral_B", "$logic_and", "$logic_or", cell->type.str()); log_debug("Replacing port B of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_sig_b)); cell->setPort(ID::B, new_sig_b); @@ -864,7 +850,6 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) { - cover("opt.opt_expr.fine.$reduce_and"); log_debug("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a)); cell->setPort(ID::A, sig_a = new_a); @@ -890,7 +875,6 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) { - cover_list("opt.opt_expr.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell->type.str()); log_debug("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a)); cell->setPort(ID::A, sig_a = new_a); @@ -916,7 +900,6 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } if (new_b != RTLIL::State::Sm && RTLIL::SigSpec(new_b) != sig_b) { - cover_list("opt.opt_expr.fine.B", "$logic_and", "$logic_or", cell->type.str()); log_debug("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_b)); cell->setPort(ID::B, sig_b = new_b); @@ -951,7 +934,6 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons break; } if (i > 0) { - cover_list("opt.opt_expr.fine", "$add", "$sub", cell->type.str()); log_debug("Stripping %d LSB bits of %s cell %s in module %s.\n", i, log_id(cell->type), log_id(cell), log_id(module)); SigSpec new_a = sig_a.extract_end(i); SigSpec new_b = sig_b.extract_end(i); @@ -1008,7 +990,6 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons break; } if (i > 0) { - cover("opt.opt_expr.fine.$alu"); log_debug("Stripping %d LSB bits of %s cell %s in module %s.\n", i, log_id(cell->type), log_id(cell), log_id(module)); SigSpec new_a = sig_a.extract_end(i); SigSpec new_b = sig_b.extract_end(i); @@ -1047,8 +1028,6 @@ skip_fine_alu: if (0) { found_the_x_bit: - cover_list("opt.opt_expr.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", - "$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$divfloor", "$modfloor", "$pow", cell->type.str()); if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($lt), ID($le), ID($ge), ID($gt))) replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::State::Sx); else @@ -1070,7 +1049,6 @@ skip_fine_alu: } if (width < GetSize(sig_a)) { - cover_list("opt.opt_expr.trim", "$shiftx", "$shift", cell->type.str()); sig_a.remove(width, GetSize(sig_a)-width); cell->setPort(ID::A, sig_a); cell->setParam(ID::A_WIDTH, width); @@ -1081,13 +1059,11 @@ skip_fine_alu: if (cell->type.in(ID($_NOT_), ID($not), ID($logic_not)) && GetSize(cell->getPort(ID::Y)) == 1 && invert_map.count(assign_map(cell->getPort(ID::A))) != 0) { - cover_list("opt.opt_expr.invert.double", "$_NOT_", "$not", "$logic_not", cell->type.str()); replace_cell(assign_map, module, cell, "double_invert", ID::Y, invert_map.at(assign_map(cell->getPort(ID::A)))); goto next_cell; } if (cell->type.in(ID($_MUX_), ID($mux)) && invert_map.count(assign_map(cell->getPort(ID::S))) != 0) { - cover_list("opt.opt_expr.invert.muxsel", "$_MUX_", "$mux", cell->type.str()); log_debug("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell->type), log_id(cell), log_id(module)); RTLIL::SigSpec tmp = cell->getPort(ID::A); cell->setPort(ID::A, cell->getPort(ID::B)); @@ -1170,7 +1146,6 @@ skip_fine_alu: if (input.match(" 1")) ACTION_DO(ID::Y, input.extract(1, 1)); if (input.match("01 ")) ACTION_DO(ID::Y, input.extract(0, 1)); if (input.match("10 ")) { - cover("opt.opt_expr.mux_to_inv"); cell->type = ID($_NOT_); cell->setPort(ID::A, input.extract(0, 1)); cell->unsetPort(ID::B); @@ -1197,7 +1172,6 @@ skip_fine_alu: if (input == State::S1) ACTION_DO(ID::Y, cell->getPort(ID::A)); if (input == State::S0 && !a.is_fully_undef()) { - cover("opt.opt_expr.action_" S__LINE__); log_debug("Replacing data input of %s cell `%s' in module `%s' with constant undef.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str()); cell->setPort(ID::A, SigSpec(State::Sx, GetSize(a))); @@ -1222,7 +1196,6 @@ skip_fine_alu: log_assert(GetSize(a) == GetSize(b)); for (int i = 0; i < GetSize(a); i++) { if (a[i].wire == NULL && b[i].wire == NULL && a[i] != b[i] && a[i].data <= RTLIL::State::S1 && b[i].data <= RTLIL::State::S1) { - cover_list("opt.opt_expr.eqneq.isneq", "$eq", "$ne", "$eqx", "$nex", cell->type.str()); RTLIL::SigSpec new_y = RTLIL::SigSpec(cell->type.in(ID($eq), ID($eqx)) ? RTLIL::State::S0 : RTLIL::State::S1); new_y.extend_u0(cell->parameters[ID::Y_WIDTH].as_int(), false); replace_cell(assign_map, module, cell, "isneq", ID::Y, new_y); @@ -1235,7 +1208,6 @@ skip_fine_alu: } if (new_a.size() == 0) { - cover_list("opt.opt_expr.eqneq.empty", "$eq", "$ne", "$eqx", "$nex", cell->type.str()); RTLIL::SigSpec new_y = RTLIL::SigSpec(cell->type.in(ID($eq), ID($eqx)) ? RTLIL::State::S1 : RTLIL::State::S0); new_y.extend_u0(cell->parameters[ID::Y_WIDTH].as_int(), false); replace_cell(assign_map, module, cell, "empty", ID::Y, new_y); @@ -1243,7 +1215,6 @@ skip_fine_alu: } if (new_a.size() < a.size() || new_b.size() < b.size()) { - cover_list("opt.opt_expr.eqneq.resize", "$eq", "$ne", "$eqx", "$nex", cell->type.str()); cell->setPort(ID::A, new_a); cell->setPort(ID::B, new_b); cell->parameters[ID::A_WIDTH] = new_a.size(); @@ -1258,7 +1229,6 @@ skip_fine_alu: RTLIL::SigSpec b = assign_map(cell->getPort(ID::B)); if (a.is_fully_const() && !b.is_fully_const()) { - cover_list("opt.opt_expr.eqneq.swapconst", "$eq", "$ne", cell->type.str()); cell->setPort(ID::A, b); cell->setPort(ID::B, a); std::swap(a, b); @@ -1273,7 +1243,6 @@ skip_fine_alu: RTLIL::SigSpec input = b; ACTION_DO(ID::Y, cell->getPort(ID::A)); } else { - cover_list("opt.opt_expr.eqneq.isnot", "$eq", "$ne", cell->type.str()); log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module)); cell->type = ID($not); cell->parameters.erase(ID::B_WIDTH); @@ -1288,7 +1257,6 @@ skip_fine_alu: if (cell->type.in(ID($eq), ID($ne)) && (assign_map(cell->getPort(ID::A)).is_fully_zero() || assign_map(cell->getPort(ID::B)).is_fully_zero())) { - cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell->type.str()); log_debug("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell), log_id(module), cell->type == ID($eq) ? "$logic_not" : "$reduce_bool"); cell->type = cell->type == ID($eq) ? ID($logic_not) : ID($reduce_bool); @@ -1336,8 +1304,6 @@ skip_fine_alu: sig_y[i] = sig_a[GetSize(sig_a)-1]; } - cover_list("opt.opt_expr.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str()); - log_debug("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n", log_id(cell->type), log_id(cell), log_signal(assign_map(cell->getPort(ID::B))), shift_bits, log_id(module), log_signal(sig_y)); @@ -1410,11 +1376,6 @@ skip_fine_alu: if (identity_wrt_a || identity_wrt_b) { - if (identity_wrt_a) - cover_list("opt.opt_expr.identwrt.a", "$add", "$sub", "$alu", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str()); - if (identity_wrt_b) - cover_list("opt.opt_expr.identwrt.b", "$add", "$sub", "$alu", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str()); - log_debug("Replacing %s cell `%s' in module `%s' with identity for port %c.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), identity_wrt_a ? 'A' : 'B'); @@ -1463,14 +1424,12 @@ skip_identity: if (mux_bool && cell->type.in(ID($mux), ID($_MUX_)) && cell->getPort(ID::A) == State::S0 && cell->getPort(ID::B) == State::S1) { - cover_list("opt.opt_expr.mux_bool", "$mux", "$_MUX_", cell->type.str()); replace_cell(assign_map, module, cell, "mux_bool", ID::Y, cell->getPort(ID::S)); goto next_cell; } if (mux_bool && cell->type.in(ID($mux), ID($_MUX_)) && cell->getPort(ID::A) == State::S1 && cell->getPort(ID::B) == State::S0) { - cover_list("opt.opt_expr.mux_invert", "$mux", "$_MUX_", cell->type.str()); log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module)); cell->setPort(ID::A, cell->getPort(ID::S)); cell->unsetPort(ID::B); @@ -1489,7 +1448,6 @@ skip_identity: } if (consume_x && mux_bool && cell->type.in(ID($mux), ID($_MUX_)) && cell->getPort(ID::A) == State::S0) { - cover_list("opt.opt_expr.mux_and", "$mux", "$_MUX_", cell->type.str()); log_debug("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); cell->setPort(ID::A, cell->getPort(ID::S)); cell->unsetPort(ID::S); @@ -1509,7 +1467,6 @@ skip_identity: } if (consume_x && mux_bool && cell->type.in(ID($mux), ID($_MUX_)) && cell->getPort(ID::B) == State::S1) { - cover_list("opt.opt_expr.mux_or", "$mux", "$_MUX_", cell->type.str()); log_debug("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); cell->setPort(ID::B, cell->getPort(ID::S)); cell->unsetPort(ID::S); @@ -1533,7 +1490,6 @@ skip_identity: int width = GetSize(cell->getPort(ID::A)); if ((cell->getPort(ID::A).is_fully_undef() && cell->getPort(ID::B).is_fully_undef()) || cell->getPort(ID::S).is_fully_undef()) { - cover_list("opt.opt_expr.mux_undef", "$mux", "$pmux", cell->type.str()); replace_cell(assign_map, module, cell, "mux_undef", ID::Y, cell->getPort(ID::A)); goto next_cell; } @@ -1552,17 +1508,14 @@ skip_identity: new_s = new_s.extract(0, new_s.size()-1); } if (new_s.size() == 0) { - cover_list("opt.opt_expr.mux_empty", "$mux", "$pmux", cell->type.str()); replace_cell(assign_map, module, cell, "mux_empty", ID::Y, new_a); goto next_cell; } if (new_a == RTLIL::SigSpec(RTLIL::State::S0) && new_b == RTLIL::SigSpec(RTLIL::State::S1)) { - cover_list("opt.opt_expr.mux_sel01", "$mux", "$pmux", cell->type.str()); replace_cell(assign_map, module, cell, "mux_sel01", ID::Y, new_s); goto next_cell; } if (cell->getPort(ID::S).size() != new_s.size()) { - cover_list("opt.opt_expr.mux_reduce", "$mux", "$pmux", cell->type.str()); log_debug("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n", GetSize(cell->getPort(ID::S)) - GetSize(new_s), log_id(cell->type), log_id(cell), log_id(module)); cell->setPort(ID::A, new_a); @@ -1602,7 +1555,6 @@ skip_identity: RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), dummy_arg, \ cell->parameters[ID::A_SIGNED].as_bool(), false, \ cell->parameters[ID::Y_WIDTH].as_int())); \ - cover("opt.opt_expr.const.$" #_t); \ replace_cell(assign_map, module, cell, stringf("%s", log_signal(a)), ID::Y, y); \ goto next_cell; \ } \ @@ -1617,7 +1569,6 @@ skip_identity: cell->parameters[ID::A_SIGNED].as_bool(), \ cell->parameters[ID::B_SIGNED].as_bool(), \ cell->parameters[ID::Y_WIDTH].as_int())); \ - cover("opt.opt_expr.const.$" #_t); \ replace_cell(assign_map, module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), ID::Y, y); \ goto next_cell; \ } \ @@ -1629,7 +1580,6 @@ skip_identity: assign_map.apply(a), assign_map.apply(b); \ if (a.is_fully_const() && b.is_fully_const()) { \ RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), b.as_const())); \ - cover("opt.opt_expr.const.$" #_t); \ replace_cell(assign_map, module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), ID::Y, y); \ goto next_cell; \ } \ @@ -1642,7 +1592,6 @@ skip_identity: assign_map.apply(a), assign_map.apply(b), assign_map.apply(s); \ if (a.is_fully_const() && b.is_fully_const() && s.is_fully_const()) { \ RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), b.as_const(), s.as_const())); \ - cover("opt.opt_expr.const.$" #_t); \ replace_cell(assign_map, module, cell, stringf("%s, %s, %s", log_signal(a), log_signal(b), log_signal(s)), ID::Y, y); \ goto next_cell; \ } \ @@ -1759,8 +1708,6 @@ skip_identity: { if (sig_a.is_fully_zero()) { - cover("opt.opt_expr.mul_shift.zero"); - log_debug("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n", cell->name.c_str(), module->name.c_str()); @@ -1774,11 +1721,6 @@ skip_identity: int exp; if (sig_a.is_onehot(&exp) && !(a_signed && exp == GetSize(sig_a) - 1)) { - if (swapped_ab) - cover("opt.opt_expr.mul_shift.swapped"); - else - cover("opt.opt_expr.mul_shift.unswapped"); - log_debug("Replacing multiply-by-%s cell `%s' in module `%s' with shift-by-%d.\n", log_signal(sig_a), cell->name.c_str(), module->name.c_str(), exp); @@ -1812,8 +1754,6 @@ skip_identity: break; if (a_zeros || b_zeros) { int y_zeros = a_zeros + b_zeros; - cover("opt.opt_expr.mul_low_zeros"); - log_debug("Removing low %d A and %d B bits from cell `%s' in module `%s'.\n", a_zeros, b_zeros, cell->name.c_str(), module->name.c_str()); @@ -1855,8 +1795,6 @@ skip_identity: { if (sig_b.is_fully_zero()) { - cover("opt.opt_expr.divmod_zero"); - log_debug("Replacing divide-by-zero cell `%s' in module `%s' with undef-driver.\n", cell->name.c_str(), module->name.c_str()); @@ -1872,8 +1810,6 @@ skip_identity: { if (cell->type.in(ID($div), ID($divfloor))) { - cover("opt.opt_expr.div_shift"); - bool is_truncating = cell->type == ID($div); log_debug("Replacing %s-divide-by-%s cell `%s' in module `%s' with shift-by-%d.\n", is_truncating ? "truncating" : "flooring", @@ -1902,8 +1838,6 @@ skip_identity: } else if (cell->type.in(ID($mod), ID($modfloor))) { - cover("opt.opt_expr.mod_mask"); - bool is_truncating = cell->type == ID($mod); log_debug("Replacing %s-modulo-by-%s cell `%s' in module `%s' with bitmask.\n", is_truncating ? "truncating" : "flooring", @@ -2028,7 +1962,6 @@ skip_identity: sig_ci = p.second; } - cover("opt.opt_expr.alu_split"); module->remove(cell); did_something = true; diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc index 6cdcbc822..a6121b268 100644 --- a/passes/opt/opt_merge.cc +++ b/passes/opt/opt_merge.cc @@ -22,6 +22,7 @@ #include "kernel/sigtools.h" #include "kernel/log.h" #include "kernel/celltypes.h" +#include "kernel/threading.h" #include "libs/sha1/sha1.h" #include #include @@ -37,16 +38,73 @@ PRIVATE_NAMESPACE_BEGIN template inline Hasher hash_pair(const T &t, const U &u) { return hash_ops>::hash(t, u); } -struct OptMergeWorker +// Some cell and its hash value. +struct CellHash { - RTLIL::Design *design; - RTLIL::Module *module; - SigMap assign_map; - FfInitVals initvals; - bool mode_share_all; + // Index of a cell in the module + int cell_index; + Hasher::hash_t hash_value; +}; - CellTypes ct; - int total_count; +// The algorithm: +// 1) Compute and store the hashes of all relevant cells, in parallel. +// 2) Given N = the number of threads, partition the cells into N buckets by hash value: +// bucket k contains the cells whose hash value mod N = k. +// 3) For each bucket in parallel, build a hashtable of that bucket’s cells (using the +// precomputed hashes) and record the duplicates found. +// 4) On the main thread, process the list of duplicates to remove cells. +// For efficiency we fuse the second step into the first step by having the parallel +// threads write the cells into buckets directly. +// To avoid synchronization overhead, we divide each bucket into N shards. Each +// thread j adds a cell to bucket k by writing to shard j of bucket k — +// no synchronization required. In the next phase, thread k builds the hashtable for +// bucket k by iterating over all shards of the bucket. + +// The input to each thread in the "compute cell hashes" phase. +struct CellRange +{ + int begin; + int end; +}; + +// The output from each thread in the "compute cell hashes" phase. +struct CellHashes +{ + // Entry i contains the hashes where hash_value % bucketed_cell_hashes.size() == i + std::vector> bucketed_cell_hashes; +}; + +// A duplicate cell that has been found. +struct DuplicateCell +{ + // Remove this cell from the design + int remove_cell; + // ... and use this cell instead. + int keep_cell; +}; + +// The input to each thread in the "find duplicate cells" phase. +// Shards of buckets of cell hashes +struct Shards +{ + std::vector>> &bucketed_cell_hashes; +}; + +// The output from each thread in the "find duplicate cells" phase. +struct FoundDuplicates +{ + std::vector duplicates; +}; + +struct OptMergeThreadWorker +{ + const RTLIL::Module *module; + const SigMap &assign_map; + const FfInitVals &initvals; + const CellTypes &ct; + int workers; + bool mode_share_all; + bool mode_keepdc; static Hasher hash_pmux_in(const SigSpec& sig_s, const SigSpec& sig_b, Hasher h) { @@ -62,8 +120,8 @@ struct OptMergeWorker static void sort_pmux_conn(dict &conn) { - SigSpec sig_s = conn.at(ID::S); - SigSpec sig_b = conn.at(ID::B); + const SigSpec &sig_s = conn.at(ID::S); + const SigSpec &sig_b = conn.at(ID::B); int s_width = GetSize(sig_s); int width = GetSize(sig_b) / s_width; @@ -144,7 +202,6 @@ struct OptMergeWorker if (cell1->parameters != cell2->parameters) return false; - if (cell1->connections_.size() != cell2->connections_.size()) return false; for (const auto &it : cell1->connections_) @@ -199,7 +256,7 @@ struct OptMergeWorker return conn1 == conn2; } - bool has_dont_care_initval(const RTLIL::Cell *cell) + bool has_dont_care_initval(const RTLIL::Cell *cell) const { if (!cell->is_builtin_ff()) return false; @@ -207,31 +264,134 @@ struct OptMergeWorker return !initvals(cell->getPort(ID::Q)).is_fully_def(); } - OptMergeWorker(RTLIL::Design *design, RTLIL::Module *module, bool mode_nomux, bool mode_share_all, bool mode_keepdc) : - design(design), module(module), mode_share_all(mode_share_all) + OptMergeThreadWorker(const RTLIL::Module *module, const FfInitVals &initvals, + const SigMap &assign_map, const CellTypes &ct, int workers, + bool mode_share_all, bool mode_keepdc) : + module(module), assign_map(assign_map), initvals(initvals), ct(ct), + workers(workers), mode_share_all(mode_share_all), mode_keepdc(mode_keepdc) { - total_count = 0; - ct.setup_internals(); - ct.setup_internals_mem(); - ct.setup_stdcells(); - ct.setup_stdcells_mem(); + } - if (mode_nomux) { - ct.cell_types.erase(ID($mux)); - ct.cell_types.erase(ID($pmux)); + CellHashes compute_cell_hashes(const CellRange &cell_range) const + { + std::vector> bucketed_cell_hashes(workers); + for (int cell_index = cell_range.begin; cell_index < cell_range.end; ++cell_index) { + const RTLIL::Cell *cell = module->cell_at(cell_index); + if (!module->selected(cell)) + continue; + if (cell->type.in(ID($meminit), ID($meminit_v2), ID($mem), ID($mem_v2))) { + // Ignore those for performance: meminit can have an excessively large port, + // mem can have an excessively large parameter holding the init data + continue; + } + if (cell->type == ID($scopeinfo)) + continue; + if (mode_keepdc && has_dont_care_initval(cell)) + continue; + if (!cell->known()) + continue; + if (!mode_share_all && !ct.cell_known(cell->type)) + continue; + + Hasher::hash_t h = hash_cell_function(cell, Hasher()).yield(); + int bucket_index = h % workers; + bucketed_cell_hashes[bucket_index].push_back({cell_index, h}); } + return {std::move(bucketed_cell_hashes)}; + } - ct.cell_types.erase(ID($tribuf)); - ct.cell_types.erase(ID($_TBUF_)); - ct.cell_types.erase(ID($anyseq)); - ct.cell_types.erase(ID($anyconst)); - ct.cell_types.erase(ID($allseq)); - ct.cell_types.erase(ID($allconst)); + FoundDuplicates find_duplicate_cells(int index, const Shards &in) const + { + // We keep a set of known cells. They're hashed with our hash_cell_function + // and compared with our compare_cell_parameters_and_connections. + struct CellHashOp { + std::size_t operator()(const CellHash &c) const { + return (std::size_t)c.hash_value; + } + }; + struct CellEqualOp { + const OptMergeThreadWorker& worker; + CellEqualOp(const OptMergeThreadWorker& w) : worker(w) {} + bool operator()(const CellHash &lhs, const CellHash &rhs) const { + return worker.compare_cell_parameters_and_connections( + worker.module->cell_at(lhs.cell_index), + worker.module->cell_at(rhs.cell_index)); + } + }; + std::unordered_set< + CellHash, + CellHashOp, + CellEqualOp> known_cells(0, CellHashOp(), CellEqualOp(*this)); + + std::vector duplicates; + for (const std::vector> &buckets : in.bucketed_cell_hashes) { + // Clear out our buckets as we go. This keeps the work of deallocation + // off the main thread. + std::vector bucket = std::move(buckets[index]); + for (CellHash c : bucket) { + auto [cell_in_map, inserted] = known_cells.insert(c); + if (inserted) + continue; + CellHash map_c = *cell_in_map; + if (module->cell_at(c.cell_index)->has_keep_attr()) { + if (module->cell_at(map_c.cell_index)->has_keep_attr()) + continue; + known_cells.erase(map_c); + known_cells.insert(c); + std::swap(c, map_c); + } + duplicates.push_back({c.cell_index, map_c.cell_index}); + } + } + return {duplicates}; + } +}; + +template +void initialize_queues(std::vector> &queues, int size) { + queues.reserve(size); + for (int i = 0; i < size; ++i) + queues.emplace_back(1); +} + +struct OptMergeWorker +{ + int total_count; + + OptMergeWorker(RTLIL::Module *module, const CellTypes &ct, bool mode_share_all, bool mode_keepdc) : + total_count(0) + { + SigMap assign_map(module); + FfInitVals initvals; + initvals.set(&assign_map, module); log("Finding identical cells in module `%s'.\n", module->name); - assign_map.set(module); - initvals.set(&assign_map, module); + // Use no more than one worker per thousand cells, rounded down, so + // we only start multithreading with at least 2000 cells. + int num_worker_threads = ThreadPool::pool_size(0, module->cells_size()/1000); + int workers = std::max(1, num_worker_threads); + + // The main thread doesn't do any work, so if there is only one worker thread, + // just run everything on the main thread instead. + // This avoids creating and waiting on a thread, which is pretty high overhead + // for very small modules. + if (num_worker_threads == 1) + num_worker_threads = 0; + OptMergeThreadWorker thread_worker(module, initvals, assign_map, ct, workers, mode_share_all, mode_keepdc); + + std::vector> cell_ranges_queues(num_worker_threads); + std::vector> cell_hashes_queues(num_worker_threads); + std::vector> shards_queues(num_worker_threads); + std::vector> duplicates_queues(num_worker_threads); + + ThreadPool thread_pool(num_worker_threads, [&](int i) { + while (std::optional c = cell_ranges_queues[i].pop_front()) { + cell_hashes_queues[i].push_back(thread_worker.compute_cell_hashes(*c)); + std::optional shards = shards_queues[i].pop_front(); + duplicates_queues[i].push_back(thread_worker.find_duplicate_cells(i, *shards)); + } + }); bool did_something = true; // A cell may have to go through a lot of collisions if the hash @@ -239,87 +399,99 @@ struct OptMergeWorker // beyond the user's control. while (did_something) { - std::vector cells; - cells.reserve(module->cells().size()); - for (auto cell : module->cells()) { - if (!design->selected(module, cell)) - continue; - if (cell->type.in(ID($meminit), ID($meminit_v2), ID($mem), ID($mem_v2))) { - // Ignore those for performance: meminit can have an excessively large port, - // mem can have an excessively large parameter holding the init data - continue; - } - if (cell->type == ID($scopeinfo)) - continue; - if (mode_keepdc && has_dont_care_initval(cell)) - continue; - if (!cell->known()) - continue; - if (!mode_share_all && !ct.cell_known(cell->type)) - continue; - cells.push_back(cell); - } + int cells_size = module->cells_size(); + log("Computing hashes of %d cells of `%s'.\n", cells_size, module->name); + std::vector>> sharded_bucketed_cell_hashes(workers); - did_something = false; - - // We keep a set of known cells. They're hashed with our hash_cell_function - // and compared with our compare_cell_parameters_and_connections. - // Both need to capture OptMergeWorker to access initvals - struct CellPtrHash { - const OptMergeWorker& worker; - CellPtrHash(const OptMergeWorker& w) : worker(w) {} - std::size_t operator()(const Cell* c) const { - return (std::size_t)worker.hash_cell_function(c, Hasher()).yield(); - } - }; - struct CellPtrEqual { - const OptMergeWorker& worker; - CellPtrEqual(const OptMergeWorker& w) : worker(w) {} - bool operator()(const Cell* lhs, const Cell* rhs) const { - return worker.compare_cell_parameters_and_connections(lhs, rhs); - } - }; - std::unordered_set< - RTLIL::Cell*, - CellPtrHash, - CellPtrEqual> known_cells (0, CellPtrHash(*this), CellPtrEqual(*this)); - - for (auto cell : cells) + int cell_index = 0; + int cells_size_mod_workers = cells_size % workers; { - auto [cell_in_map, inserted] = known_cells.insert(cell); - if (!inserted) { - // We've failed to insert since we already have an equivalent cell - Cell* other_cell = *cell_in_map; - if (cell->has_keep_attr()) { - if (other_cell->has_keep_attr()) - continue; - known_cells.erase(other_cell); - known_cells.insert(cell); - std::swap(other_cell, cell); - } - - did_something = true; - log_debug(" Cell `%s' is identical to cell `%s'.\n", cell->name, other_cell->name); - for (auto &it : cell->connections()) { - if (cell->output(it.first)) { - RTLIL::SigSpec other_sig = other_cell->getPort(it.first); - log_debug(" Redirecting output %s: %s = %s\n", it.first, - log_signal(it.second), log_signal(other_sig)); - Const init = initvals(other_sig); - initvals.remove_init(it.second); - initvals.remove_init(other_sig); - module->connect(RTLIL::SigSig(it.second, other_sig)); - assign_map.add(it.second, other_sig); - initvals.set_init(other_sig, init); - } - } - log_debug(" Removing %s cell `%s' from module `%s'.\n", cell->type, cell->name, module->name); - module->remove(cell); - total_count++; + Multithreading multithreading; + for (int i = 0; i < workers; ++i) { + int num_cells = cells_size/workers + ((i < cells_size_mod_workers) ? 1 : 0); + CellRange c = { cell_index, cell_index + num_cells }; + cell_index += num_cells; + if (num_worker_threads > 0) + cell_ranges_queues[i].push_back(c); + else + sharded_bucketed_cell_hashes[i] = std::move(thread_worker.compute_cell_hashes(c).bucketed_cell_hashes); } + log_assert(cell_index == cells_size); + if (num_worker_threads > 0) + for (int i = 0; i < workers; ++i) + sharded_bucketed_cell_hashes[i] = std::move(cell_hashes_queues[i].pop_front()->bucketed_cell_hashes); } + + log("Finding duplicate cells in `%s'.\n", module->name); + std::vector merged_duplicates; + { + Multithreading multithreading; + for (int i = 0; i < workers; ++i) { + Shards thread_shards = { sharded_bucketed_cell_hashes }; + if (num_worker_threads > 0) + shards_queues[i].push_back(thread_shards); + else { + std::vector d = std::move(thread_worker.find_duplicate_cells(i, thread_shards).duplicates); + merged_duplicates.insert(merged_duplicates.end(), d.begin(), d.end()); + } + } + if (num_worker_threads > 0) + for (int i = 0; i < workers; ++i) { + std::vector d = std::move(duplicates_queues[i].pop_front()->duplicates); + merged_duplicates.insert(merged_duplicates.end(), d.begin(), d.end()); + } + } + std::sort(merged_duplicates.begin(), merged_duplicates.end(), [](const DuplicateCell &lhs, const DuplicateCell &rhs) { + // Sort them by the order in which duplicates would have been detected in a single-threaded + // run. The cell at which the duplicate would have been detected is the latter of the two + // cells involved. + return std::max(lhs.remove_cell, lhs.keep_cell) < std::max(rhs.remove_cell, rhs.keep_cell); + }); + + // Convert to cell pointers because removing cells will invalidate the indices. + std::vector> cell_ptrs; + for (DuplicateCell dup : merged_duplicates) + cell_ptrs.push_back({module->cell_at(dup.remove_cell), module->cell_at(dup.keep_cell)}); + + for (auto [remove_cell, keep_cell] : cell_ptrs) + { + log_debug(" Cell `%s' is identical to cell `%s'.\n", remove_cell->name, keep_cell->name); + for (auto &it : remove_cell->connections()) { + if (remove_cell->output(it.first)) { + RTLIL::SigSpec keep_sig = keep_cell->getPort(it.first); + log_debug(" Redirecting output %s: %s = %s\n", it.first, + log_signal(it.second), log_signal(keep_sig)); + Const init = initvals(keep_sig); + initvals.remove_init(it.second); + initvals.remove_init(keep_sig); + module->connect(RTLIL::SigSig(it.second, keep_sig)); + auto keep_sig_it = keep_sig.begin(); + for (SigBit remove_sig_bit : it.second) { + assign_map.add(remove_sig_bit, *keep_sig_it); + ++keep_sig_it; + } + initvals.set_init(keep_sig, init); + } + } + log_debug(" Removing %s cell `%s' from module `%s'.\n", remove_cell->type, remove_cell->name, module->name); + module->remove(remove_cell); + total_count++; + } + did_something = !merged_duplicates.empty(); } + for (ConcurrentQueue &q : cell_ranges_queues) + q.close(); + + for (ConcurrentQueue &q : shards_queues) + q.close(); + + for (ConcurrentQueue &q : cell_ranges_queues) + q.close(); + + for (ConcurrentQueue &q : shards_queues) + q.close(); + log_suppressed(); } }; @@ -372,9 +544,25 @@ struct OptMergePass : public Pass { } extra_args(args, argidx, design); + CellTypes ct; + ct.setup_internals(); + ct.setup_internals_mem(); + ct.setup_stdcells(); + ct.setup_stdcells_mem(); + if (mode_nomux) { + ct.cell_types.erase(ID($mux)); + ct.cell_types.erase(ID($pmux)); + } + ct.cell_types.erase(ID($tribuf)); + ct.cell_types.erase(ID($_TBUF_)); + ct.cell_types.erase(ID($anyseq)); + ct.cell_types.erase(ID($anyconst)); + ct.cell_types.erase(ID($allseq)); + ct.cell_types.erase(ID($allconst)); + int total_count = 0; for (auto module : design->selected_modules()) { - OptMergeWorker worker(design, module, mode_nomux, mode_share_all, mode_keepdc); + OptMergeWorker worker(module, ct, mode_share_all, mode_keepdc); total_count += worker.total_count; } diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc index 2f7d26dcf..0020af09f 100644 --- a/passes/opt/opt_muxtree.cc +++ b/passes/opt/opt_muxtree.cc @@ -64,7 +64,7 @@ struct OptMuxtreeWorker RTLIL::Module *module; SigMap assign_map; int removed_count; - int glob_evals_left = 10000000; + int glob_evals_left = 10'000'000; struct bitinfo_t { // Is bit directly used by non-mux cells or ports? diff --git a/passes/proc/proc_clean.cc b/passes/proc/proc_clean.cc index 19c2be4ca..8cccb96c4 100644 --- a/passes/proc/proc_clean.cc +++ b/passes/proc/proc_clean.cc @@ -97,6 +97,7 @@ void proc_clean_switch(RTLIL::SwitchRule *sw, RTLIL::CaseRule *parent, bool &did all_empty = false; if (all_empty) { + did_something = true; for (auto cs : sw->cases) delete cs; sw->cases.clear(); diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index 91b3b563a..083778d3c 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -39,6 +39,7 @@ OBJS += passes/techmap/muxcover.o OBJS += passes/techmap/aigmap.o OBJS += passes/techmap/tribuf.o OBJS += passes/techmap/lut2mux.o +OBJS += passes/techmap/lut2bmux.o OBJS += passes/techmap/nlutmap.o OBJS += passes/techmap/shregmap.o OBJS += passes/techmap/deminout.o diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 0963ecfde..ad4dc5ccd 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -252,8 +252,8 @@ std::optional spawn_abc(const char* abc_exe, DeferredLogs &logs) { char arg1[] = "-s"; char* argv[] = { strdup(abc_exe), arg1, nullptr }; - if (0 != posix_spawn(&result.pid, abc_exe, &file_actions, nullptr, argv, environ)) { - logs.log_error("posix_spawn %s failed", abc_exe); + if (0 != posix_spawnp(&result.pid, abc_exe, &file_actions, nullptr, argv, environ)) { + logs.log_error("posix_spawnp %s failed (errno=%s)", abc_exe, strerror(errno)); return std::nullopt; } free(argv[0]); diff --git a/passes/techmap/bufnorm.cc b/passes/techmap/bufnorm.cc index a4552c71b..123687255 100644 --- a/passes/techmap/bufnorm.cc +++ b/passes/techmap/bufnorm.cc @@ -415,7 +415,7 @@ struct BufnormPass : public Pass { return mapped_bits.at(bit); }; - auto make_buffer_f = [&](const IdString &type, const SigSpec &src, const SigSpec &dst) + auto make_buffer_f = [&](IdString type, const SigSpec &src, const SigSpec &dst) { auto it = old_buffers.find(pair(type, dst)); diff --git a/passes/techmap/extract_fa.cc b/passes/techmap/extract_fa.cc index 1984f82f5..46ab7e520 100644 --- a/passes/techmap/extract_fa.cc +++ b/passes/techmap/extract_fa.cc @@ -40,10 +40,10 @@ int bindec(unsigned char v) r += (~((v & 2) - 1)) & 10; r += (~((v & 4) - 1)) & 100; r += (~((v & 8) - 1)) & 1000; - r += (~((v & 16) - 1)) & 10000; - r += (~((v & 32) - 1)) & 100000; - r += (~((v & 64) - 1)) & 1000000; - r += (~((v & 128) - 1)) & 10000000; + r += (~((v & 16) - 1)) & 10'000; + r += (~((v & 32) - 1)) & 100'000; + r += (~((v & 64) - 1)) & 1'000'000; + r += (~((v & 128) - 1)) & 10'000'000; return r; } diff --git a/passes/techmap/lut2bmux.cc b/passes/techmap/lut2bmux.cc new file mode 100644 index 000000000..42042c942 --- /dev/null +++ b/passes/techmap/lut2bmux.cc @@ -0,0 +1,58 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Claire Xenia Wolf + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct Lut2BmuxPass : public Pass { + Lut2BmuxPass() : Pass("lut2bmux", "convert $lut to $bmux") { } + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" lut2bmux [options] [selection]\n"); + log("\n"); + log("This pass converts $lut cells to $bmux cells.\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) override + { + log_header(design, "Executing LUT2BMUX pass (convert $lut to $bmux).\n"); + + size_t argidx = 1; + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + for (auto cell : module->selected_cells()) { + if (cell->type == ID($lut)) { + cell->type = ID($bmux); + cell->setPort(ID::S, cell->getPort(ID::A)); + cell->setPort(ID::A, cell->getParam(ID::LUT)); + cell->unsetParam(ID::LUT); + cell->fixup_parameters(); + log("Converted %s.%s to BMUX cell.\n", log_id(module), log_id(cell)); + } + } + } +} Lut2BmuxPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc index 938ed5355..0c7d1930e 100644 --- a/passes/techmap/simplemap.cc +++ b/passes/techmap/simplemap.cc @@ -27,7 +27,7 @@ USING_YOSYS_NAMESPACE YOSYS_NAMESPACE_BEGIN -static void transfer_attr (Cell* to, const Cell* from, const IdString& attr) { +static void transfer_attr (Cell* to, const Cell* from, IdString attr) { if (from->has_attribute(attr)) to->attributes[attr] = from->attributes.at(attr); } diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc index 73af155bd..4d28e659b 100644 --- a/passes/tests/test_cell.cc +++ b/passes/tests/test_cell.cc @@ -1143,7 +1143,29 @@ struct TestCellPass : public Pass { else uut = create_gold_module(design, cell_type, cell_types.at(cell_type), constmode, muxdiv); if (!write_prefix.empty()) { - Pass::call(design, stringf("write_rtlil %s_%s_%05d.il", write_prefix, cell_type.c_str()+1, i)); + string writer = "write_rtlil"; + string suffix = "il"; + if (techmap_cmd.compare("aigmap") == 0) { + // try to convert to aiger + Pass::call(design, techmap_cmd); + bool is_unconverted = false; + for (auto *mod : design->selected_modules()) + for (auto *cell : mod->selected_cells()) + if (!cell->type.in(ID::$_NOT_, ID::$_AND_)) { + is_unconverted = true; + break; + } + if (is_unconverted) { + // skip unconverted cells + log_warning("Skipping %s\n", cell_type); + delete design; + break; + } else { + writer = "write_aiger -ascii"; + suffix = "aag"; + } + } + Pass::call(design, stringf("%s %s_%s_%05d.%s", writer, write_prefix, cell_type.c_str()+1, i, suffix)); } else if (edges) { Pass::call(design, "dump gold"); run_edges_test(design, verbose); diff --git a/pyosys/wrappers_tpl.cc b/pyosys/wrappers_tpl.cc index aa257e1b6..2e358029a 100644 --- a/pyosys/wrappers_tpl.cc +++ b/pyosys/wrappers_tpl.cc @@ -112,7 +112,7 @@ namespace pyosys { void notify_connect( RTLIL::Cell *cell, - const RTLIL::IdString &port, + RTLIL::IdString port, const RTLIL::SigSpec &old_sig, const RTLIL::SigSpec &sig ) override { @@ -228,7 +228,7 @@ namespace pyosys { "notify_connect", py::overload_cast< RTLIL::Cell *, - const RTLIL::IdString &, + RTLIL::IdString, const RTLIL::SigSpec &, const RTLIL::SigSpec & >(&RTLIL::Monitor::notify_connect) diff --git a/techlibs/gowin/brams.txt b/techlibs/gowin/brams.txt index ee76dd73a..6898c9bd9 100644 --- a/techlibs/gowin/brams.txt +++ b/techlibs/gowin/brams.txt @@ -2,6 +2,7 @@ ram block $__GOWIN_SP_ { abits 14; widths 1 2 4 9 18 36 per_port; cost 128; + byte 9; init no_undef; port srsw "A" { clock posedge; @@ -24,6 +25,7 @@ ram block $__GOWIN_SP_ { rdwr old; } } + wrbe_separate; } } @@ -31,6 +33,7 @@ ram block $__GOWIN_DP_ { abits 14; widths 1 2 4 9 18 per_port; cost 128; + byte 9; init no_undef; port srsw "A" "B" { clock posedge; @@ -53,6 +56,7 @@ ram block $__GOWIN_DP_ { rdwr old; } } + wrbe_separate; } } @@ -60,6 +64,7 @@ ram block $__GOWIN_SDP_ { abits 14; widths 1 2 4 9 18 36 per_port; cost 128; + byte 9; init no_undef; port sr "R" { clock posedge; @@ -75,5 +80,6 @@ ram block $__GOWIN_SDP_ { port sw "W" { clock posedge; clken; + wrbe_separate; } } diff --git a/techlibs/gowin/brams_map.v b/techlibs/gowin/brams_map.v index 8e6cc6140..774896e79 100644 --- a/techlibs/gowin/brams_map.v +++ b/techlibs/gowin/brams_map.v @@ -14,7 +14,7 @@ `define x8_width(width) (width / 9 * 8 + width % 9) `define x8_rd_data(data) {1'bx, data[31:24], 1'bx, data[23:16], 1'bx, data[15:8], 1'bx, data[7:0]} `define x8_wr_data(data) {data[34:27], data[25:18], data[16:9], data[7:0]} -`define addrbe_always(width, addr) (width < 18 ? addr : width == 18 ? {addr[13:4], 4'b0011} : {addr[13:5], 5'b01111}) +`define addrbe(width, addr, w_be) (width < 18 ? addr : width == 18 ? {addr[13:4], 2'b00, w_be[1:0]} : {addr[13:5], 1'b0, w_be[3:0]}) `define INIT(func) \ @@ -90,6 +90,7 @@ parameter OPTION_RESET_MODE = "SYNC"; parameter PORT_A_WIDTH = 36; parameter PORT_A_OPTION_WRITE_MODE = 0; +parameter PORT_A_WR_BE_WIDTH = 4; input PORT_A_CLK; input PORT_A_CLK_EN; @@ -97,13 +98,14 @@ input PORT_A_WR_EN; input PORT_A_RD_SRST; input PORT_A_RD_ARST; input [13:0] PORT_A_ADDR; +input [PORT_A_WR_BE_WIDTH-1:0] PORT_A_WR_BE; input [PORT_A_WIDTH-1:0] PORT_A_WR_DATA; output [PORT_A_WIDTH-1:0] PORT_A_RD_DATA; `DEF_FUNCS wire RST = OPTION_RESET_MODE == "SYNC" ? PORT_A_RD_SRST : PORT_A_RD_ARST; -wire [13:0] AD = `addrbe_always(PORT_A_WIDTH, PORT_A_ADDR); +wire [13:0] AD = `addrbe(PORT_A_WIDTH, PORT_A_ADDR, PORT_A_WR_BE); generate @@ -173,9 +175,11 @@ parameter OPTION_RESET_MODE = "SYNC"; parameter PORT_A_WIDTH = 18; parameter PORT_A_OPTION_WRITE_MODE = 0; +parameter PORT_A_WR_BE_WIDTH = 4; parameter PORT_B_WIDTH = 18; parameter PORT_B_OPTION_WRITE_MODE = 0; +parameter PORT_B_WR_BE_WIDTH = 4; input PORT_A_CLK; input PORT_A_CLK_EN; @@ -183,6 +187,7 @@ input PORT_A_WR_EN; input PORT_A_RD_SRST; input PORT_A_RD_ARST; input [13:0] PORT_A_ADDR; +input [PORT_A_WR_BE_WIDTH-1:0] PORT_A_WR_BE; input [PORT_A_WIDTH-1:0] PORT_A_WR_DATA; output [PORT_A_WIDTH-1:0] PORT_A_RD_DATA; @@ -192,6 +197,7 @@ input PORT_B_WR_EN; input PORT_B_RD_SRST; input PORT_B_RD_ARST; input [13:0] PORT_B_ADDR; +input [PORT_B_WR_BE_WIDTH-1:0] PORT_B_WR_BE; input [PORT_A_WIDTH-1:0] PORT_B_WR_DATA; output [PORT_A_WIDTH-1:0] PORT_B_RD_DATA; @@ -199,8 +205,8 @@ output [PORT_A_WIDTH-1:0] PORT_B_RD_DATA; wire RSTA = OPTION_RESET_MODE == "SYNC" ? PORT_A_RD_SRST : PORT_A_RD_ARST; wire RSTB = OPTION_RESET_MODE == "SYNC" ? PORT_B_RD_SRST : PORT_B_RD_ARST; -wire [13:0] ADA = `addrbe_always(PORT_A_WIDTH, PORT_A_ADDR); -wire [13:0] ADB = `addrbe_always(PORT_B_WIDTH, PORT_B_ADDR); +wire [13:0] ADA = `addrbe(PORT_A_WIDTH, PORT_A_ADDR, PORT_B_WR_BE); +wire [13:0] ADB = `addrbe(PORT_B_WIDTH, PORT_B_ADDR, PORT_B_WR_BE); generate @@ -306,6 +312,7 @@ parameter OPTION_RESET_MODE = "SYNC"; parameter PORT_R_WIDTH = 18; parameter PORT_W_WIDTH = 18; +parameter PORT_W_WR_BE_WIDTH = 4; input PORT_R_CLK; input PORT_R_CLK_EN; @@ -318,12 +325,13 @@ input PORT_W_CLK; input PORT_W_CLK_EN; input PORT_W_WR_EN; input [13:0] PORT_W_ADDR; +input [PORT_W_WR_BE_WIDTH-1:0] PORT_W_WR_BE; input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA; `DEF_FUNCS wire RST = OPTION_RESET_MODE == "SYNC" ? PORT_R_RD_SRST : PORT_R_RD_ARST; -wire [13:0] ADW = `addrbe_always(PORT_W_WIDTH, PORT_W_ADDR); +wire [13:0] ADW = `addrbe(PORT_W_WIDTH, PORT_W_ADDR, PORT_W_WR_BE); wire WRE = PORT_W_CLK_EN & PORT_W_WR_EN; generate diff --git a/techlibs/gowin/brams_map_gw5a.v b/techlibs/gowin/brams_map_gw5a.v index 246146ee5..547b0d1d1 100644 --- a/techlibs/gowin/brams_map_gw5a.v +++ b/techlibs/gowin/brams_map_gw5a.v @@ -14,7 +14,7 @@ `define x8_width(width) (width / 9 * 8 + width % 9) `define x8_rd_data(data) {1'bx, data[31:24], 1'bx, data[23:16], 1'bx, data[15:8], 1'bx, data[7:0]} `define x8_wr_data(data) {data[34:27], data[25:18], data[16:9], data[7:0]} -`define addrbe_always(width, addr) (width < 18 ? addr : width == 18 ? {addr[13:4], 4'b0011} : {addr[13:5], 5'b01111}) +`define addrbe(width, addr, w_be) (width < 18 ? addr : width == 18 ? {addr[13:4], 2'b00, w_be[1:0]} : {addr[13:5], 1'b0, w_be[3:0]}) `define INIT(func) \ @@ -90,6 +90,7 @@ parameter OPTION_RESET_MODE = "SYNC"; parameter PORT_A_WIDTH = 36; parameter PORT_A_OPTION_WRITE_MODE = 0; +parameter PORT_A_WR_BE_WIDTH = 4; input PORT_A_CLK; input PORT_A_CLK_EN; @@ -97,13 +98,14 @@ input PORT_A_WR_EN; input PORT_A_RD_SRST; input PORT_A_RD_ARST; input [13:0] PORT_A_ADDR; +input [PORT_A_WR_BE_WIDTH-1:0] PORT_A_WR_BE; input [PORT_A_WIDTH-1:0] PORT_A_WR_DATA; output [PORT_A_WIDTH-1:0] PORT_A_RD_DATA; `DEF_FUNCS wire RST = OPTION_RESET_MODE == "SYNC" ? PORT_A_RD_SRST : PORT_A_RD_ARST; -wire [13:0] AD = `addrbe_always(PORT_A_WIDTH, PORT_A_ADDR); +wire [13:0] AD = `addrbe(PORT_A_WIDTH, PORT_A_ADDR, PORT_A_WR_BE); generate @@ -173,9 +175,11 @@ parameter OPTION_RESET_MODE = "SYNC"; parameter PORT_A_WIDTH = 18; parameter PORT_A_OPTION_WRITE_MODE = 0; +parameter PORT_A_WR_BE_WIDTH = 4; parameter PORT_B_WIDTH = 18; parameter PORT_B_OPTION_WRITE_MODE = 0; +parameter PORT_B_WR_BE_WIDTH = 4; input PORT_A_CLK; input PORT_A_CLK_EN; @@ -183,6 +187,7 @@ input PORT_A_WR_EN; input PORT_A_RD_SRST; input PORT_A_RD_ARST; input [13:0] PORT_A_ADDR; +input [PORT_A_WR_BE_WIDTH-1:0] PORT_A_WR_BE; input [PORT_A_WIDTH-1:0] PORT_A_WR_DATA; output [PORT_A_WIDTH-1:0] PORT_A_RD_DATA; @@ -192,6 +197,7 @@ input PORT_B_WR_EN; input PORT_B_RD_SRST; input PORT_B_RD_ARST; input [13:0] PORT_B_ADDR; +input [PORT_B_WR_BE_WIDTH-1:0] PORT_B_WR_BE; input [PORT_A_WIDTH-1:0] PORT_B_WR_DATA; output [PORT_A_WIDTH-1:0] PORT_B_RD_DATA; @@ -199,8 +205,8 @@ output [PORT_A_WIDTH-1:0] PORT_B_RD_DATA; wire RSTA = OPTION_RESET_MODE == "SYNC" ? PORT_A_RD_SRST : PORT_A_RD_ARST; wire RSTB = OPTION_RESET_MODE == "SYNC" ? PORT_B_RD_SRST : PORT_B_RD_ARST; -wire [13:0] ADA = `addrbe_always(PORT_A_WIDTH, PORT_A_ADDR); -wire [13:0] ADB = `addrbe_always(PORT_B_WIDTH, PORT_B_ADDR); +wire [13:0] ADA = `addrbe(PORT_A_WIDTH, PORT_A_ADDR, PORT_B_WR_BE); +wire [13:0] ADB = `addrbe(PORT_B_WIDTH, PORT_B_ADDR, PORT_B_WR_BE); generate @@ -306,6 +312,7 @@ parameter OPTION_RESET_MODE = "SYNC"; parameter PORT_R_WIDTH = 18; parameter PORT_W_WIDTH = 18; +parameter PORT_W_WR_BE_WIDTH = 4; input PORT_R_CLK; input PORT_R_CLK_EN; @@ -318,12 +325,13 @@ input PORT_W_CLK; input PORT_W_CLK_EN; input PORT_W_WR_EN; input [13:0] PORT_W_ADDR; +input [PORT_W_WR_BE_WIDTH-1:0] PORT_W_WR_BE; input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA; `DEF_FUNCS wire RST = OPTION_RESET_MODE == "SYNC" ? PORT_R_RD_SRST : PORT_R_RD_ARST; -wire [13:0] ADW = `addrbe_always(PORT_W_WIDTH, PORT_W_ADDR); +wire [13:0] ADW = `addrbe(PORT_W_WIDTH, PORT_W_ADDR, PORT_W_WR_BE); wire WRE = PORT_W_CLK_EN & PORT_W_WR_EN; generate diff --git a/techlibs/ice40/ice40_wrapcarry.cc b/techlibs/ice40/ice40_wrapcarry.cc index 82218ff11..f62019617 100644 --- a/techlibs/ice40/ice40_wrapcarry.cc +++ b/techlibs/ice40/ice40_wrapcarry.cc @@ -138,7 +138,7 @@ struct Ice40WrapCarryPass : public Pass { lut->attributes[a.first.c_str() + strlen("\\SB_LUT4.")] = a.second; else if (a.first == ID::src) src = a.second; - else if (a.first.in(IdString{"\\SB_LUT4.name"}, ID::keep, ID::module_not_derived)) + else if (a.first.in(IdString{"\\SB_LUT4.name"}, ID::keep, ID::module_not_derived, ID::src)) continue; else log_abort(); diff --git a/tests/aiger/.gitignore b/tests/aiger/.gitignore index 4bb3e67f6..ef347c9d3 100644 --- a/tests/aiger/.gitignore +++ b/tests/aiger/.gitignore @@ -1,2 +1,3 @@ /*_ref.v /neg.out/ +/gate/ diff --git a/tests/aiger/gold/__ANDNOT__00000.aag b/tests/aiger/gold/__ANDNOT__00000.aag new file mode 100644 index 000000000..93f5c0044 --- /dev/null +++ b/tests/aiger/gold/__ANDNOT__00000.aag @@ -0,0 +1,7 @@ +aag 3 2 0 1 1 +2 +4 +6 +6 5 2 +c +Generated by Yosys diff --git a/tests/aiger/gold/__AND__00000.aag b/tests/aiger/gold/__AND__00000.aag new file mode 100644 index 000000000..5b0148022 --- /dev/null +++ b/tests/aiger/gold/__AND__00000.aag @@ -0,0 +1,7 @@ +aag 3 2 0 1 1 +2 +4 +6 +6 4 2 +c +Generated by Yosys diff --git a/tests/aiger/gold/__AOI3__00000.aag b/tests/aiger/gold/__AOI3__00000.aag new file mode 100644 index 000000000..a726927fe --- /dev/null +++ b/tests/aiger/gold/__AOI3__00000.aag @@ -0,0 +1,9 @@ +aag 5 3 0 1 2 +2 +4 +6 +10 +8 4 2 +10 9 7 +c +Generated by Yosys diff --git a/tests/aiger/gold/__AOI4__00000.aag b/tests/aiger/gold/__AOI4__00000.aag new file mode 100644 index 000000000..4044dc5a8 --- /dev/null +++ b/tests/aiger/gold/__AOI4__00000.aag @@ -0,0 +1,11 @@ +aag 7 4 0 1 3 +2 +4 +6 +8 +14 +10 4 2 +12 8 6 +14 13 11 +c +Generated by Yosys diff --git a/tests/aiger/gold/__BUF__00000.aag b/tests/aiger/gold/__BUF__00000.aag new file mode 100644 index 000000000..7a4cd3156 --- /dev/null +++ b/tests/aiger/gold/__BUF__00000.aag @@ -0,0 +1,5 @@ +aag 1 1 0 1 0 +2 +2 +c +Generated by Yosys diff --git a/tests/aiger/gold/__MUX__00000.aag b/tests/aiger/gold/__MUX__00000.aag new file mode 100644 index 000000000..4d1757a65 --- /dev/null +++ b/tests/aiger/gold/__MUX__00000.aag @@ -0,0 +1,10 @@ +aag 6 3 0 1 3 +2 +4 +6 +13 +8 7 2 +10 6 4 +12 11 9 +c +Generated by Yosys diff --git a/tests/aiger/gold/__NAND__00000.aag b/tests/aiger/gold/__NAND__00000.aag new file mode 100644 index 000000000..bc42187b1 --- /dev/null +++ b/tests/aiger/gold/__NAND__00000.aag @@ -0,0 +1,7 @@ +aag 3 2 0 1 1 +2 +4 +7 +6 4 2 +c +Generated by Yosys diff --git a/tests/aiger/gold/__NMUX__00000.aag b/tests/aiger/gold/__NMUX__00000.aag new file mode 100644 index 000000000..b939855f9 --- /dev/null +++ b/tests/aiger/gold/__NMUX__00000.aag @@ -0,0 +1,10 @@ +aag 6 3 0 1 3 +2 +4 +6 +12 +8 7 2 +10 6 4 +12 11 9 +c +Generated by Yosys diff --git a/tests/aiger/gold/__NOR__00000.aag b/tests/aiger/gold/__NOR__00000.aag new file mode 100644 index 000000000..30b1d6c95 --- /dev/null +++ b/tests/aiger/gold/__NOR__00000.aag @@ -0,0 +1,7 @@ +aag 3 2 0 1 1 +2 +4 +6 +6 5 3 +c +Generated by Yosys diff --git a/tests/aiger/gold/__NOT__00000.aag b/tests/aiger/gold/__NOT__00000.aag new file mode 100644 index 000000000..0c9119cea --- /dev/null +++ b/tests/aiger/gold/__NOT__00000.aag @@ -0,0 +1,5 @@ +aag 1 1 0 1 0 +2 +3 +c +Generated by Yosys diff --git a/tests/aiger/gold/__OAI3__00000.aag b/tests/aiger/gold/__OAI3__00000.aag new file mode 100644 index 000000000..9f8af1f72 --- /dev/null +++ b/tests/aiger/gold/__OAI3__00000.aag @@ -0,0 +1,9 @@ +aag 5 3 0 1 2 +2 +4 +6 +11 +8 5 3 +10 9 6 +c +Generated by Yosys diff --git a/tests/aiger/gold/__OAI4__00000.aag b/tests/aiger/gold/__OAI4__00000.aag new file mode 100644 index 000000000..871c05ba3 --- /dev/null +++ b/tests/aiger/gold/__OAI4__00000.aag @@ -0,0 +1,11 @@ +aag 7 4 0 1 3 +2 +4 +6 +8 +15 +10 5 3 +12 9 7 +14 13 11 +c +Generated by Yosys diff --git a/tests/aiger/gold/__ORNOT__00000.aag b/tests/aiger/gold/__ORNOT__00000.aag new file mode 100644 index 000000000..fc7263fce --- /dev/null +++ b/tests/aiger/gold/__ORNOT__00000.aag @@ -0,0 +1,7 @@ +aag 3 2 0 1 1 +2 +4 +7 +6 4 3 +c +Generated by Yosys diff --git a/tests/aiger/gold/__OR__00000.aag b/tests/aiger/gold/__OR__00000.aag new file mode 100644 index 000000000..d5e8085c2 --- /dev/null +++ b/tests/aiger/gold/__OR__00000.aag @@ -0,0 +1,7 @@ +aag 3 2 0 1 1 +2 +4 +7 +6 5 3 +c +Generated by Yosys diff --git a/tests/aiger/gold/__XNOR__00000.aag b/tests/aiger/gold/__XNOR__00000.aag new file mode 100644 index 000000000..18bb92393 --- /dev/null +++ b/tests/aiger/gold/__XNOR__00000.aag @@ -0,0 +1,9 @@ +aag 5 2 0 1 3 +2 +4 +11 +6 4 2 +8 5 3 +10 9 7 +c +Generated by Yosys diff --git a/tests/aiger/gold/__XOR__00000.aag b/tests/aiger/gold/__XOR__00000.aag new file mode 100644 index 000000000..ab4bc32ad --- /dev/null +++ b/tests/aiger/gold/__XOR__00000.aag @@ -0,0 +1,9 @@ +aag 5 2 0 1 3 +2 +4 +10 +6 4 2 +8 5 3 +10 9 7 +c +Generated by Yosys diff --git a/tests/aiger/gold/_add_00000.aag b/tests/aiger/gold/_add_00000.aag new file mode 100644 index 000000000..9f22bc0f3 --- /dev/null +++ b/tests/aiger/gold/_add_00000.aag @@ -0,0 +1,62 @@ +aag 51 4 0 8 47 +2 +4 +6 +8 +14 +30 +42 +54 +66 +78 +90 +102 +10 6 2 +12 7 3 +14 13 11 +16 6 2 +18 8 4 +20 9 5 +22 21 19 +24 22 16 +26 21 19 +28 27 11 +30 29 25 +32 21 16 +34 33 19 +36 35 22 +38 33 19 +40 38 27 +42 41 37 +44 35 21 +46 45 19 +48 47 22 +50 45 19 +52 50 27 +54 53 49 +56 47 21 +58 57 19 +60 59 22 +62 57 19 +64 62 27 +66 65 61 +68 59 21 +70 69 19 +72 71 22 +74 69 19 +76 74 27 +78 77 73 +80 71 21 +82 81 19 +84 83 22 +86 81 19 +88 86 27 +90 89 85 +92 83 21 +94 93 19 +96 95 22 +98 93 19 +100 98 27 +102 101 97 +c +Generated by Yosys diff --git a/tests/aiger/gold/_alu_00000.aag b/tests/aiger/gold/_alu_00000.aag new file mode 100644 index 000000000..3fdb09ea5 --- /dev/null +++ b/tests/aiger/gold/_alu_00000.aag @@ -0,0 +1,45 @@ +aag 33 5 0 9 28 +2 +4 +6 +8 +10 +27 +35 +36 +38 +40 +8 +48 +58 +66 +12 8 6 +14 9 7 +16 15 13 +18 16 2 +20 15 13 +22 21 3 +24 23 10 +26 25 19 +28 8 4 +30 9 5 +32 31 27 +34 33 29 +36 35 8 +38 23 19 +40 31 29 +42 38 10 +44 23 19 +46 45 11 +48 47 43 +50 40 27 +52 31 29 +54 25 19 +56 54 53 +58 57 51 +60 35 8 +62 33 29 +64 62 9 +66 65 61 +c +Generated by Yosys diff --git a/tests/aiger/gold/_and_00000.aag b/tests/aiger/gold/_and_00000.aag new file mode 100644 index 000000000..6d3bab8d3 --- /dev/null +++ b/tests/aiger/gold/_and_00000.aag @@ -0,0 +1,28 @@ +aag 17 11 0 8 6 +2 +4 +6 +8 +10 +12 +14 +16 +18 +20 +22 +24 +26 +28 +30 +32 +34 +34 +34 +24 14 2 +26 16 4 +28 18 6 +30 20 8 +32 22 10 +34 22 12 +c +Generated by Yosys diff --git a/tests/aiger/gold/_buf_00000.aag b/tests/aiger/gold/_buf_00000.aag new file mode 100644 index 000000000..d373a6a80 --- /dev/null +++ b/tests/aiger/gold/_buf_00000.aag @@ -0,0 +1,15 @@ +aag 6 6 0 6 0 +2 +4 +6 +8 +10 +12 +2 +4 +6 +8 +10 +12 +c +Generated by Yosys diff --git a/tests/aiger/gold/_eq_00000.aag b/tests/aiger/gold/_eq_00000.aag new file mode 100644 index 000000000..e3cbcd2fc --- /dev/null +++ b/tests/aiger/gold/_eq_00000.aag @@ -0,0 +1,46 @@ +aag 38 11 0 5 27 +2 +4 +6 +8 +10 +12 +14 +16 +18 +20 +22 +76 +0 +0 +0 +0 +24 10 2 +26 11 3 +28 27 25 +30 12 4 +32 13 5 +34 33 31 +36 35 29 +38 14 6 +40 15 7 +42 41 39 +44 43 36 +46 16 8 +48 17 9 +50 49 47 +52 51 44 +54 18 8 +56 19 9 +58 57 55 +60 59 52 +62 20 8 +64 21 9 +66 65 63 +68 67 60 +70 22 8 +72 23 9 +74 73 71 +76 75 68 +c +Generated by Yosys diff --git a/tests/aiger/gold/_ge_00000.aag b/tests/aiger/gold/_ge_00000.aag new file mode 100644 index 000000000..8ccc44797 --- /dev/null +++ b/tests/aiger/gold/_ge_00000.aag @@ -0,0 +1,9 @@ +aag 3 2 0 3 1 +2 +4 +7 +0 +0 +6 4 3 +c +Generated by Yosys diff --git a/tests/aiger/gold/_gt_00000.aag b/tests/aiger/gold/_gt_00000.aag new file mode 100644 index 000000000..cc0905ea1 --- /dev/null +++ b/tests/aiger/gold/_gt_00000.aag @@ -0,0 +1,48 @@ +aag 43 10 0 2 33 +2 +4 +6 +8 +10 +12 +14 +16 +18 +20 +86 +0 +22 20 7 +24 21 6 +26 25 23 +28 18 7 +30 16 7 +32 14 7 +34 12 7 +36 10 5 +38 9 2 +40 8 3 +42 41 38 +44 11 4 +46 45 43 +48 47 37 +50 13 6 +52 51 49 +54 53 35 +56 15 6 +58 57 55 +60 59 33 +62 17 6 +64 63 61 +66 65 31 +68 19 6 +70 69 67 +72 71 29 +74 73 25 +76 75 23 +78 77 26 +80 25 23 +82 75 23 +84 82 81 +86 85 79 +c +Generated by Yosys diff --git a/tests/aiger/gold/_le_00000.aag b/tests/aiger/gold/_le_00000.aag new file mode 100644 index 000000000..75a138267 --- /dev/null +++ b/tests/aiger/gold/_le_00000.aag @@ -0,0 +1,52 @@ +aag 47 12 0 2 35 +2 +4 +6 +8 +10 +12 +14 +16 +18 +20 +22 +24 +94 +0 +26 25 8 +28 24 9 +30 29 27 +32 23 8 +34 21 8 +36 19 8 +38 17 8 +40 15 6 +42 13 4 +44 11 2 +46 12 5 +48 47 44 +50 49 43 +52 14 7 +54 53 51 +56 55 41 +58 16 9 +60 59 57 +62 61 39 +64 18 9 +66 65 63 +68 67 37 +70 20 9 +72 71 69 +74 73 35 +76 22 9 +78 77 75 +80 79 33 +82 81 29 +84 83 27 +86 85 30 +88 29 27 +90 83 27 +92 90 89 +94 93 87 +c +Generated by Yosys diff --git a/tests/aiger/gold/_logic_and_00000.aag b/tests/aiger/gold/_logic_and_00000.aag new file mode 100644 index 000000000..d68c6fc34 --- /dev/null +++ b/tests/aiger/gold/_logic_and_00000.aag @@ -0,0 +1,30 @@ +aag 21 11 0 6 10 +2 +4 +6 +8 +10 +12 +14 +16 +18 +20 +22 +42 +0 +0 +0 +0 +0 +24 5 3 +26 24 7 +28 26 9 +30 28 11 +32 30 13 +34 17 15 +36 34 19 +38 36 21 +40 38 23 +42 41 33 +c +Generated by Yosys diff --git a/tests/aiger/gold/_logic_not_00000.aag b/tests/aiger/gold/_logic_not_00000.aag new file mode 100644 index 000000000..7798b23e9 --- /dev/null +++ b/tests/aiger/gold/_logic_not_00000.aag @@ -0,0 +1,15 @@ +aag 7 4 0 5 3 +2 +4 +6 +8 +14 +0 +0 +0 +0 +10 5 3 +12 10 7 +14 12 9 +c +Generated by Yosys diff --git a/tests/aiger/gold/_logic_or_00000.aag b/tests/aiger/gold/_logic_or_00000.aag new file mode 100644 index 000000000..12b3364d4 --- /dev/null +++ b/tests/aiger/gold/_logic_or_00000.aag @@ -0,0 +1,29 @@ +aag 21 11 0 5 10 +2 +4 +6 +8 +10 +12 +14 +16 +18 +20 +22 +43 +0 +0 +0 +0 +24 5 3 +26 24 7 +28 26 9 +30 28 11 +32 30 13 +34 17 15 +36 34 19 +38 36 21 +40 38 23 +42 40 32 +c +Generated by Yosys diff --git a/tests/aiger/gold/_lt_00000.aag b/tests/aiger/gold/_lt_00000.aag new file mode 100644 index 000000000..2169b4a53 --- /dev/null +++ b/tests/aiger/gold/_lt_00000.aag @@ -0,0 +1,43 @@ +aag 34 9 0 6 25 +2 +4 +6 +8 +10 +12 +14 +16 +18 +68 +0 +0 +0 +0 +0 +20 19 10 +22 18 11 +24 23 21 +26 19 8 +28 17 6 +30 15 4 +32 12 3 +34 13 2 +36 35 32 +38 14 5 +40 39 37 +42 41 31 +44 16 7 +46 45 43 +48 47 29 +50 18 9 +52 51 49 +54 53 27 +56 55 23 +58 57 21 +60 59 24 +62 23 21 +64 57 21 +66 64 63 +68 67 61 +c +Generated by Yosys diff --git a/tests/aiger/gold/_mux_00000.aag b/tests/aiger/gold/_mux_00000.aag new file mode 100644 index 000000000..4d1757a65 --- /dev/null +++ b/tests/aiger/gold/_mux_00000.aag @@ -0,0 +1,10 @@ +aag 6 3 0 1 3 +2 +4 +6 +13 +8 7 2 +10 6 4 +12 11 9 +c +Generated by Yosys diff --git a/tests/aiger/gold/_ne_00000.aag b/tests/aiger/gold/_ne_00000.aag new file mode 100644 index 000000000..e4d894bde --- /dev/null +++ b/tests/aiger/gold/_ne_00000.aag @@ -0,0 +1,40 @@ +aag 29 10 0 8 19 +2 +4 +6 +8 +10 +12 +14 +16 +18 +20 +59 +0 +0 +0 +0 +0 +0 +0 +22 12 2 +24 13 3 +26 25 23 +28 14 4 +30 15 5 +32 31 29 +34 33 27 +36 16 6 +38 17 7 +40 39 37 +42 41 34 +44 18 8 +46 19 9 +48 47 45 +50 49 42 +52 20 10 +54 21 11 +56 55 53 +58 57 50 +c +Generated by Yosys diff --git a/tests/aiger/gold/_not_00000.aag b/tests/aiger/gold/_not_00000.aag new file mode 100644 index 000000000..3c5ede656 --- /dev/null +++ b/tests/aiger/gold/_not_00000.aag @@ -0,0 +1,11 @@ +aag 6 6 0 2 0 +2 +4 +6 +8 +10 +12 +3 +5 +c +Generated by Yosys diff --git a/tests/aiger/gold/_or_00000.aag b/tests/aiger/gold/_or_00000.aag new file mode 100644 index 000000000..58714e461 --- /dev/null +++ b/tests/aiger/gold/_or_00000.aag @@ -0,0 +1,11 @@ +aag 6 4 0 2 2 +2 +4 +6 +8 +11 +13 +10 5 3 +12 7 3 +c +Generated by Yosys diff --git a/tests/aiger/gold/_pos_00000.aag b/tests/aiger/gold/_pos_00000.aag new file mode 100644 index 000000000..29a2dd61a --- /dev/null +++ b/tests/aiger/gold/_pos_00000.aag @@ -0,0 +1,9 @@ +aag 1 1 0 5 0 +2 +2 +2 +2 +2 +2 +c +Generated by Yosys diff --git a/tests/aiger/gold/_reduce_and_00000.aag b/tests/aiger/gold/_reduce_and_00000.aag new file mode 100644 index 000000000..06db9a1dd --- /dev/null +++ b/tests/aiger/gold/_reduce_and_00000.aag @@ -0,0 +1,7 @@ +aag 1 1 0 3 0 +2 +2 +0 +0 +c +Generated by Yosys diff --git a/tests/aiger/gold/_reduce_bool_00000.aag b/tests/aiger/gold/_reduce_bool_00000.aag new file mode 100644 index 000000000..48a1410c8 --- /dev/null +++ b/tests/aiger/gold/_reduce_bool_00000.aag @@ -0,0 +1,13 @@ +aag 7 4 0 3 3 +2 +4 +6 +8 +15 +0 +0 +10 5 3 +12 10 7 +14 12 9 +c +Generated by Yosys diff --git a/tests/aiger/gold/_reduce_or_00000.aag b/tests/aiger/gold/_reduce_or_00000.aag new file mode 100644 index 000000000..d5e8085c2 --- /dev/null +++ b/tests/aiger/gold/_reduce_or_00000.aag @@ -0,0 +1,7 @@ +aag 3 2 0 1 1 +2 +4 +7 +6 5 3 +c +Generated by Yosys diff --git a/tests/aiger/gold/_reduce_xnor_00000.aag b/tests/aiger/gold/_reduce_xnor_00000.aag new file mode 100644 index 000000000..6ad6ac39e --- /dev/null +++ b/tests/aiger/gold/_reduce_xnor_00000.aag @@ -0,0 +1,30 @@ +aag 25 6 0 2 19 +2 +4 +6 +8 +10 +12 +51 +0 +14 4 2 +16 5 3 +18 17 15 +20 18 6 +22 17 15 +24 23 7 +26 25 21 +28 26 8 +30 25 21 +32 31 9 +34 33 29 +36 34 10 +38 33 29 +40 39 11 +42 41 37 +44 42 12 +46 41 37 +48 47 13 +50 49 45 +c +Generated by Yosys diff --git a/tests/aiger/gold/_reduce_xor_00000.aag b/tests/aiger/gold/_reduce_xor_00000.aag new file mode 100644 index 000000000..ab4bc32ad --- /dev/null +++ b/tests/aiger/gold/_reduce_xor_00000.aag @@ -0,0 +1,9 @@ +aag 5 2 0 1 3 +2 +4 +10 +6 4 2 +8 5 3 +10 9 7 +c +Generated by Yosys diff --git a/tests/aiger/gold/_sub_00000.aag b/tests/aiger/gold/_sub_00000.aag new file mode 100644 index 000000000..e9d976b32 --- /dev/null +++ b/tests/aiger/gold/_sub_00000.aag @@ -0,0 +1,20 @@ +aag 16 13 0 1 3 +2 +4 +6 +8 +10 +12 +14 +16 +18 +20 +22 +24 +26 +33 +28 17 2 +30 16 3 +32 31 29 +c +Generated by Yosys diff --git a/tests/aiger/gold/_xnor_00000.aag b/tests/aiger/gold/_xnor_00000.aag new file mode 100644 index 000000000..9dd097862 --- /dev/null +++ b/tests/aiger/gold/_xnor_00000.aag @@ -0,0 +1,17 @@ +aag 10 4 0 4 6 +2 +4 +6 +8 +15 +21 +21 +21 +10 6 2 +12 7 3 +14 13 11 +16 8 4 +18 9 5 +20 19 17 +c +Generated by Yosys diff --git a/tests/aiger/gold/_xor_00000.aag b/tests/aiger/gold/_xor_00000.aag new file mode 100644 index 000000000..453b8d0ee --- /dev/null +++ b/tests/aiger/gold/_xor_00000.aag @@ -0,0 +1,12 @@ +aag 8 5 0 1 3 +2 +4 +6 +8 +10 +16 +12 8 2 +14 9 3 +16 15 13 +c +Generated by Yosys diff --git a/tests/aiger/run-test.sh b/tests/aiger/run-test.sh index ca7339ff0..94d83ede4 100755 --- a/tests/aiger/run-test.sh +++ b/tests/aiger/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh set -e @@ -57,3 +58,13 @@ for y in *.ys; do echo "Running $y." ../../yosys -ql ${y%.*}.log $y done + +# compare aigmap with reference +# make gold with: rm gold/*; yosys --no-version -p "test_cell -aigmap -w gold/ -n 1 -s 1 all" +rm -rf gate; mkdir gate +../../yosys --no-version -p "test_cell -aigmap -w gate/ -n 1 -s 1 all" +( + set -o pipefail + diff --brief gold gate | tee aigmap.err +) +rm aigmap.err diff --git a/tests/alumacc/run-test.sh b/tests/alumacc/run-test.sh index e9698386e..2e3f5235c 100644 --- a/tests/alumacc/run-test.sh +++ b/tests/alumacc/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh set -e for x in *.ys; do echo "Running $x.." diff --git a/tests/arch/run-test.sh b/tests/arch/run-test.sh index 68f925b34..7602717d2 100755 --- a/tests/arch/run-test.sh +++ b/tests/arch/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh set -e diff --git a/tests/asicworld/run-test.sh b/tests/asicworld/run-test.sh index 5131ed646..c9b4118a7 100755 --- a/tests/asicworld/run-test.sh +++ b/tests/asicworld/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh OPTIND=1 seed="" # default to no seed specified diff --git a/tests/blif/run-test.sh b/tests/blif/run-test.sh index e9698386e..2e3f5235c 100755 --- a/tests/blif/run-test.sh +++ b/tests/blif/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh set -e for x in *.ys; do echo "Running $x.." diff --git a/tests/bram/run-test.sh b/tests/bram/run-test.sh index 37fc91d0e..47f24f5dd 100755 --- a/tests/bram/run-test.sh +++ b/tests/bram/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh # run this test many times: # MAKE="make -j8" time bash -c 'for ((i=0; i<100; i++)); do echo "-- $i --"; bash run-test.sh || exit 1; done' diff --git a/tests/common-env.sh b/tests/common-env.sh new file mode 100644 index 000000000..f3a411280 --- /dev/null +++ b/tests/common-env.sh @@ -0,0 +1 @@ +export YOSYS_MAX_THREADS=4 diff --git a/tests/cxxrtl/run-test.sh b/tests/cxxrtl/run-test.sh index 4b542e180..aa7a0c26c 100755 --- a/tests/cxxrtl/run-test.sh +++ b/tests/cxxrtl/run-test.sh @@ -1,4 +1,5 @@ #!/bin/bash +source ../common-env.sh set -ex diff --git a/tests/fmt/run-test.sh b/tests/fmt/run-test.sh index 88ee6e238..a3402f953 100644 --- a/tests/fmt/run-test.sh +++ b/tests/fmt/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh set -ex diff --git a/tests/fsm/run-test.sh b/tests/fsm/run-test.sh index dc60c69c4..139ea8261 100755 --- a/tests/fsm/run-test.sh +++ b/tests/fsm/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh # run this test many times: # time bash -c 'for ((i=0; i<100; i++)); do echo "-- $i --"; bash run-test.sh || exit 1; done' diff --git a/tests/functional/run-test.sh b/tests/functional/run-test.sh index e0bedf8d4..7c38f3190 100755 --- a/tests/functional/run-test.sh +++ b/tests/functional/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) diff --git a/tests/functional/test_smtbmc_witness_mismatch.py b/tests/functional/test_smtbmc_witness_mismatch.py new file mode 100644 index 000000000..f13620f1d --- /dev/null +++ b/tests/functional/test_smtbmc_witness_mismatch.py @@ -0,0 +1,190 @@ +import json +import shutil +import subprocess +from pathlib import Path + +import pytest + +base_path = Path(__file__).resolve().parent.parent.parent + +pytestmark = pytest.mark.skipif(shutil.which("z3") is None, reason="z3 not available") + +def run(cmd, **kwargs): + """Run a command and assert it succeeds.""" + status = subprocess.run(cmd, **kwargs) + assert status.returncode == 0, f"{cmd[0]} failed" + return status + + +def write_smt2(tmp_path, verilog_text): + """Write Verilog to temp and emit SMT2 via yosys.""" + vfile = tmp_path / "design.v" + smt2 = tmp_path / "design.smt2" + vfile.write_text(verilog_text) + run([base_path / "yosys", "-Q", "-p", + f"read_verilog {vfile}; prep -top top; write_smt2 {smt2}"]) + return smt2 + + +def witness_entries(smt2_path): + """Parse yosys-smt2-witness JSON records from an SMT2 file.""" + entries = [] + marker = "yosys-smt2-witness" + with open(smt2_path, "r") as f: + for line in f: + if marker not in line: + continue + payload = line.split(marker, 1)[1].strip() + entries.append(json.loads(payload)) + return entries + + +def find_entry(entries, entry_type): + """Return the first witness entry of the given type.""" + for entry in entries: + if entry.get("type") == entry_type: + return entry + return None + + +def write_yw(yw_path, signals, bits): + """Write a minimal Yosys witness file with one step of bits.""" + data = { + "format": "Yosys Witness Trace", + "clocks": [], + "signals": signals, + "steps": [{"bits": bits}], + } + yw_path.write_text(json.dumps(data)) + + +def run_smtbmc(smt2_path, yw_path): + """Run yosys-smtbmc on the SMT2 file with a witness trace.""" + cmd = [ + base_path / "yosys-smtbmc", + "-s", "z3", + "-m", "top", + "--check-witness", + "--yw", yw_path, + "-t", "1", + smt2_path, + ] + return subprocess.run(cmd, capture_output=True, text=True) + + +def assert_no_mismatch_message(result): + """Assert the mismatch error prefix is absent from outputs.""" + combined = (result.stderr or "") + (result.stdout or "") + assert "Yosys witness signal mismatch" not in combined + + +def assert_has_mismatch_message(result, msg): + """Assert the mismatch error prefix and substring are present.""" + combined = (result.stderr or "") + (result.stdout or "") + assert "Yosys witness signal mismatch" in combined + assert msg in combined + + +def test_missing_signal_path(tmp_path): + smt2 = write_smt2(tmp_path, "module top(input ok, output out); assign out = ok; endmodule") + yw_path = tmp_path / "trace.yw" + signals = [{"path": ["\\missing"], "offset": 0, "width": 1, "init_only": False}] + write_yw(yw_path, signals, "1") + result = run_smtbmc(smt2, yw_path) + assert result.returncode != 0 + assert_has_mismatch_message(result, "signal not found in design") + + +def test_width_mismatch(tmp_path): + smt2 = write_smt2(tmp_path, "module top(input ok, output out); assign out = ok; endmodule") + entries = witness_entries(smt2) + input_entry = find_entry(entries, "input") + assert input_entry is not None + yw_path = tmp_path / "trace.yw" + signals = [{ + "path": input_entry["path"], + "offset": 0, + "width": 2, + "init_only": False, + }] + write_yw(yw_path, signals, "10") + result = run_smtbmc(smt2, yw_path) + assert result.returncode != 0 + assert_has_mismatch_message(result, "signal width/offset mismatch") + + +def test_memory_address_oob(tmp_path): + verilog = """ +module top(input ok, output [7:0] mem_out); + reg [7:0] mem [0:1]; + assign mem_out = mem[0] ^ {8{ok}}; +endmodule +""" + smt2 = write_smt2(tmp_path, verilog) + entries = witness_entries(smt2) + mem_entry = find_entry(entries, "mem") + assert mem_entry is not None + addr = mem_entry["size"] + yw_path = tmp_path / "trace.yw" + signals = [{ + "path": mem_entry["path"] + [f"\\[{addr}]"], + "offset": 0, + "width": mem_entry["width"], + "init_only": False, + }] + bits = "0" * mem_entry["width"] + write_yw(yw_path, signals, bits) + result = run_smtbmc(smt2, yw_path) + assert result.returncode != 0 + assert_has_mismatch_message(result, "memory address out of bounds") + + +def test_allowed_extra_signal_in_design(tmp_path): + verilog = """ +module top(input ok, input extra, output [1:0] out); + assign out = {ok, extra}; +endmodule +""" + smt2 = write_smt2(tmp_path, verilog) + entries = witness_entries(smt2) + input_entry = find_entry(entries, "input") + assert input_entry is not None + yw_path = tmp_path / "trace.yw" + signals = [{ + "path": input_entry["path"], + "offset": 0, + "width": input_entry["width"], + "init_only": False, + }] + bits = "0" * input_entry["width"] + write_yw(yw_path, signals, bits) + result = run_smtbmc(smt2, yw_path) + # With --check-witness and no assertions, smtbmc can still exit non-zero. + # Thus we don't check the result.returncode here and in the other success + # cases. + assert_no_mismatch_message(result) + + +def test_allowed_extra_memory_in_design(tmp_path): + verilog = """ +module top(input ok, output [7:0] out); + reg [7:0] mem0 [0:1]; + reg [7:0] mem1 [0:3]; + assign out = mem0[0] ^ mem1[0]; +endmodule +""" + smt2 = write_smt2(tmp_path, verilog) + entries = witness_entries(smt2) + input_entry = find_entry(entries, "input") + assert input_entry is not None + yw_path = tmp_path / "trace.yw" + signals = [{ + "path": input_entry["path"], + "offset": 0, + "width": input_entry["width"], + "init_only": False, + }] + bits = "1" * input_entry["width"] + write_yw(yw_path, signals, bits) + result = run_smtbmc(smt2, yw_path) + assert_no_mismatch_message(result) diff --git a/tests/gen-tests-makefile.sh b/tests/gen-tests-makefile.sh index e3308506b..a0fb23ac3 100755 --- a/tests/gen-tests-makefile.sh +++ b/tests/gen-tests-makefile.sh @@ -9,7 +9,7 @@ generate_target() { echo "all: $target_name" echo ".PHONY: $target_name" echo "$target_name:" - printf "\t@%s\n" "$test_command" + printf "\t@YOSYS_MAX_THREADS=4 %s\n" "$test_command" printf "\t@echo 'Passed %s'\n" "$target_name" } diff --git a/tests/hana/run-test.sh b/tests/hana/run-test.sh index 99be37f5e..8533e5544 100755 --- a/tests/hana/run-test.sh +++ b/tests/hana/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh OPTIND=1 seed="" # default to no seed specified diff --git a/tests/liberty/run-test.sh b/tests/liberty/run-test.sh index 5afdb727e..d5fb65e16 100755 --- a/tests/liberty/run-test.sh +++ b/tests/liberty/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh set -eo pipefail for x in *.lib; do diff --git a/tests/memfile/run-test.sh b/tests/memfile/run-test.sh index db0ec54ee..44c1e4821 100755 --- a/tests/memfile/run-test.sh +++ b/tests/memfile/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh set -e diff --git a/tests/memlib/run-test.sh b/tests/memlib/run-test.sh index 5f230a03e..9e95fb255 100755 --- a/tests/memlib/run-test.sh +++ b/tests/memlib/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh set -eu OPTIND=1 diff --git a/tests/memories/run-test.sh b/tests/memories/run-test.sh index 4f1da7ce7..8f83e11a1 100755 --- a/tests/memories/run-test.sh +++ b/tests/memories/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh set -e diff --git a/tests/opt/opt_expr_combined_assign.ys b/tests/opt/opt_expr_combined_assign.ys index b18923c7b..823ca959a 100644 --- a/tests/opt/opt_expr_combined_assign.ys +++ b/tests/opt/opt_expr_combined_assign.ys @@ -1,11 +1,12 @@ read_verilog -sv < Y) = 453; + (D1 => Y) = 449; + (D2 => Y) = 488; + (D3 => Y) = 484; + (S0 => Y) = 422; + (S1 => Y) = 385; + endspecify + + assign Y = S1 ? (S0 ? D3 : D2) : + (S0 ? D1 : D0); + +endmodule + +EOF + +logger -expect error "Malformed design" 1 +abc_new -script abc_speed_gia_only.script -liberty ../../tests/liberty/normal.lib -liberty ../../tests/liberty/dff.lib diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh index 47b06d575..c9a12b66b 100755 --- a/tests/tools/autotest.sh +++ b/tests/tools/autotest.sh @@ -162,20 +162,24 @@ do cp ../${bn}_tb.v ${bn}_tb.v fi if $genvcd; then sed -i 's,// \$dump,$dump,g' ${bn}_tb.v; fi + touch ${bn}.iverilog compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.${refext} "${libs[@]}" \ "$toolsdir"/../../techlibs/common/simlib.v \ "$toolsdir"/../../techlibs/common/simcells.v + rm ${bn}.iverilog if $genvcd; then mv testbench.vcd ${bn}_ref.vcd; fi test_count=0 test_passes() { "$toolsdir"/../../yosys -b "verilog $backend_opts" -o ${bn}_syn${test_count}.v "$@" + touch ${bn}.iverilog compile_and_run ${bn}_tb_syn${test_count} ${bn}_out_syn${test_count} \ ${bn}_tb.v ${bn}_syn${test_count}.v "${libs[@]}" \ "$toolsdir"/../../techlibs/common/simlib.v \ "$toolsdir"/../../techlibs/common/simcells.v if $genvcd; then mv testbench.vcd ${bn}_syn${test_count}.vcd; fi "$toolsdir/cmp_tbdata" ${bn}_out_ref ${bn}_out_syn${test_count} + rm ${bn}.iverilog test_count=$(( test_count + 1 )) } @@ -227,7 +231,9 @@ do else echo "${status_prefix}${did_firrtl}-> ERROR!" if $warn_iverilog_git; then - echo "Note: Make sure that 'iverilog' is an up-to-date git checkout of Icarus Verilog." + if [ -f ${bn}.out/${bn}.iverilog ]; then + echo "Note: Make sure that 'iverilog' is an up-to-date git checkout of Icarus Verilog." + fi fi $keeprunning || exit 1 fi diff --git a/tests/tools/rtlil-fuzz-grammar.json b/tests/tools/rtlil-fuzz-grammar.json new file mode 100644 index 000000000..c27b160f4 --- /dev/null +++ b/tests/tools/rtlil-fuzz-grammar.json @@ -0,0 +1,104 @@ +{ + "": [ + [ + "module \\test\n", + "", "", + "", + "", + "end\n" + ] + ], + "": [ [ " wire width ", "", " ", "", " ", "", "\n" ] ], + "": [ [ "1" ], [ "2" ], [ "3" ], [ "4" ], [ "32" ], [ "128" ] ], + "": [ [ "input ", "" ], [ "output ", "" ], [ "inout ", "" ], [] ], + "": [ + [ + " cell $not ", "", "\n", + " parameter \\A_SIGNED 0\n", + " parameter \\A_WIDTH 0\n", + " parameter \\Y_WIDTH 0\n", + " connect \\A ", "", "\n", + " connect \\Y ", "", "\n", + " end\n" + ], + [ + " cell $and ", "", "\n", + " parameter \\A_SIGNED 0\n", + " parameter \\B_SIGNED 0\n", + " parameter \\A_WIDTH 0\n", + " parameter \\B_WIDTH 0\n", + " parameter \\Y_WIDTH 0\n", + " connect \\A ", "", "\n", + " connect \\B ", "", "\n", + " connect \\Y ", "", "\n", + " end\n" + ], + [ + " cell $or ", "", "\n", + " parameter \\A_SIGNED 0\n", + " parameter \\B_SIGNED 0\n", + " parameter \\A_WIDTH 0\n", + " parameter \\B_WIDTH 0\n", + " parameter \\Y_WIDTH 0\n", + " connect \\A ", "", "\n", + " connect \\B ", "", "\n", + " connect \\Y ", "", "\n", + " end\n" + ], + [ + " cell $xor ", "", "\n", + " parameter \\A_SIGNED 0\n", + " parameter \\B_SIGNED 0\n", + " parameter \\A_WIDTH 0\n", + " parameter \\B_WIDTH 0\n", + " parameter \\Y_WIDTH 0\n", + " connect \\A ", "", "\n", + " connect \\B ", "", "\n", + " connect \\Y ", "", "\n", + " end\n" + ], + [ + " cell ", "", " ", "", "\n", + " connect \\A ", "", "\n", + " connect \\Y ", "", "\n", + " end\n" + ], + [ + " cell ", "", " ", "", "\n", + " connect \\A ", "", "\n", + " connect \\B ", "", "\n", + " connect \\Y ", "", "\n", + " end\n" + ] + ], + "": [ [ "\\wire_a" ], [ "\\wire_b" ], [ "\\wire_c" ], [ "\\wire_d" ], [ "\\wire_e" ], [ "\\wire_f" ], [ "\\wire_g" ], [ "\\wire_h" ], [ "\\wire_i" ], [ "\\wire_j" ] ], + "": [ [ "\\cell_a" ], [ "\\cell_b" ], [ "\\cell_c" ], [ "\\cell_d" ], [ "\\cell_e" ], [ "\\cell_f" ], [ "\\cell_g" ], [ "\\cell_h" ], [ "\\cell_i" ], [ "\\cell_j" ] ], + "": [ [ "\\bb1" ], [ "\\bb2" ] ], + "": [ + [ "", " " ], + [ "{", "", " ", "", "}" ], + [ "" ], + [ "", "[", "", "]" ], + [ "", "[", "", ":", "", "]" ] + ], + "": [ + [ "0'", "" ], + [ "1'", "" ], + [ "2'", "" ], + [ "3'", "" ], + [ "4'", "" ], + [ "31'", "" ], + [ "32'", "" ], + [ "128'", "" ] + ], + "": [ [ "0" ], [ "1" ], [ "x" ], [ "z" ], [ "-" ], [ "m" ] ], + "": [ "0", "1", "2", "3", "31", "32" ], + "": [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" ], + "": [ [ " connect ", "", " ", "", "\n" ] ], + + "": [ [ ], [ "", "" ] ], + "": [ [ ], [ "", "" ] ], + "": [ [ ], [ "", "" ] ], + "": [ [ ], [ "", "" ] ], + "": [ [ ], [ "", " ", "" ] ] +} diff --git a/tests/various/design_equal_fail.ys b/tests/various/design_equal_fail.ys new file mode 100644 index 000000000..330d8d838 --- /dev/null +++ b/tests/various/design_equal_fail.ys @@ -0,0 +1,22 @@ +logger -expect error "Second design missing module top_renamed" 1 + +read_rtlil < run-test.mk.tmp && mv run-test.mk.tmp run-test.mk diff --git a/tests/verilog/.gitignore b/tests/verilog/.gitignore index b16ed0890..6a226989c 100644 --- a/tests/verilog/.gitignore +++ b/tests/verilog/.gitignore @@ -1,3 +1,4 @@ +/bug5572.v /const_arst.v /const_sr.v /doubleslash.v diff --git a/tests/verilog/bug5572.ys b/tests/verilog/bug5572.ys new file mode 100644 index 000000000..3044e3572 --- /dev/null +++ b/tests/verilog/bug5572.ys @@ -0,0 +1,15 @@ +read_rtlil << EOT +module \top + wire \sig + wire \val + process $2 + attribute \full_case 1 + switch \sig + end + end +end +EOT + +write_verilog bug5572.v +design -reset +read_verilog bug5572.v diff --git a/tests/verilog/genblk_wire.sv b/tests/verilog/genblk_wire.sv new file mode 100644 index 000000000..ef95fa98a --- /dev/null +++ b/tests/verilog/genblk_wire.sv @@ -0,0 +1,20 @@ +module gold(a, b); + output wire [1:0] a; + input wire [1:0] b; + genvar i; + for (i = 0; i < 2; i++) begin + wire x; + assign x = b[i]; + assign a[i] = x; + end +endmodule + +module gate(a, b); + output wire [1:0] a; + input wire [1:0] b; + genvar i; + for (i = 0; i < 2; i++) begin + assign x = b[i]; + assign a[i] = x; + end +endmodule diff --git a/tests/verilog/genblk_wire.ys b/tests/verilog/genblk_wire.ys new file mode 100644 index 000000000..582303760 --- /dev/null +++ b/tests/verilog/genblk_wire.ys @@ -0,0 +1,17 @@ +logger -expect warning "Identifier `\\genblk1[[]0[]]\.x' is implicitly declared." 1 +logger -expect warning "Identifier `\\genblk1[[]1[]]\.x' is implicitly declared." 1 +read_verilog -sv genblk_wire.sv +logger -check-expected + +select -assert-count 1 gate/genblk1[0].x +select -assert-count 1 gate/genblk1[1].x +select -assert-count 0 gate/genblk1[2].x + +select -assert-count 1 gold/genblk1[0].x +select -assert-count 1 gold/genblk1[1].x +select -assert-count 0 gold/genblk1[2].x + +proc +equiv_make gold gate equiv +equiv_simple +equiv_status -assert diff --git a/tests/xprop/run-test.sh b/tests/xprop/run-test.sh index 84b7c4ac4..303c0bb3b 100755 --- a/tests/xprop/run-test.sh +++ b/tests/xprop/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh set -e python3 generate.py $@