diff --git a/.gitignore b/.gitignore index 49b886e7e..9b799c1f3 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *.gch *.gcda *.gcno +*~ __pycache__ /.cproject /.project diff --git a/CHANGELOG b/CHANGELOG index 465918a36..ee5f6b43d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,9 +2,33 @@ List of major changes and improvements between releases ======================================================= -Yosys 0.33 .. Yosys 0.34-dev +Yosys 0.34 .. Yosys 0.35-dev -------------------------- +Yosys 0.33 .. Yosys 0.34 +-------------------------- + * New commands and options + - Added option "-assert" to "sim" pass. + - Added option "-noinitstate" to "sim" pass. + - Added option "-dont_use" to "abc" pass. + - Added "dft_tag" pass to create tagging logic for data flow tracking. + - Added "future" pass to resolve future sampled value functions. + - Added "booth" pass to map $mul cells to Booth multipliers. + - Added option "-booth" to "synth" pass. + + * SystemVerilog + - Added support for assignments within expressions, e.g., `x[y++] = z;` or + `x = (y *= 2) - 1;`. + + * Verific support + - "src" attribute contain full location info. + - module parameters are kept after import. + - accurate access order semantics in memory inference. + - better "bind" support for mixed language projects. + + * Various + - "show" command displays dot instead of box for wire aliases. + Yosys 0.32 .. Yosys 0.33 -------------------------- * Various diff --git a/Makefile b/Makefile index 62485f150..0b8cb96dd 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.33+34 +YOSYS_VER := 0.34+55 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo @@ -157,7 +157,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: - sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 2584903.. | wc -l`/;" Makefile + sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 4a1b559.. | wc -l`/;" Makefile # set 'ABCREV = default' to use abc/ as it is # @@ -165,7 +165,7 @@ bumpversion: # is just a symlink to your actual ABC working directory, as 'make mrproper' # will remove the 'abc' directory and you do not want to accidentally # delete your work on ABC.. -ABCREV = daad9ed +ABCREV = 896e5e7 ABCPULL = 1 ABCURL ?= https://github.com/YosysHQ/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) @@ -357,7 +357,7 @@ CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s LDLIBS := $(filter-out -lrt,$(LDLIBS)) ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w" -ABCMKARGS += LIBS="-lpthread -s" ABC_USE_NO_READLINE=0 CC="i686-w64-mingw32-gcc" CXX="$(CXX)" +ABCMKARGS += LIBS="-lpthread -lshlwapi -s" ABC_USE_NO_READLINE=0 CC="i686-w64-mingw32-gcc" CXX="$(CXX)" EXE = .exe else ifeq ($(CONFIG),msys2-64) @@ -368,7 +368,7 @@ CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s LDLIBS := $(filter-out -lrt,$(LDLIBS)) ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w" -ABCMKARGS += LIBS="-lpthread -s" ABC_USE_NO_READLINE=0 CC="x86_64-w64-mingw32-gcc" CXX="$(CXX)" +ABCMKARGS += LIBS="-lpthread -lshlwapi -s" ABC_USE_NO_READLINE=0 CC="x86_64-w64-mingw32-gcc" CXX="$(CXX)" EXE = .exe else ifneq ($(CONFIG),none) diff --git a/README.md b/README.md index 7e6aba22b..b95397c67 100644 --- a/README.md +++ b/README.md @@ -592,6 +592,8 @@ from SystemVerilog: - SystemVerilog interfaces (SVIs) are supported. Modports for specifying whether ports are inputs or outputs are supported. +- Assignments within expressions are supported. + Building the documentation ========================== diff --git a/backends/cxxrtl/cxxrtl.h b/backends/cxxrtl/cxxrtl.h index 8f5e4035a..b2871ee19 100644 --- a/backends/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/cxxrtl.h @@ -1019,14 +1019,14 @@ struct metadata { // In debug mode, using the wrong .as_*() function will assert. // In release mode, using the wrong .as_*() function will safely return a default value. - const unsigned uint_value = 0; - const signed sint_value = 0; + const uint64_t uint_value = 0; + const int64_t sint_value = 0; const std::string string_value = ""; const double double_value = 0.0; metadata() : value_type(MISSING) {} - metadata(unsigned value) : value_type(UINT), uint_value(value) {} - metadata(signed value) : value_type(SINT), sint_value(value) {} + metadata(uint64_t value) : value_type(UINT), uint_value(value) {} + metadata(int64_t value) : value_type(SINT), sint_value(value) {} metadata(const std::string &value) : value_type(STRING), string_value(value) {} metadata(const char *value) : value_type(STRING), string_value(value) {} metadata(double value) : value_type(DOUBLE), double_value(value) {} @@ -1034,12 +1034,12 @@ struct metadata { metadata(const metadata &) = default; metadata &operator=(const metadata &) = delete; - unsigned as_uint() const { + uint64_t as_uint() const { assert(value_type == UINT); return uint_value; } - signed as_sint() const { + int64_t as_sint() const { assert(value_type == SINT); return sint_value; } @@ -1068,6 +1068,9 @@ using debug_outline = ::_cxxrtl_outline; // // To avoid violating strict aliasing rules, this structure has to be a subclass of the one used // in the C API, or it would not be possible to cast between the pointers to these. +// +// The `attrs` member cannot be owned by this structure because a `cxxrtl_object` can be created +// from external C code. struct debug_item : ::cxxrtl_object { // Object types. enum : uint32_t { @@ -1103,6 +1106,7 @@ struct debug_item : ::cxxrtl_object { curr = item.data; next = item.data; outline = nullptr; + attrs = nullptr; } template @@ -1118,6 +1122,7 @@ struct debug_item : ::cxxrtl_object { curr = const_cast(item.data); next = nullptr; outline = nullptr; + attrs = nullptr; } template @@ -1134,6 +1139,7 @@ struct debug_item : ::cxxrtl_object { curr = item.curr.data; next = item.next.data; outline = nullptr; + attrs = nullptr; } template @@ -1149,6 +1155,7 @@ struct debug_item : ::cxxrtl_object { curr = item.data ? item.data[0].data : nullptr; next = nullptr; outline = nullptr; + attrs = nullptr; } template @@ -1164,6 +1171,7 @@ struct debug_item : ::cxxrtl_object { curr = const_cast(item.data); next = nullptr; outline = nullptr; + attrs = nullptr; } template @@ -1180,6 +1188,7 @@ struct debug_item : ::cxxrtl_object { curr = const_cast(item.curr.data); next = nullptr; outline = nullptr; + attrs = nullptr; } template @@ -1195,6 +1204,7 @@ struct debug_item : ::cxxrtl_object { curr = const_cast(item.data); next = nullptr; outline = &group; + attrs = nullptr; } template @@ -1215,10 +1225,28 @@ struct debug_item : ::cxxrtl_object { }; static_assert(std::is_standard_layout::value, "debug_item is not compatible with C layout"); +} // namespace cxxrtl + +typedef struct _cxxrtl_attr_set { + cxxrtl::metadata_map map; +} *cxxrtl_attr_set; + +namespace cxxrtl { + +// Representation of an attribute set in the C++ interface. +using debug_attrs = ::_cxxrtl_attr_set; + struct debug_items { std::map> table; + std::map> attrs_table; - void add(const std::string &name, debug_item &&item) { + void add(const std::string &name, debug_item &&item, metadata_map &&item_attrs = {}) { + std::unique_ptr &attrs = attrs_table[name]; + if (attrs.get() == nullptr) + attrs = std::unique_ptr(new debug_attrs); + for (auto attr : item_attrs) + attrs->map.insert(attr); + item.attrs = attrs.get(); std::vector &parts = table[name]; parts.emplace_back(item); std::sort(parts.begin(), parts.end(), @@ -1246,6 +1274,10 @@ struct debug_items { const debug_item &operator [](const std::string &name) const { return at(name); } + + const metadata_map &attrs(const std::string &name) const { + return attrs_table.at(name)->map; + } }; // Tag class to disambiguate the default constructor used by the toplevel module that calls reset(), diff --git a/backends/cxxrtl/cxxrtl_backend.cc b/backends/cxxrtl/cxxrtl_backend.cc index 7696ae574..3fd4857bd 100644 --- a/backends/cxxrtl/cxxrtl_backend.cc +++ b/backends/cxxrtl/cxxrtl_backend.cc @@ -2120,6 +2120,46 @@ struct CxxrtlWorker { dec_indent(); } + void dump_metadata_map(const dict &metadata_map) + { + if (metadata_map.empty()) { + f << "metadata_map()"; + return; + } + f << "metadata_map({\n"; + inc_indent(); + for (auto metadata_item : metadata_map) { + if (!metadata_item.first.isPublic()) + continue; + if (metadata_item.second.size() > 64 && (metadata_item.second.flags & RTLIL::CONST_FLAG_STRING) == 0) { + f << indent << "/* attribute " << metadata_item.first.str().substr(1) << " is over 64 bits wide */"; + continue; + } + f << indent << "{ " << escape_cxx_string(metadata_item.first.str().substr(1)) << ", "; + // In Yosys, a real is a type of string. + if (metadata_item.second.flags & RTLIL::CONST_FLAG_REAL) { + f << std::showpoint << std::stod(metadata_item.second.decode_string()) << std::noshowpoint; + } else if (metadata_item.second.flags & RTLIL::CONST_FLAG_STRING) { + f << escape_cxx_string(metadata_item.second.decode_string()); + } else if (metadata_item.second.flags & RTLIL::CONST_FLAG_SIGNED) { + f << "INT64_C(" << metadata_item.second.as_int(/*is_signed=*/true) << ")"; + } else { + f << "UINT64_C(" << metadata_item.second.as_int(/*is_signed=*/false) << ")"; + } + f << " },\n"; + } + dec_indent(); + f << indent << "})"; + } + + void dump_debug_attrs(const RTLIL::AttrObject *object) + { + dict attributes = object->attributes; + // Inherently necessary to get access to the object, so a waste of space to emit. + attributes.erase(ID::hdlname); + dump_metadata_map(attributes); + } + void dump_debug_info_method(RTLIL::Module *module) { size_t count_public_wires = 0; @@ -2205,7 +2245,9 @@ struct CxxrtlWorker { } f << "debug_item::" << flag; } - f << "));\n"; + f << "), "; + dump_debug_attrs(wire); + f << ");\n"; count_member_wires++; break; } @@ -2220,7 +2262,9 @@ struct CxxrtlWorker { f << "debug_eval_outline"; else f << "debug_alias()"; - f << ", " << mangle(aliasee) << ", " << wire->start_offset << "));\n"; + f << ", " << mangle(aliasee) << ", " << wire->start_offset << "), "; + dump_debug_attrs(aliasee); + f << ");\n"; count_alias_wires++; break; } @@ -2230,14 +2274,18 @@ struct CxxrtlWorker { dump_const(debug_wire_type.sig_subst.as_const()); f << ";\n"; f << indent << "items.add(path + " << escape_cxx_string(get_hdl_name(wire)); - f << ", debug_item(const_" << mangle(wire) << ", " << wire->start_offset << "));\n"; + f << ", debug_item(const_" << mangle(wire) << ", " << wire->start_offset << "), "; + dump_debug_attrs(wire); + f << ");\n"; count_const_wires++; break; } case WireType::OUTLINE: { // Localized or inlined, but rematerializable wire f << indent << "items.add(path + " << escape_cxx_string(get_hdl_name(wire)); - f << ", debug_item(debug_eval_outline, " << mangle(wire) << ", " << wire->start_offset << "));\n"; + f << ", debug_item(debug_eval_outline, " << mangle(wire) << ", " << wire->start_offset << "), "; + dump_debug_attrs(wire); + f << ");\n"; count_inline_wires++; break; } @@ -2254,7 +2302,13 @@ struct CxxrtlWorker { continue; f << indent << "items.add(path + " << escape_cxx_string(mem.packed ? get_hdl_name(mem.cell) : get_hdl_name(mem.mem)); f << ", debug_item(" << mangle(&mem) << ", "; - f << mem.start_offset << "));\n"; + f << mem.start_offset << "), "; + if (mem.packed) { + dump_debug_attrs(mem.cell); + } else { + dump_debug_attrs(mem.mem); + } + f << ");\n"; } for (auto cell : module->cells()) { if (is_internal_cell(cell->type)) @@ -2282,33 +2336,6 @@ struct CxxrtlWorker { } } - void dump_metadata_map(const dict &metadata_map) - { - if (metadata_map.empty()) { - f << "metadata_map()"; - return; - } - f << "metadata_map({\n"; - inc_indent(); - for (auto metadata_item : metadata_map) { - if (!metadata_item.first.begins_with("\\")) - continue; - f << indent << "{ " << escape_cxx_string(metadata_item.first.str().substr(1)) << ", "; - if (metadata_item.second.flags & RTLIL::CONST_FLAG_REAL) { - f << std::showpoint << std::stod(metadata_item.second.decode_string()) << std::noshowpoint; - } else if (metadata_item.second.flags & RTLIL::CONST_FLAG_STRING) { - f << escape_cxx_string(metadata_item.second.decode_string()); - } else { - f << metadata_item.second.as_int(/*is_signed=*/metadata_item.second.flags & RTLIL::CONST_FLAG_SIGNED); - if (!(metadata_item.second.flags & RTLIL::CONST_FLAG_SIGNED)) - f << "u"; - } - f << " },\n"; - } - dec_indent(); - f << indent << "})"; - } - void dump_module_intf(RTLIL::Module *module) { dump_attrs(module); diff --git a/backends/cxxrtl/cxxrtl_capi.cc b/backends/cxxrtl/cxxrtl_capi.cc index 227173ba8..d50ddcd69 100644 --- a/backends/cxxrtl/cxxrtl_capi.cc +++ b/backends/cxxrtl/cxxrtl_capi.cc @@ -90,3 +90,46 @@ void cxxrtl_enum(cxxrtl_handle handle, void *data, void cxxrtl_outline_eval(cxxrtl_outline outline) { outline->eval(); } + +int cxxrtl_attr_type(cxxrtl_attr_set attrs_, const char *name) { + auto attrs = (cxxrtl::metadata_map*)attrs_; + if (!attrs->count(name)) + return CXXRTL_ATTR_NONE; + switch (attrs->at(name).value_type) { + case cxxrtl::metadata::UINT: + return CXXRTL_ATTR_UNSIGNED_INT; + case cxxrtl::metadata::SINT: + return CXXRTL_ATTR_SIGNED_INT; + case cxxrtl::metadata::STRING: + return CXXRTL_ATTR_STRING; + case cxxrtl::metadata::DOUBLE: + return CXXRTL_ATTR_DOUBLE; + default: + // Present unsupported attribute type the same way as no attribute at all. + return CXXRTL_ATTR_NONE; + } +} + +uint64_t cxxrtl_attr_get_unsigned_int(cxxrtl_attr_set attrs_, const char *name) { + auto &attrs = *(cxxrtl::metadata_map*)attrs_; + assert(attrs.count(name) && attrs.at(name).value_type == cxxrtl::metadata::UINT); + return attrs[name].as_uint(); +} + +int64_t cxxrtl_attr_get_signed_int(cxxrtl_attr_set attrs_, const char *name) { + auto &attrs = *(cxxrtl::metadata_map*)attrs_; + assert(attrs.count(name) && attrs.at(name).value_type == cxxrtl::metadata::SINT); + return attrs[name].as_sint(); +} + +const char *cxxrtl_attr_get_string(cxxrtl_attr_set attrs_, const char *name) { + auto &attrs = *(cxxrtl::metadata_map*)attrs_; + assert(attrs.count(name) && attrs.at(name).value_type == cxxrtl::metadata::STRING); + return attrs[name].as_string().c_str(); +} + +double cxxrtl_attr_get_double(cxxrtl_attr_set attrs_, const char *name) { + auto &attrs = *(cxxrtl::metadata_map*)attrs_; + assert(attrs.count(name) && attrs.at(name).value_type == cxxrtl::metadata::DOUBLE); + return attrs[name].as_double(); +} diff --git a/backends/cxxrtl/cxxrtl_capi.h b/backends/cxxrtl/cxxrtl_capi.h index 2df2b7287..e5c84bf65 100644 --- a/backends/cxxrtl/cxxrtl_capi.h +++ b/backends/cxxrtl/cxxrtl_capi.h @@ -249,6 +249,15 @@ struct cxxrtl_object { // this field to NULL. struct _cxxrtl_outline *outline; + // Opaque reference to an attribute set. + // + // See the documentation of `cxxrtl_attr_set` for details. When creating a `cxxrtl_object`, set + // this field to NULL. + // + // The lifetime of the pointers returned by `cxxrtl_attr_*` family of functions is the same as + // the lifetime of this structure. + struct _cxxrtl_attr_set *attrs; + // More description fields may be added in the future, but the existing ones will never change. }; @@ -304,6 +313,62 @@ typedef struct _cxxrtl_outline *cxxrtl_outline; // re-evaluated, otherwise the bits read from that object are meaningless. void cxxrtl_outline_eval(cxxrtl_outline outline); +// Opaque reference to an attribute set. +// +// An attribute set is a map between attribute names (always strings) and values (which may have +// several different types). To find out the type of an attribute, use `cxxrtl_attr_type`, and +// to retrieve the value of an attribute, use `cxxrtl_attr_as_string`. +typedef struct _cxxrtl_attr_set *cxxrtl_attr_set; + +// Type of an attribute. +enum cxxrtl_attr_type { + // Attribute is not present. + CXXRTL_ATTR_NONE = 0, + + // Attribute has an unsigned integer value. + CXXRTL_ATTR_UNSIGNED_INT = 1, + + // Attribute has an unsigned integer value. + CXXRTL_ATTR_SIGNED_INT = 2, + + // Attribute has a string value. + CXXRTL_ATTR_STRING = 3, + + // Attribute has a double precision floating point value. + CXXRTL_ATTR_DOUBLE = 4, + + // More attribute types may be defined in the future, but the existing values will never change. +}; + +// Determine the presence and type of an attribute in an attribute set. +// +// This function returns one of the possible `cxxrtl_attr_type` values. +int cxxrtl_attr_type(cxxrtl_attr_set attrs, const char *name); + +// Retrieve an unsigned integer valued attribute from an attribute set. +// +// This function asserts that `cxxrtl_attr_type(attrs, name) == CXXRTL_ATTR_UNSIGNED_INT`. +// If assertions are disabled, returns 0 if the attribute is missing or has an incorrect type. +uint64_t cxxrtl_attr_get_unsigned_int(cxxrtl_attr_set attrs, const char *name); + +// Retrieve a signed integer valued attribute from an attribute set. +// +// This function asserts that `cxxrtl_attr_type(attrs, name) == CXXRTL_ATTR_SIGNED_INT`. +// If assertions are disabled, returns 0 if the attribute is missing or has an incorrect type. +int64_t cxxrtl_attr_get_signed_int(cxxrtl_attr_set attrs, const char *name); + +// Retrieve a string valued attribute from an attribute set. The returned string is zero-terminated. +// +// This function asserts that `cxxrtl_attr_type(attrs, name) == CXXRTL_ATTR_STRING`. If assertions +// are disabled, returns NULL if the attribute is missing or has an incorrect type. +const char *cxxrtl_attr_get_string(cxxrtl_attr_set attrs, const char *name); + +// Retrieve a double precision floating point valued attribute from an attribute set. +// +// This function asserts that `cxxrtl_attr_type(attrs, name) == CXXRTL_ATTR_DOUBLE`. If assertions +// are disabled, returns NULL if the attribute is missing or has an incorrect type. +double cxxrtl_attr_get_double(cxxrtl_attr_set attrs, const char *name); + #ifdef __cplusplus } #endif diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 7099c18c3..735672a43 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -2008,6 +2008,11 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw dump_case_body(f, indent + " ", *it); } + if (sw->cases.empty()) { + // Verilog does not allow empty cases. + f << stringf("%s default: ;\n", indent.c_str()); + } + f << stringf("%s" "endcase\n", indent.c_str()); } diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index a027295e9..5335a3992 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -229,6 +229,10 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch id2ast = NULL; basic_prep = false; lookahead = false; + in_lvalue_from_above = false; + in_param_from_above = false; + in_lvalue = false; + in_param = false; if (child1) children.push_back(child1); @@ -238,6 +242,8 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch children.push_back(child3); if (child4) children.push_back(child4); + + fixup_hierarchy_flags(); } // create a (deep recursive) copy of a node @@ -249,6 +255,10 @@ AstNode *AstNode::clone() const it = it->clone(); for (auto &it : that->attributes) it.second = it.second->clone(); + + that->set_in_lvalue_flag(false); + that->set_in_param_flag(false); + that->fixup_hierarchy_flags(); // fixup to set flags on cloned children return that; } @@ -256,10 +266,13 @@ AstNode *AstNode::clone() const void AstNode::cloneInto(AstNode *other) const { AstNode *tmp = clone(); + tmp->in_lvalue_from_above = other->in_lvalue_from_above; + tmp->in_param_from_above = other->in_param_from_above; other->delete_children(); *other = *tmp; tmp->children.clear(); tmp->attributes.clear(); + other->fixup_hierarchy_flags(); delete tmp; } @@ -351,6 +364,10 @@ void AstNode::dumpAst(FILE *f, std::string indent) const if (is_enum) { fprintf(f, " type=enum"); } + if (in_lvalue) + fprintf(f, " in_lvalue"); + if (in_param) + fprintf(f, " in_param"); fprintf(f, "\n"); for (auto &it : attributes) { @@ -1061,7 +1078,7 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d // simplify this module or interface using the current design as context // for lookup up ports and wires within cells set_simplify_design_context(design); - while (ast->simplify(!flag_noopt, false, 0, -1, false, false)) { } + while (ast->simplify(!flag_noopt, 0, -1, false)) { } set_simplify_design_context(nullptr); if (flag_dump_ast2) { @@ -1091,7 +1108,7 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d ast->attributes.erase(ID::whitebox); } AstNode *n = ast->attributes.at(ID::lib_whitebox); - ast->attributes[ID::whitebox] = n; + ast->set_attribute(ID::whitebox, n); ast->attributes.erase(ID::lib_whitebox); } } @@ -1150,7 +1167,7 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d ast->children.swap(new_children); if (ast->attributes.count(ID::blackbox) == 0) { - ast->attributes[ID::blackbox] = AstNode::mkconst_int(1, false); + ast->set_attribute(ID::blackbox, AstNode::mkconst_int(1, false)); } } @@ -1298,6 +1315,8 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump flag_pwires = pwires; flag_autowire = autowire; + ast->fixup_hierarchy_flags(true); + log_assert(current_ast->type == AST_DESIGN); for (AstNode *child : current_ast->children) { @@ -1361,7 +1380,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump } else if (child->type == AST_PACKAGE) { // process enum/other declarations - child->simplify(true, false, 1, -1, false, false); + child->simplify(true, 1, -1, false); rename_in_package_stmts(child); design->verilog_packages.push_back(child->clone()); current_scope.clear(); @@ -1748,7 +1767,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dictclone(); if (!new_ast->attributes.count(ID::hdlname)) - new_ast->attributes[ID::hdlname] = AstNode::mkconst_str(stripped_name); + new_ast->set_attribute(ID::hdlname, AstNode::mkconst_str(stripped_name)); para_counter = 0; for (auto child : new_ast->children) { @@ -1795,6 +1814,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dictchildren.push_back(defparam); } + new_ast->fixup_hierarchy_flags(true); (*new_ast_out) = new_ast; return modname; } diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index e357579ad..f789e930b 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -221,6 +221,13 @@ namespace AST std::string filename; AstSrcLocType location; + // are we embedded in an lvalue, param? + // (see fixup_hierarchy_flags) + bool in_lvalue; + bool in_param; + bool in_lvalue_from_above; + bool in_param_from_above; + // creating and deleting nodes AstNode(AstNodeType type = AST_NONE, AstNode *child1 = nullptr, AstNode *child2 = nullptr, AstNode *child3 = nullptr, AstNode *child4 = nullptr); AstNode *clone() const; @@ -251,7 +258,7 @@ namespace AST // simplify() creates a simpler AST by unrolling for-loops, expanding generate blocks, etc. // it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL() - bool simplify(bool const_fold, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param); + bool simplify(bool const_fold, int stage, int width_hint, bool sign_hint); void replace_result_wire_name_in_function(const std::string &from, const std::string &to); AstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init); void expand_genblock(const std::string &prefix); @@ -343,6 +350,24 @@ namespace AST // to evaluate widths of dynamic ranges) AstNode *clone_at_zero(); + void set_attribute(RTLIL::IdString key, AstNode *node) + { + attributes[key] = node; + node->set_in_param_flag(true); + } + + // helper to set in_lvalue/in_param flags from the hierarchy context (the actual flag + // can be overridden based on the intrinsic properties of this node, i.e. based on its type) + void set_in_lvalue_flag(bool flag, bool no_descend = false); + void set_in_param_flag(bool flag, bool no_descend = false); + + // fix up the hierarchy flags (in_lvalue/in_param) of this node and its children + // + // to keep the flags in sync, fixup_hierarchy_flags(true) needs to be called once after + // parsing the AST to walk the full tree, then plain fixup_hierarchy_flags() performs + // localized fixups after modifying children/attributes of a particular node + void fixup_hierarchy_flags(bool force_descend = false); + // helper to print errors from simplify/genrtlil code [[noreturn]] void input_error(const char *format, ...) const YS_ATTRIBUTE(format(printf, 2, 3)); }; diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index d62f06ae5..6e750863f 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -176,10 +176,11 @@ struct AST_INTERNAL::LookaheadRewriter AstNode *wire = new AstNode(AST_WIRE); for (auto c : node->id2ast->children) wire->children.push_back(c->clone()); + wire->fixup_hierarchy_flags(); wire->str = stringf("$lookahead%s$%d", node->str.c_str(), autoidx++); - wire->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire->is_logic = true; - while (wire->simplify(true, false, 1, -1, false, false)) { } + while (wire->simplify(true, 1, -1, false)) { } current_ast_mod->children.push_back(wire); lookaheadids[node->str] = make_pair(node->id2ast, wire); wire->genRTLIL(); @@ -926,7 +927,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun this_width = id_ast->children[1]->range_left - id_ast->children[1]->range_right + 1; } else { if (id_ast->children[0]->type != AST_CONSTANT) - while (id_ast->simplify(true, false, 1, -1, false, true)) { } + while (id_ast->simplify(true, 1, -1, false)) { } if (id_ast->children[0]->type == AST_CONSTANT) this_width = id_ast->children[0]->bits.size(); else @@ -970,8 +971,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun else if (!range->range_valid) { AstNode *left_at_zero_ast = children[0]->children[0]->clone_at_zero(); AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone(); - while (left_at_zero_ast->simplify(true, false, 1, -1, false, false)) { } - while (right_at_zero_ast->simplify(true, false, 1, -1, false, false)) { } + while (left_at_zero_ast->simplify(true, 1, -1, false)) { } + while (right_at_zero_ast->simplify(true, 1, -1, false)) { } if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); this_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; @@ -987,7 +988,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun break; case AST_TO_BITS: - while (children[0]->simplify(true, false, 1, -1, false, false) == true) { } + while (children[0]->simplify(true, 1, -1, false) == true) { } if (children[0]->type != AST_CONSTANT) input_error("Left operand of tobits expression is not constant!\n"); children[1]->detectSignWidthWorker(sub_width_hint, sign_hint); @@ -1009,7 +1010,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun break; case AST_CAST_SIZE: - while (children.at(0)->simplify(true, false, 1, -1, false, false)) { } + while (children.at(0)->simplify(true, 1, -1, false)) { } if (children.at(0)->type != AST_CONSTANT) input_error("Static cast with non constant expression!\n"); children.at(1)->detectSignWidthWorker(width_hint, sign_hint); @@ -1031,7 +1032,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun break; case AST_REPLICATE: - while (children[0]->simplify(true, false, 1, -1, false, true) == true) { } + while (children[0]->simplify(true, 1, -1, false) == true) { } if (children[0]->type != AST_CONSTANT) input_error("Left operand of replicate expression is not constant!\n"); children[1]->detectSignWidthWorker(sub_width_hint, sub_sign_hint); @@ -1143,7 +1144,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun case AST_PREFIX: // Prefix nodes always resolve to identifiers in generate loops, so we // can simply perform the resolution to determine the sign and width. - simplify(true, false, 1, -1, false, false); + simplify(true, 1, -1, false); log_assert(type == AST_IDENTIFIER); detectSignWidthWorker(width_hint, sign_hint, found_real); break; @@ -1151,7 +1152,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun case AST_FCALL: if (str == "\\$anyconst" || str == "\\$anyseq" || str == "\\$allconst" || str == "\\$allseq") { if (GetSize(children) == 1) { - while (children[0]->simplify(true, false, 1, -1, false, true) == true) { } + while (children[0]->simplify(true, 1, -1, false) == true) { } if (children[0]->type != AST_CONSTANT) input_error("System function %s called with non-const argument!\n", RTLIL::unescape_id(str).c_str()); @@ -1198,8 +1199,10 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun log_assert(range->type == AST_RANGE && range->children.size() == 2); AstNode *left = range->children.at(0)->clone(); AstNode *right = range->children.at(1)->clone(); - while (left->simplify(true, false, 1, -1, false, true)) { } - while (right->simplify(true, false, 1, -1, false, true)) { } + left->set_in_param_flag(true); + right->set_in_param_flag(true); + while (left->simplify(true, 1, -1, false)) { } + while (right->simplify(true, 1, -1, false)) { } if (left->type != AST_CONSTANT || right->type != AST_CONSTANT) input_error("Function %s has non-constant width!", RTLIL::unescape_id(str).c_str()); @@ -1543,8 +1546,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (!children[0]->range_valid) { AstNode *left_at_zero_ast = children[0]->children[0]->clone_at_zero(); AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone(); - while (left_at_zero_ast->simplify(true, false, 1, -1, false, false)) { } - while (right_at_zero_ast->simplify(true, false, 1, -1, false, false)) { } + while (left_at_zero_ast->simplify(true, 1, -1, false)) { } + while (right_at_zero_ast->simplify(true, 1, -1, false)) { } if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; @@ -1552,7 +1555,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) children[0]->children[1]->clone() : children[0]->children[0]->clone()); fake_ast->children[0]->delete_children(); if (member_node) - fake_ast->children[0]->attributes[ID::wiretype] = member_node->clone(); + fake_ast->children[0]->set_attribute(ID::wiretype, member_node->clone()); int fake_ast_width = 0; bool fake_ast_sign = true; diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index ee1be3781..2a500b56b 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -41,13 +41,102 @@ YOSYS_NAMESPACE_BEGIN using namespace AST; using namespace AST_INTERNAL; +void AstNode::set_in_lvalue_flag(bool flag, bool no_descend) +{ + if (flag != in_lvalue_from_above) { + in_lvalue_from_above = flag; + if (!no_descend) + fixup_hierarchy_flags(); + } +} + +void AstNode::set_in_param_flag(bool flag, bool no_descend) +{ + if (flag != in_param_from_above) { + in_param_from_above = flag; + if (!no_descend) + fixup_hierarchy_flags(); + } +} + +void AstNode::fixup_hierarchy_flags(bool force_descend) +{ + // With forced descend, we disable the implicit + // descend from within the set_* functions, instead + // we do an explicit descend at the end of this function + + in_param = in_param_from_above; + + switch (type) { + case AST_PARAMETER: + case AST_LOCALPARAM: + case AST_DEFPARAM: + case AST_PARASET: + case AST_PREFIX: + in_param = true; + for (auto child : children) + child->set_in_param_flag(true, force_descend); + break; + + case AST_REPLICATE: + case AST_WIRE: + case AST_GENIF: + case AST_GENCASE: + for (auto child : children) + child->set_in_param_flag(in_param, force_descend); + if (children.size() >= 1) + children[0]->set_in_param_flag(true, force_descend); + break; + + case AST_GENFOR: + case AST_FOR: + for (auto child : children) + child->set_in_param_flag(in_param, force_descend); + if (children.size() >= 2) + children[1]->set_in_param_flag(true, force_descend); + break; + + default: + in_param = in_param_from_above; + for (auto child : children) + child->set_in_param_flag(in_param, force_descend); + } + + for (auto attr : attributes) + attr.second->set_in_param_flag(true, force_descend); + + in_lvalue = in_lvalue_from_above; + + switch (type) { + case AST_ASSIGN: + case AST_ASSIGN_EQ: + case AST_ASSIGN_LE: + if (children.size() >= 1) + children[0]->set_in_lvalue_flag(true, force_descend); + if (children.size() >= 2) + children[1]->set_in_lvalue_flag(in_lvalue, force_descend); + break; + + default: + for (auto child : children) + child->set_in_lvalue_flag(in_lvalue, force_descend); + } + + if (force_descend) { + for (auto child : children) + child->fixup_hierarchy_flags(true); + for (auto attr : attributes) + attr.second->fixup_hierarchy_flags(true); + } +} + // Process a format string and arguments for $display, $write, $sprintf, etc Fmt AstNode::processFormat(int stage, bool sformat_like, int default_base, size_t first_arg_at) { std::vector args; for (size_t index = first_arg_at; index < children.size(); index++) { AstNode *node_arg = children[index]; - while (node_arg->simplify(true, false, stage, -1, false, false)) { } + while (node_arg->simplify(true, stage, -1, false)) { } VerilogFmtArg arg = {}; arg.filename = filename; @@ -91,7 +180,7 @@ void AstNode::annotateTypedEnums(AstNode *template_node) log_assert(current_scope.count(enum_type) == 1); AstNode *enum_node = current_scope.at(enum_type); log_assert(enum_node->type == AST_ENUM); - while (enum_node->simplify(true, false, 1, -1, false, true)) { } + while (enum_node->simplify(true, 1, -1, false)) { } //get width from 1st enum item: log_assert(enum_node->children.size() >= 1); AstNode *enum_item0 = enum_node->children[0]; @@ -132,7 +221,7 @@ void AstNode::annotateTypedEnums(AstNode *template_node) RTLIL::Const val = enum_item->children[0]->bitsAsConst(width, is_signed); enum_item_str.append(val.as_string()); //set attribute for available val to enum item name mappings - attributes[enum_item_str.c_str()] = mkconst_str(enum_item->str); + set_attribute(enum_item_str.c_str(), mkconst_str(enum_item->str)); } } } @@ -457,17 +546,15 @@ static int get_max_offset(AstNode *node) static AstNode *make_packed_struct(AstNode *template_node, std::string &name, decltype(AstNode::attributes) &attributes) { // create a wire for the packed struct - auto wnode = new AstNode(AST_WIRE); + int offset = get_max_offset(template_node); + auto wnode = new AstNode(AST_WIRE, make_range(offset, 0)); wnode->str = name; wnode->is_logic = true; wnode->range_valid = true; wnode->is_signed = template_node->is_signed; for (auto &pair : attributes) { - wnode->attributes[pair.first] = pair.second->clone(); + wnode->set_attribute(pair.first, pair.second->clone()); } - int offset = get_max_offset(template_node); - auto range = make_range(offset, 0); - wnode->children.push_back(range); // make sure this node is the one in scope for this name current_scope[name] = wnode; // add all the struct members to scope under the wire's name @@ -527,7 +614,7 @@ const RTLIL::Module* AstNode::lookup_cell_module() auto reprocess_after = [this] (const std::string &modname) { if (!attributes.count(ID::reprocess_after)) - attributes[ID::reprocess_after] = AstNode::mkconst_str(modname); + set_attribute(ID::reprocess_after, AstNode::mkconst_str(modname)); }; const AstNode *celltype = nullptr; @@ -707,6 +794,11 @@ AstNode *AstNode::clone_at_zero() it = it->clone_at_zero(); for (auto &it : that->attributes) it.second = it.second->clone(); + + that->set_in_lvalue_flag(false); + that->set_in_param_flag(false); + that->fixup_hierarchy_flags(); + return that; } @@ -722,8 +814,8 @@ static bool try_determine_range_width(AstNode *range, int &result_width) AstNode *left_at_zero_ast = range->children[0]->clone_at_zero(); AstNode *right_at_zero_ast = range->children[1]->clone_at_zero(); - while (left_at_zero_ast->simplify(true, false, 1, -1, false, false)) {} - while (right_at_zero_ast->simplify(true, false, 1, -1, false, false)) {} + while (left_at_zero_ast->simplify(true, 1, -1, false)) {} + while (right_at_zero_ast->simplify(true, 1, -1, false)) {} bool ok = false; if (left_at_zero_ast->type == AST_CONSTANT @@ -745,8 +837,7 @@ static void mark_auto_nosync(AstNode *block, const AstNode *wire) { log_assert(block->type == AST_BLOCK); log_assert(wire->type == AST_WIRE); - block->attributes[auto_nosync_prefix + wire->str] = AstNode::mkconst_int(1, - false); + block->set_attribute(auto_nosync_prefix + wire->str, AstNode::mkconst_int(1, false)); } // block names can be prefixed with an explicit scope during elaboration @@ -787,7 +878,7 @@ static void check_auto_nosync(AstNode *node) // mark the wire with `nosync` AstNode *wire = it->second; log_assert(wire->type == AST_WIRE); - wire->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); } // remove the attributes we've "consumed" @@ -808,7 +899,7 @@ static void check_auto_nosync(AstNode *node) // // this function also does all name resolving and sets the id2ast member of all // nodes that link to a different node using names and lexical scoping. -bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param) +bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hint) { static int recursion_counter = 0; static bool deep_recursion_warning = false; @@ -826,8 +917,8 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin #if 0 log("-------------\n"); log("AST simplify[%d] depth %d at %s:%d on %s %p:\n", stage, recursion_counter, filename.c_str(), location.first_line, type2str(type).c_str(), this); - log("const_fold=%d, in_lvalue=%d, stage=%d, width_hint=%d, sign_hint=%d, in_param=%d\n", - int(const_fold), int(in_lvalue), int(stage), int(width_hint), int(sign_hint), int(in_param)); + log("const_fold=%d, stage=%d, width_hint=%d, sign_hint=%d\n", + int(const_fold), int(stage), int(width_hint), int(sign_hint)); // dumpAst(NULL, "> "); #endif @@ -836,7 +927,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin log_assert(type == AST_MODULE || type == AST_INTERFACE); deep_recursion_warning = true; - while (simplify(const_fold, in_lvalue, 1, width_hint, sign_hint, in_param)) { } + while (simplify(const_fold, 1, width_hint, sign_hint)) { } if (!flag_nomem2reg && !get_bool_attribute(ID::nomem2reg)) { @@ -915,11 +1006,11 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin reg->is_signed = node->is_signed; for (auto &it : node->attributes) if (it.first != ID::mem2reg) - reg->attributes.emplace(it.first, it.second->clone()); + reg->set_attribute(it.first, it.second->clone()); reg->filename = node->filename; reg->location = node->location; children.push_back(reg); - while (reg->simplify(true, false, 1, -1, false, false)) { } + while (reg->simplify(true, 1, -1, false)) { } } } @@ -933,7 +1024,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin delete node; } - while (simplify(const_fold, in_lvalue, 2, width_hint, sign_hint, in_param)) { } + while (simplify(const_fold, 2, width_hint, sign_hint)) { } recursion_counter--; return false; } @@ -980,7 +1071,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin // when $display()/$write() functions are used in an always block, simplify the expressions and // convert them to a special cell later in genrtlil for (auto node : children) - while (node->simplify(true, false, stage, -1, false, false)) {} + while (node->simplify(true, stage, -1, false)) {} return false; } @@ -994,10 +1085,6 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin if (type == AST_IDENTIFIER && current_scope.count(str) > 0 && (current_scope[str]->type == AST_PARAMETER || current_scope[str]->type == AST_LOCALPARAM || current_scope[str]->type == AST_ENUM_ITEM)) const_fold = true; - // in certain cases a function must be evaluated constant. this is what in_param controls. - if (type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_PREFIX) - in_param = true; - std::map backup_scope; // create name resolution entries for all objects with names @@ -1017,7 +1104,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin if (!c->is_simple_const_expr()) { if (attributes.count(ID::dynports)) delete attributes.at(ID::dynports); - attributes[ID::dynports] = AstNode::mkconst_int(1, true); + set_attribute(ID::dynports, AstNode::mkconst_int(1, true)); } } } @@ -1066,7 +1153,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin for (auto &it : node->attributes) { if (first_node->attributes.count(it.first) > 0) delete first_node->attributes[it.first]; - first_node->attributes[it.first] = it.second->clone(); + first_node->set_attribute(it.first, it.second->clone()); } children.erase(children.begin()+(i--)); did_something = true; @@ -1100,12 +1187,12 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin for (size_t i = 0; i < children.size(); i++) { AstNode *node = children[i]; if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_MEMORY || node->type == AST_TYPEDEF) - while (node->simplify(true, false, 1, -1, false, node->type == AST_PARAMETER || node->type == AST_LOCALPARAM)) + while (node->simplify(true, 1, -1, false)) did_something = true; if (node->type == AST_ENUM) { for (auto enode : node->children){ log_assert(enode->type==AST_ENUM_ITEM); - while (node->simplify(true, false, 1, -1, false, in_param)) + while (node->simplify(true, 1, -1, false)) did_something = true; } } @@ -1170,7 +1257,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin for (AstNode *child : children) { // simplify any parameters to constants if (child->type == AST_PARASET) - while (child->simplify(true, false, 1, -1, false, true)) { } + while (child->simplify(true, 1, -1, false)) { } // look for patterns which _may_ indicate ambiguity requiring // resolution of the underlying module @@ -1263,6 +1350,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin asgn->children.push_back(arg); asgn->children.push_back(ident); } + asgn->fixup_hierarchy_flags(); } @@ -1284,9 +1372,9 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin case AST_ASSIGN_EQ: case AST_ASSIGN_LE: case AST_ASSIGN: - while (!children[0]->basic_prep && children[0]->simplify(false, true, stage, -1, false, in_param) == true) + while (!children[0]->basic_prep && children[0]->simplify(false, stage, -1, false) == true) did_something = true; - while (!children[1]->basic_prep && children[1]->simplify(false, false, stage, -1, false, in_param) == true) + while (!children[1]->basic_prep && children[1]->simplify(false, stage, -1, false) == true) did_something = true; children[0]->detectSignWidth(backup_width_hint, backup_sign_hint); children[1]->detectSignWidth(width_hint, sign_hint); @@ -1322,7 +1410,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin if (!basic_prep) { for (auto *node : children) { // resolve any ranges - while (!node->basic_prep && node->simplify(true, false, stage, -1, false, false)) { + while (!node->basic_prep && node->simplify(true, stage, -1, false)) { did_something = true; } } @@ -1355,7 +1443,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *template_node = resolved_type_node->children[0]; // Ensure typedef itself is fully simplified - while (template_node->simplify(const_fold, in_lvalue, stage, width_hint, sign_hint, in_param)) {}; + while (template_node->simplify(const_fold, stage, width_hint, sign_hint)) {}; // Remove type reference delete children[0]; @@ -1384,7 +1472,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin range_left = template_node->range_left; range_right = template_node->range_right; - attributes[ID::wiretype] = mkconst_str(resolved_type_node->str); + set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); // Copy clones of children from template for (auto template_child : template_node->children) { @@ -1401,7 +1489,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin //log("\nENUM %s: %d child %d\n", str.c_str(), basic_prep, children[0]->basic_prep); if (!basic_prep) { for (auto item_node : children) { - while (!item_node->basic_prep && item_node->simplify(false, false, stage, -1, false, in_param)) + while (!item_node->basic_prep && item_node->simplify(false, stage, -1, false)) did_something = true; } // allocate values (called more than once) @@ -1416,16 +1504,16 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin if (children[0]->type == AST_IDENTIFIER && current_scope.count(children[0]->str) > 0) { auto item_node = current_scope[children[0]->str]; if (item_node->type == AST_STRUCT || item_node->type == AST_UNION) { - attributes[ID::wiretype] = item_node->clone(); + set_attribute(ID::wiretype, item_node->clone()); size_packed_struct(attributes[ID::wiretype], 0); add_members_to_scope(attributes[ID::wiretype], str); } } - while (!children[0]->basic_prep && children[0]->simplify(false, false, stage, -1, false, true) == true) + while (!children[0]->basic_prep && children[0]->simplify(false, stage, -1, false) == true) did_something = true; children[0]->detectSignWidth(width_hint, sign_hint); if (children.size() > 1 && children[1]->type == AST_RANGE) { - while (!children[1]->basic_prep && children[1]->simplify(false, false, stage, -1, false, true) == true) + while (!children[1]->basic_prep && children[1]->simplify(false, stage, -1, false) == true) did_something = true; if (!children[1]->range_valid) input_error("Non-constant width range on parameter decl.\n"); @@ -1433,11 +1521,11 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin } break; case AST_ENUM_ITEM: - while (!children[0]->basic_prep && children[0]->simplify(false, false, stage, -1, false, in_param)) + while (!children[0]->basic_prep && children[0]->simplify(false, stage, -1, false)) did_something = true; children[0]->detectSignWidth(width_hint, sign_hint); if (children.size() > 1 && children[1]->type == AST_RANGE) { - while (!children[1]->basic_prep && children[1]->simplify(false, false, stage, -1, false, in_param)) + while (!children[1]->basic_prep && children[1]->simplify(false, stage, -1, false)) did_something = true; if (!children[1]->range_valid) input_error("Non-constant width range on enum item decl.\n"); @@ -1496,7 +1584,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin width_hint = -1; sign_hint = true; for (auto child : children) { - while (!child->basic_prep && child->simplify(false, in_lvalue, stage, -1, false, in_param) == true) + while (!child->basic_prep && child->simplify(false, stage, -1, false) == true) did_something = true; child->detectSignWidthWorker(width_hint, sign_hint); } @@ -1531,10 +1619,10 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin if (detect_width_simple && width_hint < 0) { if (type == AST_REPLICATE) - while (children[0]->simplify(true, in_lvalue, stage, -1, false, true) == true) + while (children[0]->simplify(true, stage, -1, false) == true) did_something = true; for (auto child : children) - while (!child->basic_prep && child->simplify(false, in_lvalue, stage, -1, false, in_param) == true) + while (!child->basic_prep && child->simplify(false, stage, -1, false) == true) did_something = true; detectSignWidth(width_hint, sign_hint); } @@ -1544,18 +1632,18 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin if (type == AST_TERNARY) { if (width_hint < 0) { - while (!children[0]->basic_prep && children[0]->simplify(true, in_lvalue, stage, -1, false, in_param)) + while (!children[0]->basic_prep && children[0]->simplify(true, stage, -1, false)) did_something = true; bool backup_unevaluated_tern_branch = unevaluated_tern_branch; AstNode *chosen = get_tern_choice().first; unevaluated_tern_branch = backup_unevaluated_tern_branch || chosen == children[2]; - while (!children[1]->basic_prep && children[1]->simplify(false, in_lvalue, stage, -1, false, in_param)) + while (!children[1]->basic_prep && children[1]->simplify(false, stage, -1, false)) did_something = true; unevaluated_tern_branch = backup_unevaluated_tern_branch || chosen == children[1]; - while (!children[2]->basic_prep && children[2]->simplify(false, in_lvalue, stage, -1, false, in_param)) + while (!children[2]->basic_prep && children[2]->simplify(false, stage, -1, false)) did_something = true; unevaluated_tern_branch = backup_unevaluated_tern_branch; @@ -1587,7 +1675,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin if (const_fold && type == AST_CASE) { detectSignWidth(width_hint, sign_hint); - while (children[0]->simplify(const_fold, in_lvalue, stage, width_hint, sign_hint, in_param)) { } + while (children[0]->simplify(const_fold, stage, width_hint, sign_hint)) { } if (children[0]->type == AST_CONSTANT && children[0]->bits_only_01()) { children[0]->is_signed = sign_hint; RTLIL::Const case_expr = children[0]->bitsAsConst(width_hint, sign_hint); @@ -1601,7 +1689,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin goto keep_const_cond; if (v->type == AST_BLOCK) continue; - while (v->simplify(const_fold, in_lvalue, stage, width_hint, sign_hint, in_param)) { } + while (v->simplify(const_fold, stage, width_hint, sign_hint)) { } if (v->type == AST_CONSTANT && v->bits_only_01()) { RTLIL::Const case_item_expr = v->bitsAsConst(width_hint, sign_hint); RTLIL::Const match = const_eq(case_expr, case_item_expr, sign_hint, sign_hint, 1); @@ -1658,20 +1746,13 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin unevaluated_tern_branch = chosen && chosen != children[i]; } while (did_something_here && i < children.size()) { - bool const_fold_here = const_fold, in_lvalue_here = in_lvalue; + bool const_fold_here = const_fold; int width_hint_here = width_hint; bool sign_hint_here = sign_hint; - bool in_param_here = in_param; if (i == 0 && (type == AST_REPLICATE || type == AST_WIRE)) - const_fold_here = true, in_param_here = true; - if (i == 0 && (type == AST_GENIF || type == AST_GENCASE)) - in_param_here = true; - if (i == 1 && (type == AST_FOR || type == AST_GENFOR)) - in_param_here = true; + const_fold_here = true; if (type == AST_PARAMETER || type == AST_LOCALPARAM) const_fold_here = true; - if (i == 0 && (type == AST_ASSIGN || type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE)) - in_lvalue_here = true; if (type == AST_BLOCK) { current_block = this; current_block_child = children[i]; @@ -1686,7 +1767,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin width_hint_here = -1, sign_hint_here = false; if (children_are_self_determined) width_hint_here = -1, sign_hint_here = false; - did_something_here = children[i]->simplify(const_fold_here, in_lvalue_here, stage, width_hint_here, sign_hint_here, in_param_here); + did_something_here = children[i]->simplify(const_fold_here, stage, width_hint_here, sign_hint_here); if (did_something_here) did_something = true; } @@ -1706,7 +1787,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin } } for (auto &attr : attributes) { - while (attr.second->simplify(true, false, stage, -1, false, true)) + while (attr.second->simplify(true, stage, -1, false)) did_something = true; } if (type == AST_CASE && stage == 2) { @@ -1784,7 +1865,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin log_assert(children.size() == 1); auto type_node = children[0]; log_assert(type_node->type == AST_WIRE || type_node->type == AST_MEMORY || type_node->type == AST_STRUCT || type_node->type == AST_UNION); - while (type_node->simplify(const_fold, in_lvalue, stage, width_hint, sign_hint, in_param)) { + while (type_node->simplify(const_fold, stage, width_hint, sign_hint)) { did_something = true; } log_assert(!type_node->is_custom_type); @@ -1806,12 +1887,12 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *template_node = resolved_type_node->children[0]; // Ensure typedef itself is fully simplified - while (template_node->simplify(const_fold, in_lvalue, stage, width_hint, sign_hint, in_param)) {}; + while (template_node->simplify(const_fold, stage, width_hint, sign_hint)) {}; if (!str.empty() && str[0] == '\\' && (template_node->type == AST_STRUCT || template_node->type == AST_UNION)) { // replace instance with wire representing the packed structure newNode = make_packed_struct(template_node, str, attributes); - newNode->attributes[ID::wiretype] = mkconst_str(resolved_type_node->str); + newNode->set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); // add original input/output attribute to resolved wire newNode->is_input = this->is_input; newNode->is_output = this->is_output; @@ -1836,7 +1917,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin range_left = template_node->range_left; range_right = template_node->range_right; - attributes[ID::wiretype] = mkconst_str(resolved_type_node->str); + set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); // if an enum then add attributes to support simulator tracing annotateTypedEnums(template_node); @@ -1850,6 +1931,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *rng = make_range(0, 0); children.insert(children.begin(), rng); } + fixup_hierarchy_flags(); did_something = true; } log_assert(!is_custom_type); @@ -1871,12 +1953,12 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *template_node = resolved_type_node->children[0]; // Ensure typedef itself is fully simplified - while (template_node->simplify(const_fold, in_lvalue, stage, width_hint, sign_hint, in_param)) {}; + while (template_node->simplify(const_fold, stage, width_hint, sign_hint)) {}; if (template_node->type == AST_STRUCT || template_node->type == AST_UNION) { // replace with wire representing the packed structure newNode = make_packed_struct(template_node, str, attributes); - newNode->attributes[ID::wiretype] = mkconst_str(resolved_type_node->str); + newNode->set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); newNode->type = type; current_scope[str] = this; // copy param value, it needs to be 1st value @@ -1898,9 +1980,10 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin range_swapped = template_node->range_swapped; range_left = template_node->range_left; range_right = template_node->range_right; - attributes[ID::wiretype] = mkconst_str(resolved_type_node->str); + set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); for (auto template_child : template_node->children) children.push_back(template_child->clone()); + fixup_hierarchy_flags(); did_something = true; } log_assert(!is_custom_type); @@ -1913,7 +1996,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin input_error("Index in generate block prefix syntax is not constant!\n"); } if (children[1]->type == AST_PREFIX) - children[1]->simplify(const_fold, in_lvalue, stage, width_hint, sign_hint, in_param); + children[1]->simplify(const_fold, stage, width_hint, sign_hint); log_assert(children[1]->type == AST_IDENTIFIER); newNode = children[1]->clone(); const char *second_part = children[1]->str.c_str(); @@ -2020,6 +2103,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin } delete children[1]; children[1] = new AstNode(AST_RANGE, AstNode::mkconst_int(0, true), AstNode::mkconst_int(total_size-1, true)); + fixup_hierarchy_flags(); did_something = true; } @@ -2054,6 +2138,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin else children[0] = new AstNode(AST_RANGE, index_expr); + fixup_hierarchy_flags(); did_something = true; } @@ -2069,6 +2154,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin children[0]->realvalue, log_signal(constvalue)); delete children[0]; children[0] = mkconst_bits(constvalue.bits, sign_hint); + fixup_hierarchy_flags(); did_something = true; } if (children[0]->type == AST_CONSTANT) { @@ -2078,6 +2164,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *old_child_0 = children[0]; children[0] = mkconst_bits(sig.as_const().bits, is_signed); delete old_child_0; + fixup_hierarchy_flags(); } children[0]->is_signed = is_signed; } @@ -2091,6 +2178,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin delete children[0]; children[0] = new AstNode(AST_REALVALUE); children[0]->realvalue = as_realvalue; + fixup_hierarchy_flags(); did_something = true; } } @@ -2107,7 +2195,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin newNode = new AstNode(AST_IDENTIFIER, range); newNode->str = sname; // save type and original number of dimensions for $size() etc. - newNode->attributes[ID::wiretype] = item_node->clone(); + newNode->set_attribute(ID::wiretype, item_node->clone()); if (!item_node->multirange_dimensions.empty() && children.size() > 0) { if (children[0]->type == AST_RANGE) newNode->integer = 1; @@ -2201,9 +2289,9 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(data_range_left, true), mkconst_int(data_range_right, true))); wire->str = wire_id; if (current_block) - wire->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); current_ast_mod->children.push_back(wire); - while (wire->simplify(true, false, 1, -1, false, false)) { } + while (wire->simplify(true, 1, -1, false)) { } AstNode *data = clone(); delete data->children[1]; @@ -2245,7 +2333,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *body = children[1]; // eval count expression - while (count->simplify(true, false, stage, 32, true, false)) { } + while (count->simplify(true, stage, 32, true)) { } if (count->type != AST_CONSTANT) input_error("Repeat loops outside must have constant repeat counts!\n"); @@ -2301,7 +2389,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin int expr_width_hint = -1; bool expr_sign_hint = true; varbuf->detectSignWidth(expr_width_hint, expr_sign_hint); - while (varbuf->simplify(true, false, stage, 32, true, false)) { } + while (varbuf->simplify(true, stage, 32, true)) { } } if (varbuf->type != AST_CONSTANT) @@ -2342,7 +2430,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin int expr_width_hint = -1; bool expr_sign_hint = true; buf->detectSignWidth(expr_width_hint, expr_sign_hint); - while (buf->simplify(true, false, stage, expr_width_hint, expr_sign_hint, false)) { } + while (buf->simplify(true, stage, expr_width_hint, expr_sign_hint)) { } } if (buf->type != AST_CONSTANT) @@ -2377,7 +2465,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin if (type == AST_GENFOR) { for (size_t i = 0; i < buf->children.size(); i++) { - buf->children[i]->simplify(const_fold, false, stage, -1, false, false); + buf->children[i]->simplify(const_fold, stage, -1, false); current_ast_mod->children.push_back(buf->children[i]); } } else { @@ -2389,11 +2477,12 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin // eval 3rd expression buf = next_ast->children[1]->clone(); + buf->set_in_param_flag(true); { int expr_width_hint = -1; bool expr_sign_hint = true; buf->detectSignWidth(expr_width_hint, expr_sign_hint); - while (buf->simplify(true, false, stage, expr_width_hint, expr_sign_hint, true)) { } + while (buf->simplify(true, stage, expr_width_hint, expr_sign_hint)) { } } if (buf->type != AST_CONSTANT) @@ -2445,7 +2534,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin std::vector new_children; for (size_t i = 0; i < children.size(); i++) if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM || children[i]->type == AST_TYPEDEF) { - children[i]->simplify(false, false, stage, -1, false, false); + children[i]->simplify(false, stage, -1, false); current_ast_mod->children.push_back(children[i]); current_scope[children[i]->str] = children[i]; } else @@ -2464,7 +2553,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin } for (size_t i = 0; i < children.size(); i++) { - children[i]->simplify(const_fold, false, stage, -1, false, false); + children[i]->simplify(const_fold, stage, -1, false); current_ast_mod->children.push_back(children[i]); } @@ -2476,7 +2565,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin if (type == AST_GENIF && children.size() != 0) { AstNode *buf = children[0]->clone(); - while (buf->simplify(true, false, stage, width_hint, sign_hint, false)) { } + while (buf->simplify(true, stage, width_hint, sign_hint)) { } if (buf->type != AST_CONSTANT) { // for (auto f : log_files) // dumpAst(f, "verilog-ast> "); @@ -2500,7 +2589,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin } for (size_t i = 0; i < buf->children.size(); i++) { - buf->children[i]->simplify(const_fold, false, stage, -1, false, false); + buf->children[i]->simplify(const_fold, stage, -1, false); current_ast_mod->children.push_back(buf->children[i]); } @@ -2516,7 +2605,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin if (type == AST_GENCASE && children.size() != 0) { AstNode *buf = children[0]->clone(); - while (buf->simplify(true, false, stage, width_hint, sign_hint, false)) { } + while (buf->simplify(true, stage, width_hint, sign_hint)) { } if (buf->type != AST_CONSTANT) { // for (auto f : log_files) // dumpAst(f, "verilog-ast> "); @@ -2550,7 +2639,8 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin continue; buf = child->clone(); - while (buf->simplify(true, false, stage, width_hint, sign_hint, true)) { } + buf->set_in_param_flag(true); + while (buf->simplify(true, stage, width_hint, sign_hint)) { } if (buf->type != AST_CONSTANT) { // for (auto f : log_files) // dumpAst(f, "verilog-ast> "); @@ -2578,7 +2668,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin } for (size_t i = 0; i < buf->children.size(); i++) { - buf->children[i]->simplify(const_fold, false, stage, -1, false, false); + buf->children[i]->simplify(const_fold, stage, -1, false); current_ast_mod->children.push_back(buf->children[i]); } @@ -2656,6 +2746,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin children.push_back(children_list.at(0)); children.back()->was_checked = true; children.push_back(node); + fixup_hierarchy_flags(); did_something = true; } else if (str == "buf" || str == "not") @@ -2706,6 +2797,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin children.push_back(children_list[0]); children.back()->was_checked = true; children.push_back(node); + fixup_hierarchy_flags(); did_something = true; } } @@ -2761,7 +2853,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin if (children[0]->id2ast->attributes.count(ID::nowrshmsk)) { AstNode *node = children[0]->id2ast->attributes.at(ID::nowrshmsk); - while (node->simplify(true, false, stage, -1, false, false)) { } + while (node->simplify(true, stage, -1, false)) { } if (node->type != AST_CONSTANT) input_error("Non-constant value for `nowrshmsk' attribute on `%s'!\n", children[0]->id2ast->str.c_str()); if (node->asAttrConst().as_bool()) @@ -2784,7 +2876,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *lvalue = children[0]->clone(); lvalue->delete_children(); if (member_node) - lvalue->attributes[ID::wiretype] = member_node->clone(); + lvalue->set_attribute(ID::wiretype, member_node->clone()); lvalue->children.push_back(new AstNode(AST_RANGE, mkconst_int(end_bit, true), mkconst_int(start_bit, true))); cond->children.push_back(new AstNode(AST_BLOCK, new AstNode(type, lvalue, children[1]->clone()))); @@ -2797,16 +2889,16 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *wire_mask = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true))); wire_mask->str = stringf("$bitselwrite$mask$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); - wire_mask->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire_mask->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire_mask->is_logic = true; - while (wire_mask->simplify(true, false, 1, -1, false, false)) { } + while (wire_mask->simplify(true, 1, -1, false)) { } current_ast_mod->children.push_back(wire_mask); AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true))); wire_data->str = stringf("$bitselwrite$data$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); - wire_data->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire_data->is_logic = true; - while (wire_data->simplify(true, false, 1, -1, false, false)) { } + while (wire_data->simplify(true, 1, -1, false)) { } current_ast_mod->children.push_back(wire_data); int shamt_width_hint = -1; @@ -2815,10 +2907,10 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *wire_sel = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(shamt_width_hint-1, true), mkconst_int(0, true))); wire_sel->str = stringf("$bitselwrite$sel$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); - wire_sel->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire_sel->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire_sel->is_logic = true; wire_sel->is_signed = shamt_sign_hint; - while (wire_sel->simplify(true, false, 1, -1, false, false)) { } + while (wire_sel->simplify(true, 1, -1, false)) { } current_ast_mod->children.push_back(wire_sel); did_something = true; @@ -2827,7 +2919,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *lvalue = children[0]->clone(); lvalue->delete_children(); if (member_node) - lvalue->attributes[ID::wiretype] = member_node->clone(); + lvalue->set_attribute(ID::wiretype, member_node->clone()); AstNode *ref_mask = new AstNode(AST_IDENTIFIER); ref_mask->str = wire_mask->str; @@ -2884,6 +2976,8 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin t = new AstNode(AST_BIT_OR, t, ref_data); t = new AstNode(type, lvalue, t); newNode->children.push_back(t); + + newNode->fixup_hierarchy_flags(true); } goto apply_newNode; @@ -2901,7 +2995,7 @@ skip_dynamic_range_lvalue_expansion:; wire_check->was_checked = true; current_ast_mod->children.push_back(wire_check); current_scope[wire_check->str] = wire_check; - while (wire_check->simplify(true, false, 1, -1, false, false)) { } + while (wire_check->simplify(true, 1, -1, false)) { } AstNode *wire_en = new AstNode(AST_WIRE); wire_en->str = id_en; @@ -2913,7 +3007,7 @@ skip_dynamic_range_lvalue_expansion:; current_ast_mod->children.back()->children[0]->children[0]->children[0]->was_checked = true; } current_scope[wire_en->str] = wire_en; - while (wire_en->simplify(true, false, 1, -1, false, false)) { } + while (wire_en->simplify(true, 1, -1, false)) { } AstNode *check_defval; if (type == AST_LIVE || type == AST_FAIR) { @@ -2943,6 +3037,7 @@ skip_dynamic_range_lvalue_expansion:; assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_REDUCE_BOOL, children[0]->clone())); assign_check->children[0]->str = id_check; assign_check->children[0]->was_checked = true; + assign_check->fixup_hierarchy_flags(); } if (current_always == nullptr || current_always->type != AST_INITIAL) { @@ -2953,6 +3048,7 @@ skip_dynamic_range_lvalue_expansion:; } assign_en->children[0]->str = id_en; assign_en->children[0]->was_checked = true; + assign_en->fixup_hierarchy_flags(); newNode = new AstNode(AST_BLOCK); if (assign_check != nullptr) @@ -2975,6 +3071,7 @@ skip_dynamic_range_lvalue_expansion:; if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME || type == AST_LIVE || type == AST_FAIR || type == AST_COVER) && children.size() == 1) { children.push_back(mkconst_int(1, false, 1)); + fixup_hierarchy_flags(); did_something = true; } @@ -3005,8 +3102,8 @@ skip_dynamic_range_lvalue_expansion:; wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); current_ast_mod->children.push_back(wire_tmp); current_scope[wire_tmp->str] = wire_tmp; - wire_tmp->attributes[ID::nosync] = AstNode::mkconst_int(1, false); - while (wire_tmp->simplify(true, false, 1, -1, false, false)) { } + wire_tmp->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); + while (wire_tmp->simplify(true, 1, -1, false)) { } wire_tmp->is_logic = true; AstNode *wire_tmp_id = new AstNode(AST_IDENTIFIER); @@ -3076,7 +3173,7 @@ skip_dynamic_range_lvalue_expansion:; wire_addr->was_checked = true; current_ast_mod->children.push_back(wire_addr); current_scope[wire_addr->str] = wire_addr; - while (wire_addr->simplify(true, false, 1, -1, false, false)) { } + while (wire_addr->simplify(true, 1, -1, false)) { } AstNode *assign_addr = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_addr, false)); assign_addr->children[0]->str = id_addr; @@ -3102,7 +3199,7 @@ skip_dynamic_range_lvalue_expansion:; wire_data->is_signed = mem_signed; current_ast_mod->children.push_back(wire_data); current_scope[wire_data->str] = wire_data; - while (wire_data->simplify(true, false, 1, -1, false, false)) { } + while (wire_data->simplify(true, 1, -1, false)) { } AstNode *assign_data = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_data, false)); assign_data->children[0]->str = id_data; @@ -3118,7 +3215,7 @@ skip_dynamic_range_lvalue_expansion:; wire_en->was_checked = true; current_ast_mod->children.push_back(wire_en); current_scope[wire_en->str] = wire_en; - while (wire_en->simplify(true, false, 1, -1, false, false)) { } + while (wire_en->simplify(true, 1, -1, false)) { } AstNode *assign_en_first = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width)); assign_en_first->children[0]->str = id_en; @@ -3246,7 +3343,7 @@ skip_dynamic_range_lvalue_expansion:; AstNode *wire = new AstNode(AST_WIRE); wire->str = stringf("$initstate$%d_wire", myidx); current_ast_mod->children.push_back(wire); - while (wire->simplify(true, false, 1, -1, false, false)) { } + while (wire->simplify(true, 1, -1, false)) { } AstNode *cell = new AstNode(AST_CELL, new AstNode(AST_CELLTYPE), new AstNode(AST_ARGUMENT, new AstNode(AST_IDENTIFIER))); cell->str = stringf("$initstate$%d", myidx); @@ -3255,7 +3352,7 @@ skip_dynamic_range_lvalue_expansion:; cell->children[1]->children[0]->str = wire->str; cell->children[1]->children[0]->id2ast = wire; current_ast_mod->children.push_back(cell); - while (cell->simplify(true, false, 1, -1, false, false)) { } + while (cell->simplify(true, 1, -1, false)) { } newNode = new AstNode(AST_IDENTIFIER); newNode->str = wire->str; @@ -3281,7 +3378,7 @@ skip_dynamic_range_lvalue_expansion:; if (GetSize(children) == 2) { AstNode *buf = children[1]->clone(); - while (buf->simplify(true, false, stage, -1, false, false)) { } + while (buf->simplify(true, stage, -1, false)) { } if (buf->type != AST_CONSTANT) input_error("Failed to evaluate system function `%s' with non-constant value.\n", str.c_str()); @@ -3316,7 +3413,7 @@ skip_dynamic_range_lvalue_expansion:; current_ast_mod->children.push_back(reg); - while (reg->simplify(true, false, 1, -1, false, false)) { } + while (reg->simplify(true, 1, -1, false)) { } AstNode *regid = new AstNode(AST_IDENTIFIER); regid->str = reg->str; @@ -3392,7 +3489,7 @@ skip_dynamic_range_lvalue_expansion:; RTLIL::unescape_id(str).c_str(), int(children.size())); AstNode *buf = children[0]->clone(); - while (buf->simplify(true, false, stage, width_hint, sign_hint, false)) { } + while (buf->simplify(true, stage, width_hint, sign_hint)) { } if (buf->type != AST_CONSTANT) input_error("Failed to evaluate system function `%s' with non-constant value.\n", str.c_str()); @@ -3424,7 +3521,7 @@ skip_dynamic_range_lvalue_expansion:; if (children.size() == 2) { AstNode *buf = children[1]->clone(); // Evaluate constant expression - while (buf->simplify(true, false, stage, width_hint, sign_hint, false)) { } + while (buf->simplify(true, stage, width_hint, sign_hint)) { } dim = buf->asInt(false); delete buf; } @@ -3582,7 +3679,7 @@ skip_dynamic_range_lvalue_expansion:; } if (children.size() >= 1) { - while (children[0]->simplify(true, false, stage, width_hint, sign_hint, false)) { } + while (children[0]->simplify(true, stage, width_hint, sign_hint)) { } if (!children[0]->isConst()) input_error("Failed to evaluate system function `%s' with non-constant argument.\n", RTLIL::unescape_id(str).c_str()); @@ -3593,7 +3690,7 @@ skip_dynamic_range_lvalue_expansion:; } if (children.size() >= 2) { - while (children[1]->simplify(true, false, stage, width_hint, sign_hint, false)) { } + while (children[1]->simplify(true, stage, width_hint, sign_hint)) { } if (!children[1]->isConst()) input_error("Failed to evaluate system function `%s' with non-constant argument.\n", RTLIL::unescape_id(str).c_str()); @@ -3650,7 +3747,7 @@ skip_dynamic_range_lvalue_expansion:; // Determine which bits to count for (size_t i = 1; i < children.size(); i++) { AstNode *node = children[i]; - while (node->simplify(true, false, stage, -1, false, false)) { } + while (node->simplify(true, stage, -1, false)) { } if (node->type != AST_CONSTANT) input_error("Failed to evaluate system function `%s' with non-constant control bit argument.\n", str.c_str()); if (node->bits.size() != 1) @@ -3745,7 +3842,7 @@ skip_dynamic_range_lvalue_expansion:; argtypes.push_back(RTLIL::unescape_id(dpi_decl->children.at(i)->str)); args.push_back(children.at(i-2)->clone()); - while (args.back()->simplify(true, false, stage, -1, false, true)) { } + while (args.back()->simplify(true, stage, -1, false)) { } if (args.back()->type != AST_CONSTANT && args.back()->type != AST_REALVALUE) input_error("Failed to evaluate DPI function with non-constant argument.\n"); @@ -3782,12 +3879,12 @@ skip_dynamic_range_lvalue_expansion:; RTLIL::unescape_id(str).c_str(), int(children.size())); AstNode *node_filename = children[0]->clone(); - while (node_filename->simplify(true, false, stage, width_hint, sign_hint, false)) { } + while (node_filename->simplify(true, stage, width_hint, sign_hint)) { } if (node_filename->type != AST_CONSTANT) input_error("Failed to evaluate system function `%s' with non-constant 1st argument.\n", str.c_str()); AstNode *node_memory = children[1]->clone(); - while (node_memory->simplify(true, false, stage, width_hint, sign_hint, false)) { } + while (node_memory->simplify(true, stage, width_hint, sign_hint)) { } if (node_memory->type != AST_IDENTIFIER || node_memory->id2ast == nullptr || node_memory->id2ast->type != AST_MEMORY) input_error("Failed to evaluate system function `%s' with non-memory 2nd argument.\n", str.c_str()); @@ -3795,7 +3892,7 @@ skip_dynamic_range_lvalue_expansion:; if (GetSize(children) > 2) { AstNode *node_addr = children[2]->clone(); - while (node_addr->simplify(true, false, stage, width_hint, sign_hint, false)) { } + while (node_addr->simplify(true, stage, width_hint, sign_hint)) { } if (node_addr->type != AST_CONSTANT) input_error("Failed to evaluate system function `%s' with non-constant 3rd argument.\n", str.c_str()); start_addr = int(node_addr->asInt(false)); @@ -3803,7 +3900,7 @@ skip_dynamic_range_lvalue_expansion:; if (GetSize(children) > 3) { AstNode *node_addr = children[3]->clone(); - while (node_addr->simplify(true, false, stage, width_hint, sign_hint, false)) { } + while (node_addr->simplify(true, stage, width_hint, sign_hint)) { } if (node_addr->type != AST_CONSTANT) input_error("Failed to evaluate system function `%s' with non-constant 4th argument.\n", str.c_str()); finish_addr = int(node_addr->asInt(false)); @@ -3855,13 +3952,14 @@ skip_dynamic_range_lvalue_expansion:; bool require_const_eval = decl->has_const_only_constructs(); bool all_args_const = true; for (auto child : children) { - while (child->simplify(true, false, 1, -1, false, true)) { } + while (child->simplify(true, 1, -1, false)) { } if (child->type != AST_CONSTANT && child->type != AST_REALVALUE) all_args_const = false; } if (all_args_const) { AstNode *func_workspace = decl->clone(); + func_workspace->set_in_param_flag(true); func_workspace->str = prefix_id(prefix, "$result"); newNode = func_workspace->eval_const_function(this, in_param || require_const_eval); delete func_workspace; @@ -3899,7 +3997,7 @@ skip_dynamic_range_lvalue_expansion:; current_scope[wire->str] = wire; current_ast_mod->children.push_back(wire); - while (wire->simplify(true, false, 1, -1, false, false)) { } + while (wire->simplify(true, 1, -1, false)) { } AstNode *lvalue = new AstNode(AST_IDENTIFIER); lvalue->str = wire->str; @@ -3945,7 +4043,7 @@ skip_dynamic_range_lvalue_expansion:; wire->is_input = false; wire->is_output = false; current_ast_mod->children.push_back(wire); - while (wire->simplify(true, false, 1, -1, false, false)) { } + while (wire->simplify(true, 1, -1, false)) { } AstNode *wire_id = new AstNode(AST_IDENTIFIER); wire_id->str = wire->str; @@ -3988,7 +4086,7 @@ skip_dynamic_range_lvalue_expansion:; for (auto c : child->children) wire->children.push_back(c->clone()); } else if (!child->children.empty()) { - while (child->simplify(true, false, stage, -1, false, false)) { } + while (child->simplify(true, stage, -1, false)) { } if (GetSize(child->children) == GetSize(wire->children) - contains_value) { for (int i = 0; i < GetSize(child->children); i++) if (*child->children.at(i) != *wire->children.at(i + contains_value)) @@ -4006,9 +4104,9 @@ skip_dynamic_range_lvalue_expansion:; wire->is_input = false; wire->is_output = false; wire->is_reg = true; - wire->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); if (child->type == AST_ENUM_ITEM) - wire->attributes[ID::enum_base_type] = child->attributes[ID::enum_base_type]; + wire->set_attribute(ID::enum_base_type, child->attributes[ID::enum_base_type]); wire_cache[child->str] = wire; @@ -4016,7 +4114,7 @@ skip_dynamic_range_lvalue_expansion:; current_ast_mod->children.push_back(wire); } - while (wire->simplify(true, false, 1, -1, false, false)) { } + while (wire->simplify(true, 1, -1, false)) { } if ((child->is_input || child->is_output) && arg_count < children.size()) { @@ -4047,8 +4145,9 @@ skip_dynamic_range_lvalue_expansion:; range->children.push_back(mkconst_int(0, true)); } } + wire->fixup_hierarchy_flags(); // updates the sizing - while (wire->simplify(true, false, 1, -1, false, false)) { } + while (wire->simplify(true, 1, -1, false)) { } delete arg; continue; } @@ -4366,6 +4465,7 @@ apply_newNode: newNode->filename = filename; newNode->location = location; newNode->cloneInto(this); + fixup_hierarchy_flags(); delete newNode; did_something = true; } @@ -4956,18 +5056,18 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, wire_addr->str = id_addr; wire_addr->is_reg = true; wire_addr->was_checked = true; - wire_addr->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire_addr->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); mod->children.push_back(wire_addr); - while (wire_addr->simplify(true, false, 1, -1, false, false)) { } + while (wire_addr->simplify(true, 1, -1, false)) { } AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); wire_data->str = id_data; wire_data->is_reg = true; wire_data->was_checked = true; wire_data->is_signed = mem_signed; - wire_data->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); mod->children.push_back(wire_data); - while (wire_data->simplify(true, false, 1, -1, false, false)) { } + while (wire_data->simplify(true, 1, -1, false)) { } log_assert(block != NULL); size_t assign_idx = 0; @@ -4994,6 +5094,10 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, cond_node->children[1]->children.push_back(assign_reg); case_node->children.push_back(cond_node); } + + // fixup on the full hierarchy below case_node + case_node->fixup_hierarchy_flags(true); + block->children.insert(block->children.begin()+assign_idx+2, case_node); children[0]->delete_children(); @@ -5003,6 +5107,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, type = AST_ASSIGN_EQ; children[0]->was_checked = true; + fixup_hierarchy_flags(); did_something = true; } @@ -5073,9 +5178,9 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, wire_addr->is_reg = true; wire_addr->was_checked = true; if (block) - wire_addr->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire_addr->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); mod->children.push_back(wire_addr); - while (wire_addr->simplify(true, false, 1, -1, false, false)) { } + while (wire_addr->simplify(true, 1, -1, false)) { } AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); wire_data->str = id_data; @@ -5083,9 +5188,9 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, wire_data->was_checked = true; wire_data->is_signed = mem_signed; if (block) - wire_data->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); mod->children.push_back(wire_data); - while (wire_data->simplify(true, false, 1, -1, false, false)) { } + while (wire_data->simplify(true, 1, -1, false)) { } AstNode *assign_addr = new AstNode(block ? AST_ASSIGN_EQ : AST_ASSIGN, new AstNode(AST_IDENTIFIER), children[0]->children[0]->clone()); assign_addr->children[0]->str = id_addr; @@ -5117,6 +5222,9 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, cond_node->children[1]->children.push_back(assign_reg); case_node->children.push_back(cond_node); + // fixup on the full hierarchy below case_node + case_node->fixup_hierarchy_flags(true); + if (block) { size_t assign_idx = 0; @@ -5128,10 +5236,10 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, } else { - AstNode *proc = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK)); - proc->children[0]->children.push_back(case_node); + AstNode *proc = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK, case_node)); mod->children.push_back(proc); mod->children.push_back(assign_addr); + mod->fixup_hierarchy_flags(); } delete_children(); @@ -5140,8 +5248,10 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, str = id_data; } - if (bit_part_sel) + if (bit_part_sel) { children.push_back(bit_part_sel); + fixup_hierarchy_flags(); + } did_something = true; } @@ -5263,7 +5373,7 @@ bool AstNode::replace_variables(std::map &varia } if (!children.at(0)->replace_variables(variables, fcall, must_succeed)) return false; - while (simplify(true, false, 1, -1, false, true)) { } + while (simplify(true, 1, -1, false)) { } if (!children.at(0)->range_valid) { if (!must_succeed) return false; @@ -5304,6 +5414,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) { block->children.push_back(child->clone()); } + block->set_in_param_flag(true); while (!block->children.empty()) { @@ -5318,7 +5429,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) if (stmt->type == AST_WIRE) { - while (stmt->simplify(true, false, 1, -1, false, true)) { } + while (stmt->simplify(true, 1, -1, false)) { } if (!stmt->range_valid) { if (!must_succeed) goto finished; @@ -5362,7 +5473,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) if (stmt->type == AST_LOCALPARAM) { - while (stmt->simplify(true, false, 1, -1, false, true)) { } + while (stmt->simplify(true, 1, -1, false)) { } current_scope[stmt->str] = stmt; @@ -5379,7 +5490,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) goto finished; if (!stmt->children.at(1)->replace_variables(variables, fcall, must_succeed)) goto finished; - while (stmt->simplify(true, false, 1, -1, false, true)) { } + while (stmt->simplify(true, 1, -1, false)) { } if (stmt->type != AST_ASSIGN_EQ) continue; @@ -5446,7 +5557,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) AstNode *cond = stmt->children.at(0)->clone(); if (!cond->replace_variables(variables, fcall, must_succeed)) goto finished; - while (cond->simplify(true, false, 1, -1, false, true)) { } + cond->set_in_param_flag(true); + while (cond->simplify(true, 1, -1, false)) { } if (cond->type != AST_CONSTANT) { if (!must_succeed) @@ -5471,7 +5583,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) AstNode *num = stmt->children.at(0)->clone(); if (!num->replace_variables(variables, fcall, must_succeed)) goto finished; - while (num->simplify(true, false, 1, -1, false, true)) { } + num->set_in_param_flag(true); + while (num->simplify(true, 1, -1, false)) { } if (num->type != AST_CONSTANT) { if (!must_succeed) @@ -5494,7 +5607,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) AstNode *expr = stmt->children.at(0)->clone(); if (!expr->replace_variables(variables, fcall, must_succeed)) goto finished; - while (expr->simplify(true, false, 1, -1, false, true)) { } + expr->set_in_param_flag(true); + while (expr->simplify(true, 1, -1, false)) { } AstNode *sel_case = NULL; for (size_t i = 1; i < stmt->children.size(); i++) @@ -5514,7 +5628,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) goto finished; cond = new AstNode(AST_EQ, expr->clone(), cond); - while (cond->simplify(true, false, 1, -1, false, true)) { } + cond->set_in_param_flag(true); + while (cond->simplify(true, 1, -1, false)) { } if (cond->type != AST_CONSTANT) { if (!must_succeed) @@ -5549,6 +5664,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) block->children.erase(block->children.begin()); block->children.insert(block->children.begin(), stmt->children.begin(), stmt->children.end()); stmt->children.clear(); + block->fixup_hierarchy_flags(); delete stmt; continue; } @@ -5583,7 +5699,7 @@ void AstNode::allocateDefaultEnumValues() int last_enum_int = -1; for (auto node : children) { log_assert(node->type==AST_ENUM_ITEM); - node->attributes[ID::enum_base_type] = mkconst_str(str); + node->set_attribute(ID::enum_base_type, mkconst_str(str)); for (size_t i = 0; i < node->children.size(); i++) { switch (node->children[i]->type) { case AST_NONE: diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index a67244d7a..115a42e33 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -52,6 +52,7 @@ USING_YOSYS_NAMESPACE #ifdef VERIFIC_VHDL_SUPPORT #include "vhdl_file.h" #include "VhdlUnits.h" +#include "NameSpace.h" #endif #ifdef VERIFIC_EDIF_SUPPORT @@ -265,7 +266,7 @@ void VerificImporter::import_attributes(dict &att Att *attr; if (obj->Linefile()) - attributes[ID::src] = stringf("%s:%d", LineFile::GetFileName(obj->Linefile()), LineFile::GetLineNo(obj->Linefile())); + attributes[ID::src] = stringf("%s:%d.%d-%d.%d", LineFile::GetFileName(obj->Linefile()), obj->Linefile()->GetLeftLine(), obj->Linefile()->GetLeftCol(), obj->Linefile()->GetRightLine(), obj->Linefile()->GetRightCol()); FOREACH_ATTRIBUTE(obj, mi, attr) { if (attr->Key()[0] == ' ' || attr->Value() == nullptr) @@ -1275,9 +1276,24 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma log("Importing module %s.\n", RTLIL::id2cstr(module->name)); } import_attributes(module->attributes, nl, nl); + module->set_string_attribute(ID::hdlname, nl->CellBaseName()); +#ifdef VERIFIC_VHDL_SUPPORT + if (nl->IsFromVhdl()) { + NameSpace name_space(0); + char *architecture_name = name_space.ReName(nl->Name()) ; + module->set_string_attribute(ID(architecture), (architecture_name) ? architecture_name : nl->Name()); + } +#endif + const char *param_name ; + const char *param_value ; + MapIter mi; + FOREACH_PARAMETER_OF_NETLIST(nl, mi, param_name, param_value) { + module->avail_parameters(RTLIL::escape_id(param_name)); + module->parameter_default_values[RTLIL::escape_id(param_name)] = verific_const(param_value); + } SetIter si; - MapIter mi, mi2; + MapIter mi2; Port *port; PortBus *portbus; Net *net; @@ -2488,51 +2504,71 @@ std::string verific_import(Design *design, const std::mapGetModule(top.c_str(), 1); - if (veri_module) { - veri_modules.InsertLast(veri_module); - if (veri_module->IsConfiguration()) { - VeriConfiguration *cfg = (VeriConfiguration*)veri_module; - VeriName *module_name = (VeriName*)cfg->GetTopModuleNames()->GetLast(); - VeriLibrary *lib = veri_module->GetLibrary() ; - if (module_name && module_name->IsHierName()) { - VeriName *prefix = module_name->GetPrefix() ; - const char *lib_name = (prefix) ? prefix->GetName() : 0 ; - if (!Strings::compare("work", lib_name)) lib = veri_file::GetLibrary(lib_name, 1) ; +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS + for (int static_elaborate = 1; static_elaborate >= 0; static_elaborate--) +#endif + { + Array veri_modules, vhdl_units; + + if (veri_lib) { + VeriModule *veri_module = veri_lib->GetModule(top.c_str(), 1); + if (veri_module) { + veri_modules.InsertLast(veri_module); + if (veri_module->IsConfiguration()) { + VeriConfiguration *cfg = (VeriConfiguration*)veri_module; + VeriName *module_name = (VeriName*)cfg->GetTopModuleNames()->GetLast(); + VeriLibrary *lib = veri_module->GetLibrary() ; + if (module_name && module_name->IsHierName()) { + VeriName *prefix = module_name->GetPrefix() ; + const char *lib_name = (prefix) ? prefix->GetName() : 0 ; + if (!Strings::compare("work", lib_name)) lib = veri_file::GetLibrary(lib_name, 1) ; + } + if (lib && module_name) + top = lib->GetModule(module_name->GetName(), 1)->GetName(); + } + } + +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS + if (!static_elaborate) +#endif + { + // Also elaborate all root modules since they may contain bind statements + MapIter mi; + FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) { + if (!veri_module->IsRootModule()) continue; + veri_modules.InsertLast(veri_module); } - if (lib && module_name) - top = lib->GetModule(module_name->GetName(), 1)->GetName(); } } - // Also elaborate all root modules since they may contain bind statements - MapIter mi; - FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) { - if (!veri_module->IsRootModule()) continue; - veri_modules.InsertLast(veri_module); - } - } - #ifdef VERIFIC_VHDL_SUPPORT - if (vhdl_lib) { - VhdlDesignUnit *vhdl_unit = vhdl_lib->GetPrimUnit(top.c_str()); - if (vhdl_unit) - vhdl_units.InsertLast(vhdl_unit); - } + if (vhdl_lib) { + VhdlDesignUnit *vhdl_unit = vhdl_lib->GetPrimUnit(top.c_str()); + if (vhdl_unit) + vhdl_units.InsertLast(vhdl_unit); + } #endif - netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, &verific_params); + +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS + if (static_elaborate) { + VerificExtensions::ElaborateAndRewrite("work", &veri_modules, &vhdl_units, &verific_params); + verific_error_msg.clear(); + continue; + } +#endif + + netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, &verific_params); + } } Netlist *nl; @@ -2545,7 +2581,7 @@ std::string verific_import(Design *design, const std::mapAddAtt(new Att(" \\top", NULL)); nl_todo.emplace(nl->CellBaseName(), nl); - cell_name = nl->Owner()->Name(); + cell_name = nl->CellBaseName(); } if (top.empty()) cell_name = top; @@ -2567,7 +2603,7 @@ std::string verific_import(Design *design, const std::mapfirst) == 0) { VerificImporter importer(false, false, false, false, false, false, false); nl_done[it->first] = it->second; - importer.import_netlist(design, nl, nl_todo, nl->Owner()->Name() == cell_name); + importer.import_netlist(design, nl, nl_todo, nl->CellBaseName() == cell_name); } nl_todo.erase(it); } @@ -3056,6 +3092,7 @@ struct VerificPass : public Pass { int argidx = 1; std::string work = "work"; bool is_work_set = false; + (void)is_work_set; veri_file::RegisterCallBackVerificStream(&verific_read_cb); if (GetSize(args) > argidx && (args[argidx] == "-set-error" || args[argidx] == "-set-warning" || @@ -3133,7 +3170,20 @@ struct VerificPass : public Pass { } veri_file::RemoveAllLOptions(); - veri_file::AddLOption("work"); + for (int i = argidx; i < GetSize(args); i++) + { + if (args[i] == "-work" && i+1 < GetSize(args)) { + work = args[++i]; + is_work_set = true; + continue; + } + if (args[i] == "-L" && i+1 < GetSize(args)) { + ++i; + continue; + } + break; + } + veri_file::AddLOption(work.c_str()); for (int i = argidx; i < GetSize(args); i++) { if (args[i] == "-work" && i+1 < GetSize(args)) { @@ -3141,7 +3191,7 @@ struct VerificPass : public Pass { continue; } if (args[i] == "-L" && i+1 < GetSize(args)) { - if (args[++i] == "work") + if (args[++i] == work) veri_file::RemoveAllLOptions(); continue; } @@ -3574,15 +3624,16 @@ struct VerificPass : public Pass { std::set top_mod_names; -#ifdef YOSYSHQ_VERIFIC_EXTENSIONS - VerificExtensions::ElaborateAndRewrite(work, ¶meters); - verific_error_msg.clear(); -#endif - if (!ppfile.empty()) - veri_file::PrettyPrint(ppfile.c_str(), nullptr, work.c_str()); - if (mode_all) { + +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS + VerificExtensions::ElaborateAndRewrite(work, ¶meters); + verific_error_msg.clear(); +#endif + if (!ppfile.empty()) + veri_file::PrettyPrint(ppfile.c_str(), nullptr, work.c_str()); + log("Running hier_tree::ElaborateAll().\n"); VeriLibrary *veri_lib = veri_file::GetLibrary(work.c_str(), 1); @@ -3607,67 +3658,93 @@ struct VerificPass : public Pass { if (argidx == GetSize(args)) cmd_error(args, argidx, "No top module specified.\n"); - VeriLibrary* veri_lib = veri_file::GetLibrary(work.c_str(), 1); -#ifdef VERIFIC_VHDL_SUPPORT - VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1); -#endif + Array *netlists = nullptr; - Array veri_modules, vhdl_units; - for (; argidx < GetSize(args); argidx++) +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS + for (int static_elaborate = 1; static_elaborate >= 0; static_elaborate--) +#endif { - const char *name = args[argidx].c_str(); - top_mod_names.insert(name); - VeriModule *veri_module = veri_lib ? veri_lib->GetModule(name, 1) : nullptr; - if (veri_module) { - if (veri_module->IsConfiguration()) { - log("Adding Verilog configuration '%s' to elaboration queue.\n", name); - veri_modules.InsertLast(veri_module); - - top_mod_names.erase(name); - - VeriConfiguration *cfg = (VeriConfiguration*)veri_module; - VeriName *module_name; - int i; - FOREACH_ARRAY_ITEM(cfg->GetTopModuleNames(), i, module_name) { - VeriLibrary *lib = veri_module->GetLibrary() ; - if (module_name && module_name->IsHierName()) { - VeriName *prefix = module_name->GetPrefix() ; - const char *lib_name = (prefix) ? prefix->GetName() : 0 ; - if (!Strings::compare("work", lib_name)) lib = veri_file::GetLibrary(lib_name, 1) ; - } - if (lib && module_name) - top_mod_names.insert(lib->GetModule(module_name->GetName(), 1)->GetName()); - } - } else { - log("Adding Verilog module '%s' to elaboration queue.\n", name); - veri_modules.InsertLast(veri_module); - } - continue; - } + VeriLibrary* veri_lib = veri_file::GetLibrary(work.c_str(), 1); #ifdef VERIFIC_VHDL_SUPPORT - VhdlDesignUnit *vhdl_unit = vhdl_lib ? vhdl_lib->GetPrimUnit(name) : nullptr; - if (vhdl_unit) { - log("Adding VHDL unit '%s' to elaboration queue.\n", name); - vhdl_units.InsertLast(vhdl_unit); + VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1); +#endif + + Array veri_modules, vhdl_units; + for (int i = argidx; i < GetSize(args); i++) + { + const char *name = args[i].c_str(); + top_mod_names.insert(name); + + VeriModule *veri_module = veri_lib ? veri_lib->GetModule(name, 1) : nullptr; + if (veri_module) { + if (veri_module->IsConfiguration()) { + log("Adding Verilog configuration '%s' to elaboration queue.\n", name); + veri_modules.InsertLast(veri_module); + + top_mod_names.erase(name); + + VeriConfiguration *cfg = (VeriConfiguration*)veri_module; + VeriName *module_name; + int i; + FOREACH_ARRAY_ITEM(cfg->GetTopModuleNames(), i, module_name) { + VeriLibrary *lib = veri_module->GetLibrary() ; + if (module_name && module_name->IsHierName()) { + VeriName *prefix = module_name->GetPrefix() ; + const char *lib_name = (prefix) ? prefix->GetName() : 0 ; + if (work != lib_name) lib = veri_file::GetLibrary(lib_name, 1) ; + } + if (lib && module_name) + top_mod_names.insert(lib->GetModule(module_name->GetName(), 1)->GetName()); + } + } else { + log("Adding Verilog module '%s' to elaboration queue.\n", name); + veri_modules.InsertLast(veri_module); + } + continue; + } +#ifdef VERIFIC_VHDL_SUPPORT + VhdlDesignUnit *vhdl_unit = vhdl_lib ? vhdl_lib->GetPrimUnit(name) : nullptr; + if (vhdl_unit) { + log("Adding VHDL unit '%s' to elaboration queue.\n", name); + vhdl_units.InsertLast(vhdl_unit); + continue; + } +#endif + log_error("Can't find module/unit '%s'.\n", name); + } + +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS + if (static_elaborate) { + VerificExtensions::ElaborateAndRewrite(work, &veri_modules, &vhdl_units, ¶meters); + verific_error_msg.clear(); +#endif + if (!ppfile.empty()) + veri_file::PrettyPrint(ppfile.c_str(), nullptr, work.c_str()); + +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS continue; } #endif - log_error("Can't find module/unit '%s'.\n", name); - } - - if (veri_lib) { - // Also elaborate all root modules since they may contain bind statements - MapIter mi; - VeriModule *veri_module; - FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) { - if (!veri_module->IsRootModule()) continue; - veri_modules.InsertLast(veri_module); + const char *lib_name = nullptr; + SetIter si; + FOREACH_SET_ITEM(veri_file::GetAllLOptions(), si, &lib_name) { + VeriLibrary* veri_lib = veri_file::GetLibrary(lib_name, 0); + if (veri_lib) { + // Also elaborate all root modules since they may contain bind statements + MapIter mi; + VeriModule *veri_module; + FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) { + if (!veri_module->IsRootModule()) continue; + veri_modules.InsertLast(veri_module); + } + } } + + log("Running hier_tree::Elaborate().\n"); + netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, ¶meters); } - log("Running hier_tree::Elaborate().\n"); - Array *netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, ¶meters); Netlist *nl; int i; @@ -3732,7 +3809,7 @@ struct VerificPass : public Pass { VerificImporter importer(mode_gates, mode_keep, mode_nosva, mode_names, mode_verific, mode_autocover, mode_fullinit); nl_done[it->first] = it->second; - importer.import_netlist(design, nl, nl_todo, top_mod_names.count(nl->Owner()->Name())); + importer.import_netlist(design, nl, nl_todo, top_mod_names.count(nl->CellBaseName())); } nl_todo.erase(it); } diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 1e82940bb..cb8c453c0 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -292,6 +292,65 @@ static void rewriteGenForDeclInit(AstNode *loop) substitute(incr); } +static void ensureAsgnExprAllowed() +{ + if (!sv_mode) + frontend_verilog_yyerror("Assignments within expressions are only supported in SystemVerilog mode."); + if (ast_stack.back()->type != AST_BLOCK) + frontend_verilog_yyerror("Assignments within expressions are only permitted within procedures."); +} + +// add a pre/post-increment/decrement statement +static const AstNode *addIncOrDecStmt(dict *stmt_attr, AstNode *lhs, + dict *op_attr, AST::AstNodeType op, + YYLTYPE begin, YYLTYPE end) +{ + AstNode *one = AstNode::mkconst_int(1, true); + AstNode *rhs = new AstNode(op, lhs->clone(), one); + if (op_attr != nullptr) + append_attr(rhs, op_attr); + AstNode *stmt = new AstNode(AST_ASSIGN_EQ, lhs, rhs); + SET_AST_NODE_LOC(stmt, begin, end); + if (stmt_attr != nullptr) + append_attr(stmt, stmt_attr); + ast_stack.back()->children.push_back(stmt); + return stmt; +} + +// create a pre/post-increment/decrement expression, and add the corresponding statement +static AstNode *addIncOrDecExpr(AstNode *lhs, dict *attr, AST::AstNodeType op, YYLTYPE begin, YYLTYPE end, bool undo) +{ + ensureAsgnExprAllowed(); + const AstNode *stmt = addIncOrDecStmt(nullptr, lhs, attr, op, begin, end); + log_assert(stmt->type == AST_ASSIGN_EQ); + AstNode *expr = stmt->children[0]->clone(); + if (undo) { + AstNode *minus_one = AstNode::mkconst_int(-1, true, 1); + expr = new AstNode(op, expr, minus_one); + } + SET_AST_NODE_LOC(expr, begin, end); + return expr; +} + +// add a binary operator assignment statement, e.g., a += b +static const AstNode *addAsgnBinopStmt(dict *attr, AstNode *lhs, AST::AstNodeType op, AstNode *rhs, YYLTYPE begin, YYLTYPE end) +{ + SET_AST_NODE_LOC(rhs, end, end); + if (op == AST_SHIFT_LEFT || op == AST_SHIFT_RIGHT || + op == AST_SHIFT_SLEFT || op == AST_SHIFT_SRIGHT) { + rhs = new AstNode(AST_TO_UNSIGNED, rhs); + SET_AST_NODE_LOC(rhs, end, end); + } + rhs = new AstNode(op, lhs->clone(), rhs); + AstNode *stmt = new AstNode(AST_ASSIGN_EQ, lhs, rhs); + SET_AST_NODE_LOC(rhs, begin, end); + SET_AST_NODE_LOC(stmt, begin, end); + ast_stack.back()->children.push_back(stmt); + if (attr != nullptr) + append_attr(stmt, attr); + return lhs; +} + %} %define api.prefix {frontend_verilog_yy} @@ -358,7 +417,7 @@ static void rewriteGenForDeclInit(AstNode *loop) %type integer_atom_type integer_vector_type %type attr case_attr %type struct_union -%type asgn_binop +%type asgn_binop inc_or_dec_op %type genvar_identifier %type specify_target @@ -2610,17 +2669,11 @@ simple_behavioral_stmt: SET_AST_NODE_LOC(node, @2, @5); append_attr(node, $1); } | - attr lvalue TOK_INCREMENT { - AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, new AstNode(AST_ADD, $2->clone(), AstNode::mkconst_int(1, true))); - ast_stack.back()->children.push_back(node); - SET_AST_NODE_LOC(node, @2, @3); - append_attr(node, $1); + attr lvalue attr inc_or_dec_op { + addIncOrDecStmt($1, $2, $3, $4, @1, @4); } | - attr lvalue TOK_DECREMENT { - AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, new AstNode(AST_SUB, $2->clone(), AstNode::mkconst_int(1, true))); - ast_stack.back()->children.push_back(node); - SET_AST_NODE_LOC(node, @2, @3); - append_attr(node, $1); + attr inc_or_dec_op attr lvalue { + addIncOrDecStmt($1, $4, $3, $2, @1, @4); } | attr lvalue OP_LE delay expr { AstNode *node = new AstNode(AST_ASSIGN_LE, $2, $5); @@ -2629,18 +2682,7 @@ simple_behavioral_stmt: append_attr(node, $1); } | attr lvalue asgn_binop delay expr { - AstNode *expr_node = $5; - if ($3 == AST_SHIFT_LEFT || $3 == AST_SHIFT_RIGHT || - $3 == AST_SHIFT_SLEFT || $3 == AST_SHIFT_SRIGHT) { - expr_node = new AstNode(AST_TO_UNSIGNED, expr_node); - SET_AST_NODE_LOC(expr_node, @5, @5); - } - AstNode *op_node = new AstNode($3, $2->clone(), expr_node); - AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, op_node); - SET_AST_NODE_LOC(op_node, @2, @5); - SET_AST_NODE_LOC(node, @2, @5); - ast_stack.back()->children.push_back(node); - append_attr(node, $1); + addAsgnBinopStmt($1, $2, $3, $5, @2, @5); }; asgn_binop: @@ -2657,6 +2699,12 @@ asgn_binop: TOK_SSHL_ASSIGN { $$ = AST_SHIFT_SLEFT; } | TOK_SSHR_ASSIGN { $$ = AST_SHIFT_SRIGHT; } ; +inc_or_dec_op: + // NOTE: These should only be permitted in SV mode, but Yosys has + // allowed them in all modes since support for them was added in 2017. + TOK_INCREMENT { $$ = AST_ADD; } | + TOK_DECREMENT { $$ = AST_SUB; } ; + for_initialization: TOK_ID '=' expr { AstNode *ident = new AstNode(AST_IDENTIFIER); @@ -3149,6 +3197,14 @@ expr: $$->children.push_back($6); SET_AST_NODE_LOC($$, @1, @$); append_attr($$, $3); + } | + inc_or_dec_op attr rvalue { + $$ = addIncOrDecExpr($3, $2, $1, @1, @3, false); + } | + // TODO: Attributes are allowed in the middle here, but they create some + // non-trivial conflicts that don't seem worth solving for now. + rvalue inc_or_dec_op { + $$ = addIncOrDecExpr($1, nullptr, $2, @1, @2, true); }; basic_expr: @@ -3436,6 +3492,17 @@ basic_expr: frontend_verilog_yyerror("Static cast is only supported in SystemVerilog mode."); $$ = new AstNode(AST_CAST_SIZE, $1, $4); SET_AST_NODE_LOC($$, @1, @4); + } | + '(' expr '=' expr ')' { + ensureAsgnExprAllowed(); + AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, $4); + ast_stack.back()->children.push_back(node); + SET_AST_NODE_LOC(node, @2, @4); + $$ = $2->clone(); + } | + '(' expr asgn_binop expr ')' { + ensureAsgnExprAllowed(); + $$ = addAsgnBinopStmt(nullptr, $2, $3, $4, @2, @4)-> clone(); }; concat_list: diff --git a/kernel/hashlib.h b/kernel/hashlib.h index b3f99bf73..9cf43da6c 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -90,6 +90,12 @@ template<> struct hash_ops : hash_int_ops return a; } }; +template<> struct hash_ops : hash_int_ops +{ + static inline unsigned int hash(uint64_t a) { + return mkhash((unsigned int)(a), (unsigned int)(a >> 32)); + } +}; template<> struct hash_ops { static inline bool cmp(const std::string &a, const std::string &b) { @@ -988,7 +994,7 @@ public: return !operator==(other); } - bool hash() const { + unsigned int hash() const { unsigned int hashval = mkhash_init; for (auto &it : entries) hashval ^= ops.hash(it.udata); diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 51d020913..ffbd4b3ff 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -313,18 +313,33 @@ RTLIL::Const RTLIL::Const::from_string(const std::string &str) std::string RTLIL::Const::decode_string() const { - std::string string; - string.reserve(GetSize(bits)/8); - for (int i = 0; i < GetSize(bits); i += 8) { + const int n = GetSize(bits); + const int n_over_8 = n / 8; + std::string s; + s.reserve(n_over_8); + int i = n_over_8 * 8; + if (i < n) { char ch = 0; - for (int j = 0; j < 8 && i + j < int (bits.size()); j++) - if (bits[i + j] == RTLIL::State::S1) + for (int j = 0; j < (n - i); j++) { + if (bits[i + j] == RTLIL::State::S1) { ch |= 1 << j; + } + } if (ch != 0) - string.append({ch}); + s.append({ch}); } - std::reverse(string.begin(), string.end()); - return string; + i -= 8; + for (; i >= 0; i -= 8) { + char ch = 0; + for (int j = 0; j < 8; j++) { + if (bits[i + j] == RTLIL::State::S1) { + ch |= 1 << j; + } + } + if (ch != 0) + s.append({ch}); + } + return s; } bool RTLIL::Const::is_fully_zero() const @@ -2677,6 +2692,19 @@ RTLIL::Cell* RTLIL::Module::addPow(RTLIL::IdString name, const RTLIL::SigSpec &s return cell; } +RTLIL::Cell* RTLIL::Module::addFa(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_x, const RTLIL::SigSpec &sig_y, const std::string &src) +{ + RTLIL::Cell *cell = addCell(name, ID($fa)); + cell->parameters[ID::WIDTH] = sig_a.size(); + cell->setPort(ID::A, sig_a); + cell->setPort(ID::B, sig_b); + cell->setPort(ID::C, sig_c); + cell->setPort(ID::X, sig_x); + cell->setPort(ID::Y, sig_y); + cell->set_src_attribute(src); + return cell; +} + RTLIL::Cell* RTLIL::Module::addSlice(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const offset, const std::string &src) { RTLIL::Cell *cell = addCell(name, ID($slice)); @@ -4031,13 +4059,17 @@ void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec unpack(); other->unpack(); + dict pattern_to_with; for (int i = 0; i < GetSize(pattern.bits_); i++) { if (pattern.bits_[i].wire != NULL) { - for (int j = 0; j < GetSize(bits_); j++) { - if (bits_[j] == pattern.bits_[i]) { - other->bits_[j] = with.bits_[i]; - } - } + pattern_to_with.emplace(pattern.bits_[i], i); + } + } + + for (int j = 0; j < GetSize(bits_); j++) { + auto it = pattern_to_with.find(bits_[j]); + if (it != pattern_to_with.end()) { + other->bits_[j] = with.bits_[it->second]; } } diff --git a/kernel/rtlil.h b/kernel/rtlil.h index c50d75e90..9c318eac9 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -308,10 +308,14 @@ namespace RTLIL bool operator!=(const char *rhs) const { return strcmp(c_str(), rhs) != 0; } char operator[](size_t i) const { - const char *p = c_str(); + const char *p = c_str(); +#ifndef NDEBUG for (; i != 0; i--, p++) log_assert(*p != 0); return *p; +#else + return *(p + i); +#endif } std::string substr(size_t pos = 0, size_t len = std::string::npos) const { @@ -1298,6 +1302,8 @@ public: RTLIL::Cell* addModFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addPow (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool a_signed = false, bool b_signed = false, const std::string &src = ""); + RTLIL::Cell* addFa (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_x, const RTLIL::SigSpec &sig_y, const std::string &src = ""); + RTLIL::Cell* addLogicNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addLogicAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addLogicOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); diff --git a/kernel/utils.h b/kernel/utils.h index d37f045ff..8fa223824 100644 --- a/kernel/utils.h +++ b/kernel/utils.h @@ -128,41 +128,103 @@ public: // A simple class for topological sorting // ------------------------------------------------ -template> -struct TopoSort +template , typename OPS = hash_ops> class TopoSort { - bool analyze_loops, found_loops; - std::map, C> database; - std::set> loops; - std::vector sorted; + public: + // We use this ordering of the edges in the adjacency matrix for + // exact compatibility with an older implementation. + struct IndirectCmp { + IndirectCmp(const std::vector &nodes) : node_cmp_(), nodes_(nodes) {} + bool operator()(int a, int b) const + { + log_assert(static_cast(a) < nodes_.size()); + log_assert(static_cast(b) < nodes_.size()); + return node_cmp_(nodes_[a], nodes_[b]); + } + const C node_cmp_; + const std::vector &nodes_; + }; - TopoSort() + bool analyze_loops; + std::map node_to_index; + std::vector> edges; + std::vector sorted; + std::set> loops; + + TopoSort() : indirect_cmp(nodes) { analyze_loops = true; found_loops = false; } - void node(T n) + int node(T n) { - if (database.count(n) == 0) - database[n] = std::set(); + auto rv = node_to_index.emplace(n, static_cast(nodes.size())); + if (rv.second) { + nodes.push_back(n); + edges.push_back(std::set(indirect_cmp)); + } + return rv.first->second; } - void edge(T left, T right) + void edge(int l_index, int r_index) { edges[r_index].insert(l_index); } + + void edge(T left, T right) { edge(node(left), node(right)); } + + bool has_node(const T &node) { return node_to_index.find(node) != node_to_index.end(); } + + bool sort() { - node(left); - database[right].insert(left); + log_assert(GetSize(node_to_index) == GetSize(edges)); + log_assert(GetSize(nodes) == GetSize(edges)); + + loops.clear(); + sorted.clear(); + found_loops = false; + + std::vector marked_cells(edges.size(), false); + std::vector active_cells(edges.size(), false); + std::vector active_stack; + sorted.reserve(edges.size()); + + for (const auto &it : node_to_index) + sort_worker(it.second, marked_cells, active_cells, active_stack); + + log_assert(GetSize(sorted) == GetSize(nodes)); + + return !found_loops; } - void sort_worker(const T &n, std::set &marked_cells, std::set &active_cells, std::vector &active_stack) + // Build the more expensive representation of edges for + // a few passes that use it directly. + std::map, C> get_database() { - if (active_cells.count(n)) { + std::map, C> database; + for (size_t i = 0; i < nodes.size(); ++i) { + std::set converted_edge_set; + for (int other_node : edges[i]) { + converted_edge_set.insert(nodes[other_node]); + } + database.emplace(nodes[i], converted_edge_set); + } + return database; + } + + private: + bool found_loops; + std::vector nodes; + const IndirectCmp indirect_cmp; + + void sort_worker(const int root_index, std::vector &marked_cells, std::vector &active_cells, std::vector &active_stack) + { + if (active_cells[root_index]) { found_loops = true; if (analyze_loops) { std::set loop; - for (int i = GetSize(active_stack)-1; i >= 0; i--) { - loop.insert(active_stack[i]); - if (active_stack[i] == n) + for (int i = GetSize(active_stack) - 1; i >= 0; i--) { + const int index = active_stack[i]; + loop.insert(nodes[index]); + if (index == root_index) break; } loops.insert(loop); @@ -170,42 +232,24 @@ struct TopoSort return; } - if (marked_cells.count(n)) + if (marked_cells[root_index]) return; - if (!database.at(n).empty()) - { + if (!edges[root_index].empty()) { if (analyze_loops) - active_stack.push_back(n); - active_cells.insert(n); + active_stack.push_back(root_index); + active_cells[root_index] = true; - for (auto &left_n : database.at(n)) + for (int left_n : edges[root_index]) sort_worker(left_n, marked_cells, active_cells, active_stack); if (analyze_loops) active_stack.pop_back(); - active_cells.erase(n); + active_cells[root_index] = false; } - marked_cells.insert(n); - sorted.push_back(n); - } - - bool sort() - { - loops.clear(); - sorted.clear(); - found_loops = false; - - std::set marked_cells; - std::set active_cells; - std::vector active_stack; - - for (auto &it : database) - sort_worker(it.first, marked_cells, active_cells, active_stack); - - log_assert(GetSize(sorted) == GetSize(database)); - return !found_loops; + marked_cells[root_index] = true; + sorted.push_back(nodes[root_index]); } }; diff --git a/kernel/yosys.cc b/kernel/yosys.cc index bd8dded4b..4409dc91d 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -175,48 +175,6 @@ int ceil_log2(int x) #endif } -std::string stringf(const char *fmt, ...) -{ - std::string string; - va_list ap; - - va_start(ap, fmt); - string = vstringf(fmt, ap); - va_end(ap); - - return string; -} - -std::string vstringf(const char *fmt, va_list ap) -{ - std::string string; - char *str = NULL; - -#if defined(_WIN32 )|| defined(__CYGWIN__) - int sz = 64, rc; - while (1) { - va_list apc; - va_copy(apc, ap); - str = (char*)realloc(str, sz); - rc = vsnprintf(str, sz, fmt, apc); - va_end(apc); - if (rc >= 0 && rc < sz) - break; - sz *= 2; - } -#else - if (vasprintf(&str, fmt, ap) < 0) - str = NULL; -#endif - - if (str != NULL) { - string = str; - free(str); - } - - return string; -} - int readsome(std::istream &f, char *s, int n) { int rc = int(f.readsome(s, n)); @@ -1395,8 +1353,12 @@ void shell(RTLIL::Design *design) if ((command = fgets(command_buffer, 4096, stdin)) == NULL) break; #endif - if (command[strspn(command, " \t\r\n")] == 0) + if (command[strspn(command, " \t\r\n")] == 0) { +#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) + free(command); +#endif continue; + } #if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) add_history(command); #endif @@ -1418,10 +1380,17 @@ void shell(RTLIL::Design *design) log_reset_stack(); } design->check(); +#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) + if (command) + free(command); +#endif } if (command == NULL) printf("exit\n"); - +#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) + else + free(command); +#endif recursion_counter--; log_cmd_error_throw = false; } diff --git a/kernel/yosys.h b/kernel/yosys.h index 29415ff84..97a79861e 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -272,8 +272,64 @@ inline void memhasher() { if (memhasher_active) memhasher_do(); } void yosys_banner(); int ceil_log2(int x) YS_ATTRIBUTE(const); + +inline std::string vstringf(const char *fmt, va_list ap) +{ + // For the common case of strings shorter than 128, save a heap + // allocation by using a stack allocated buffer. + const int kBufSize = 128; + char buf[kBufSize]; + buf[0] = '\0'; + va_list apc; + va_copy(apc, ap); + int n = vsnprintf(buf, kBufSize, fmt, apc); + va_end(apc); + if (n < kBufSize) + return std::string(buf); + + std::string string; + char *str = NULL; +#if defined(_WIN32 )|| defined(__CYGWIN__) + int sz = 2 * kBufSize, rc; + while (1) { + va_copy(apc, ap); + str = (char*)realloc(str, sz); + rc = vsnprintf(str, sz, fmt, apc); + va_end(apc); + if (rc >= 0 && rc < sz) + break; + sz *= 2; + } + if (str != NULL) { + string = str; + free(str); + } + return string; +#else + if (vasprintf(&str, fmt, ap) < 0) + str = NULL; + if (str != NULL) { + string = str; + free(str); + } + return string; +#endif +} + std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2)); -std::string vstringf(const char *fmt, va_list ap); + +inline std::string stringf(const char *fmt, ...) +{ + std::string string; + va_list ap; + + va_start(ap, fmt); + string = vstringf(fmt, ap); + va_end(ap); + + return string; +} + int readsome(std::istream &f, char *s, int n); std::string next_token(std::string &text, const char *sep = " \t\r\n", bool long_strings = false); std::vector split_tokens(const std::string &text, const char *sep = " \t\r\n"); diff --git a/passes/cmds/autoname.cc b/passes/cmds/autoname.cc index 6019c6153..737bd3e58 100644 --- a/passes/cmds/autoname.cc +++ b/passes/cmds/autoname.cc @@ -24,8 +24,8 @@ PRIVATE_NAMESPACE_BEGIN int autoname_worker(Module *module, const dict& wire_score) { - dict> proposed_cell_names; - dict> proposed_wire_names; + dict> proposed_cell_names; + dict> proposed_wire_names; int best_score = -1; for (auto cell : module->selected_cells()) { @@ -36,7 +36,7 @@ int autoname_worker(Module *module, const dict& wire_score) if (bit.wire != nullptr && bit.wire->name[0] != '$') { if (suffix.empty()) suffix = stringf("_%s_%s", log_id(cell->type), log_id(conn.first)); - IdString new_name(bit.wire->name.str() + suffix); + string new_name(bit.wire->name.str() + suffix); int score = wire_score.at(bit.wire); if (cell->output(conn.first)) score = 0; score = 10000*score + new_name.size(); @@ -54,7 +54,7 @@ int autoname_worker(Module *module, const dict& wire_score) if (bit.wire != nullptr && bit.wire->name[0] == '$' && !bit.wire->port_id) { if (suffix.empty()) suffix = stringf("_%s", log_id(conn.first)); - IdString new_name(cell->name.str() + suffix); + string new_name(cell->name.str() + suffix); int score = wire_score.at(bit.wire); if (cell->output(conn.first)) score = 0; score = 10000*score + new_name.size(); @@ -71,7 +71,7 @@ int autoname_worker(Module *module, const dict& wire_score) for (auto &it : proposed_cell_names) { if (best_score*2 < it.second.first) continue; - IdString n = module->uniquify(it.second.second); + IdString n = module->uniquify(IdString(it.second.second)); log_debug("Rename cell %s in %s to %s.\n", log_id(it.first), log_id(module), log_id(n)); module->rename(it.first, n); } @@ -79,7 +79,7 @@ int autoname_worker(Module *module, const dict& wire_score) for (auto &it : proposed_wire_names) { if (best_score*2 < it.second.first) continue; - IdString n = module->uniquify(it.second.second); + IdString n = module->uniquify(IdString(it.second.second)); log_debug("Rename wire %s in %s to %s.\n", log_id(it.first), log_id(module), log_id(n)); module->rename(it.first, n); } diff --git a/passes/cmds/dft_tag.cc b/passes/cmds/dft_tag.cc index 9fd356ef6..2b2340dab 100644 --- a/passes/cmds/dft_tag.cc +++ b/passes/cmds/dft_tag.cc @@ -405,7 +405,7 @@ struct DftTagWorker { auto &sig_y = cell->getPort(ID::Y); auto sig_a = cell->getPort(ID::A); auto sig_b = cell->getPort(ID::B); - if (cell->type.in(ID($and), ID($or))) { + if (cell->type.in(ID($and), ID($or), ID($xor), ID($xnor))) { sig_a.extend_u0(GetSize(sig_y), cell->getParam(ID::A_SIGNED).as_bool()); sig_b.extend_u0(GetSize(sig_y), cell->getParam(ID::B_SIGNED).as_bool()); } @@ -669,12 +669,12 @@ struct DftTagWorker { auto &sig_y = cell->getPort(ID::Y); auto sig_a = cell->getPort(ID::A); - if (cell->type.in(ID($reduce_or), ID($reduce_bool), ID($logic_not))) - sig_a = autoNot(NEW_ID, sig_a); - auto group_sig_a = tag_group_signal(tag, sig_a); auto tag_sig_a = tag_signal(tag, sig_a); + if (cell->type.in(ID($reduce_or), ID($reduce_bool), ID($logic_not))) + sig_a = autoNot(NEW_ID, sig_a); + auto filled = autoOr(NEW_ID, sig_a, group_sig_a); auto prop = autoReduceAnd(NEW_ID, filled); diff --git a/passes/cmds/glift.cc b/passes/cmds/glift.cc index 439ded076..8553b02a5 100644 --- a/passes/cmds/glift.cc +++ b/passes/cmds/glift.cc @@ -582,7 +582,7 @@ struct GliftPass : public Pass { for (auto cell : module->selected_cells()) { RTLIL::Module *tpl = design->module(cell->type); if (tpl != nullptr) { - if (topo_modules.database.count(tpl) == 0) + if (!topo_modules.has_node(tpl)) worklist.push_back(tpl); topo_modules.edge(tpl, module); non_top_modules.insert(cell->type); diff --git a/passes/cmds/scc.cc b/passes/cmds/scc.cc index 81881832c..197bd9319 100644 --- a/passes/cmds/scc.cc +++ b/passes/cmds/scc.cc @@ -27,7 +27,6 @@ #include "kernel/log.h" #include #include -#include USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -39,18 +38,18 @@ struct SccWorker SigMap sigmap; CellTypes ct, specifyCells; - std::set workQueue; - std::map> cellToNextCell; - std::map cellToPrevSig, cellToNextSig; + pool workQueue; + dict> cellToNextCell; + dict cellToPrevSig, cellToNextSig; - std::map> cellLabels; - std::map cellDepth; - std::set cellsOnStack; + dict> cellLabels; + dict cellDepth; + pool cellsOnStack; std::vector cellStack; int labelCounter; - std::map cell2scc; - std::vector> sccList; + dict cell2scc; + std::vector> sccList; void run(RTLIL::Cell *cell, int depth, int maxDepth) { @@ -85,7 +84,7 @@ struct SccWorker else { log("Found an SCC:"); - std::set scc; + pool scc; while (cellsOnStack.count(cell) > 0) { RTLIL::Cell *c = cellStack.back(); cellStack.pop_back(); @@ -199,11 +198,11 @@ struct SccWorker for (auto cell : workQueue) { - cellToNextCell[cell] = sigToNextCells.find(cellToNextSig[cell]); + sigToNextCells.find(cellToNextSig[cell], cellToNextCell[cell]); if (!nofeedbackMode && cellToNextCell[cell].count(cell)) { log("Found an SCC:"); - std::set scc; + pool scc; log(" %s", RTLIL::id2cstr(cell->name)); cell2scc[cell] = sccList.size(); scc.insert(cell); @@ -231,7 +230,7 @@ struct SccWorker { for (int i = 0; i < int(sccList.size()); i++) { - std::set &cells = sccList[i]; + pool &cells = sccList[i]; RTLIL::SigSpec prevsig, nextsig, sig; for (auto cell : cells) { @@ -295,7 +294,7 @@ struct SccPass : public Pass { } void execute(std::vector args, RTLIL::Design *design) override { - std::map setAttr; + dict setAttr; bool allCellTypes = false; bool selectMode = false; bool nofeedbackMode = false; diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc index 0dc5c452c..d57cbc6bb 100644 --- a/passes/cmds/show.cc +++ b/passes/cmds/show.cc @@ -575,7 +575,7 @@ struct ShowWorker } else { net_conn_map[right_node].in.insert({stringf("x%d", single_idx_count), GetSize(conn.first)}); net_conn_map[left_node].out.insert({stringf("x%d", single_idx_count), GetSize(conn.first)}); - fprintf(f, "x%d [shape=box, style=rounded, label=\"BUF\", %s];\n", single_idx_count++, findColor(conn).c_str()); + fprintf(f, "x%d [shape=point, %s];\n", single_idx_count++, findColor(conn).c_str()); } } } diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 46773a344..3eadd35c6 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -424,13 +424,19 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons for (auto &bit : sig) outbit_to_cell[bit].insert(cell); } - cells.node(cell); + cells.node(cell); } - for (auto &it_right : cell_to_inbit) - for (auto &it_sigbit : it_right.second) - for (auto &it_left : outbit_to_cell[it_sigbit]) - cells.edge(it_left, it_right.first); + // Build the graph for the topological sort. + for (auto &it_right : cell_to_inbit) { + const int r_index = cells.node(it_right.first); + for (auto &it_sigbit : it_right.second) { + for (auto &it_left : outbit_to_cell[it_sigbit]) { + const int l_index = cells.node(it_left); + cells.edge(l_index, r_index); + } + } + } cells.sort(); diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc index e9d98cd43..248ba8091 100644 --- a/passes/opt/opt_merge.cc +++ b/passes/opt/opt_merge.cc @@ -41,7 +41,6 @@ struct OptMergeWorker CellTypes ct; int total_count; - SHA1 checksum; static void sort_pmux_conn(dict &conn) { @@ -78,7 +77,7 @@ struct OptMergeWorker return str; } - std::string hash_cell_parameters_and_connections(const RTLIL::Cell *cell) + uint64_t hash_cell_parameters_and_connections(const RTLIL::Cell *cell) { vector hash_conn_strings; std::string hash_string = cell->type.str() + "\n"; @@ -149,8 +148,7 @@ struct OptMergeWorker for (auto it : hash_conn_strings) hash_string += it; - checksum.update(hash_string); - return checksum.final(); + return std::hash{}(hash_string); } bool compare_cell_parameters_and_connections(const RTLIL::Cell *cell1, const RTLIL::Cell *cell2) @@ -268,13 +266,13 @@ struct OptMergeWorker } did_something = false; - dict sharemap; + dict sharemap; for (auto cell : cells) { if ((!mode_share_all && !ct.cell_known(cell->type)) || !cell->known()) continue; - auto hash = hash_cell_parameters_and_connections(cell); + uint64_t hash = hash_cell_parameters_and_connections(cell); auto r = sharemap.insert(std::make_pair(hash, cell)); if (!r.second) { if (compare_cell_parameters_and_connections(cell, r.first->second)) { diff --git a/passes/opt/share.cc b/passes/opt/share.cc index abef71937..586bd9dfe 100644 --- a/passes/opt/share.cc +++ b/passes/opt/share.cc @@ -1032,7 +1032,7 @@ struct ShareWorker } bool found_scc = !toposort.sort(); - topo_cell_drivers = std::move(toposort.database); + topo_cell_drivers = toposort.get_database(); if (found_scc && toposort.analyze_loops) for (auto &loop : toposort.loops) { diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc index a7ef64282..c2257b720 100644 --- a/passes/pmgen/Makefile.inc +++ b/passes/pmgen/Makefile.inc @@ -42,7 +42,8 @@ GENFILES += passes/pmgen/peepopt_pm.h passes/pmgen/peepopt.o: passes/pmgen/peepopt_pm.h $(eval $(call add_extra_objs,passes/pmgen/peepopt_pm.h)) -PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul.pmg +PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul_right.pmg +PEEPOPT_PATTERN += passes/pmgen/peepopt_shiftmul_left.pmg PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN) diff --git a/passes/pmgen/README.md b/passes/pmgen/README.md index 39560839f..3205be1b5 100644 --- a/passes/pmgen/README.md +++ b/passes/pmgen/README.md @@ -212,7 +212,7 @@ second argument, and the matcher will iterate over those options: index port(eq, BA) === bar set eq_ab AB set eq_ba BA - generate + endmatch Notice how `define` can be used to define additional local variables similar to the loop variables defined by `slice` and `choice`. diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc index 9a497c914..aef464d79 100644 --- a/passes/pmgen/peepopt.cc +++ b/passes/pmgen/peepopt.cc @@ -24,11 +24,8 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN bool did_something; -dict initbits; -pool rminitbits; #include "passes/pmgen/peepopt_pm.h" -#include "generate.h" struct PeepoptPass : public Pass { PeepoptPass() : Pass("peepopt", "collection of peephole optimizers") { } @@ -40,38 +37,29 @@ struct PeepoptPass : public Pass { log("\n"); log("This pass applies a collection of peephole optimizers to the current design.\n"); log("\n"); + log("This pass employs the following rules:\n"); + log("\n"); + log(" * muldiv - Replace (A*B)/B with A\n"); + log("\n"); + log(" * shiftmul - Replace A>>(B*C) with A'>>(B< args, RTLIL::Design *design) override { - std::string genmode; - log_header(design, "Executing PEEPOPT pass (run peephole optimizers).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { - if (args[argidx] == "-generate" && argidx+1 < args.size()) { - genmode = args[++argidx]; - continue; - } break; } extra_args(args, argidx, design); - if (!genmode.empty()) - { - initbits.clear(); - rminitbits.clear(); - - if (genmode == "shiftmul") - GENERATE_PATTERN(peepopt_pm, shiftmul); - else if (genmode == "muldiv") - GENERATE_PATTERN(peepopt_pm, muldiv); - else - log_abort(); - return; - } - for (auto module : design->selected_modules()) { did_something = true; @@ -79,47 +67,14 @@ struct PeepoptPass : public Pass { while (did_something) { did_something = false; - initbits.clear(); - rminitbits.clear(); peepopt_pm pm(module); - for (auto w : module->wires()) { - auto it = w->attributes.find(ID::init); - if (it != w->attributes.end()) { - SigSpec sig = pm.sigmap(w); - Const val = it->second; - int len = std::min(GetSize(sig), GetSize(val)); - for (int i = 0; i < len; i++) { - if (sig[i].wire == nullptr) - continue; - if (val[i] != State::S0 && val[i] != State::S1) - continue; - initbits[sig[i]] = val[i]; - } - } - } - pm.setup(module->selected_cells()); - pm.run_shiftmul(); + pm.run_shiftmul_right(); + pm.run_shiftmul_left(); pm.run_muldiv(); - - for (auto w : module->wires()) { - auto it = w->attributes.find(ID::init); - if (it != w->attributes.end()) { - SigSpec sig = pm.sigmap(w); - Const &val = it->second; - int len = std::min(GetSize(sig), GetSize(val)); - for (int i = 0; i < len; i++) { - if (rminitbits.count(sig[i])) - val[i] = State::Sx; - } - } - } - - initbits.clear(); - rminitbits.clear(); } } } diff --git a/passes/pmgen/peepopt_shiftmul.pmg b/passes/pmgen/peepopt_shiftmul.pmg deleted file mode 100644 index d71fbf744..000000000 --- a/passes/pmgen/peepopt_shiftmul.pmg +++ /dev/null @@ -1,92 +0,0 @@ -pattern shiftmul -// -// Optimize mul+shift pairs that result from expressions such as foo[s*W+:W] -// - -state shamt - -match shift - select shift->type.in($shift, $shiftx, $shr) -endmatch - -code shamt - shamt = port(shift, \B); - if (shamt.empty()) - reject; - if (shamt[GetSize(shamt)-1] == State::S0) { - do { - shamt.remove(GetSize(shamt)-1); - if (shamt.empty()) - reject; - } while (shamt[GetSize(shamt)-1] == State::S0); - } else - if (shift->type.in($shift, $shiftx) && param(shift, \B_SIGNED).as_bool()) { - reject; - } - if (GetSize(shamt) > 20) - reject; -endcode - -match mul - select mul->type.in($mul) - select port(mul, \A).is_fully_const() || port(mul, \B).is_fully_const() - index port(mul, \Y) === shamt - filter !param(mul, \A_SIGNED).as_bool() -endmatch - -code -{ - IdString const_factor_port = port(mul, \A).is_fully_const() ? \A : \B; - Const const_factor_cnst = port(mul, const_factor_port).as_const(); - int const_factor = const_factor_cnst.as_int(); - - if (GetSize(const_factor_cnst) == 0) - reject; - - if (GetSize(const_factor_cnst) > 20) - reject; - - if (GetSize(port(shift, \Y)) > const_factor) - reject; - - int factor_bits = ceil_log2(const_factor); - SigSpec mul_din = port(mul, const_factor_port == \A ? \B : \A); - - if (GetSize(shamt) < factor_bits+GetSize(mul_din)) - reject; - - did_something = true; - log("shiftmul pattern in %s: shift=%s, mul=%s\n", log_id(module), log_id(shift), log_id(mul)); - - int new_const_factor = 1 << factor_bits; - SigSpec padding(State::Sx, new_const_factor-const_factor); - SigSpec old_a = port(shift, \A), new_a; - int trunc = 0; - - if (GetSize(old_a) % const_factor != 0) { - trunc = const_factor - GetSize(old_a) % const_factor; - old_a.append(SigSpec(State::Sx, trunc)); - } - - for (int i = 0; i*const_factor < GetSize(old_a); i++) { - SigSpec slice = old_a.extract(i*const_factor, const_factor); - new_a.append(slice); - new_a.append(padding); - } - - if (trunc > 0) - new_a.remove(GetSize(new_a)-trunc, trunc); - - SigSpec new_b = {mul_din, SigSpec(State::S0, factor_bits)}; - if (param(shift, \B_SIGNED).as_bool()) - new_b.append(State::S0); - - shift->setPort(\A, new_a); - shift->setParam(\A_WIDTH, GetSize(new_a)); - shift->setPort(\B, new_b); - shift->setParam(\B_WIDTH, GetSize(new_b)); - - blacklist(shift); - accept; -} -endcode diff --git a/passes/pmgen/peepopt_shiftmul_left.pmg b/passes/pmgen/peepopt_shiftmul_left.pmg new file mode 100644 index 000000000..607f8368c --- /dev/null +++ b/passes/pmgen/peepopt_shiftmul_left.pmg @@ -0,0 +1,160 @@ +pattern shiftmul_left +// +// Optimize mul+shift pairs that result from expressions such as foo[s*W+:W] +// + +match shift + select shift->type.in($shift, $shiftx, $shl) + select shift->type.in($shl) || param(shift, \B_SIGNED).as_bool() + filter !port(shift, \B).empty() +endmatch + +match neg + if shift->type.in($shift, $shiftx) + select neg->type == $neg + index port(neg, \Y) === port(shift, \B) + filter !port(shift, \A).empty() +endmatch + +// the left shift amount +state shift_amount +// log2 scale factor in interpreting of shift_amount +// due to zero padding on the shift cell's B port +state log2scale + +code shift_amount log2scale + if (neg) { + // case of `$shift`, `$shiftx` + shift_amount = port(neg, \A); + if (!param(neg, \A_SIGNED).as_bool()) + shift_amount.append(State::S0); + } else { + // case of `$shl` + shift_amount = port(shift, \B); + if (!param(shift, \B_SIGNED).as_bool()) + shift_amount.append(State::S0); + } + + // at this point shift_amount is signed, make + // sure we can never go negative + if (shift_amount.bits().back() != State::S0) + reject; + + while (shift_amount.bits().back() == State::S0) { + shift_amount.remove(GetSize(shift_amount) - 1); + if (shift_amount.empty()) reject; + } + + log2scale = 0; + while (shift_amount[0] == State::S0) { + shift_amount.remove(0); + if (shift_amount.empty()) reject; + log2scale++; + } + + if (GetSize(shift_amount) > 20) + reject; +endcode + +state mul_din +state mul_const + +match mul + select mul->type.in($mul) + index port(mul, \Y) === shift_amount + filter !param(mul, \A_SIGNED).as_bool() + + choice constport {\A, \B} + filter port(mul, constport).is_fully_const() + + define varport (constport == \A ? \B : \A) + set mul_const SigSpec({port(mul, constport), SigSpec(State::S0, log2scale)}).as_const() + // get mul_din unmapped (so no `port()` shorthand) + // because we will be using it to set the \A port + // on the shift cell, and we want to stay close + // to the original design + set mul_din mul->getPort(varport) +endmatch + +code +{ + if (mul_const.empty() || GetSize(mul_const) > 20) + reject; + + // make sure there's no overlap in the signal + // selections by the shiftmul pattern + if (GetSize(port(shift, \A)) > mul_const.as_int()) + reject; + + int factor_bits = ceil_log2(mul_const.as_int()); + // make sure the multiplication never wraps around + if (GetSize(shift_amount) < factor_bits + GetSize(mul_din)) + reject; + + if (neg) { + // make sure the negation never wraps around + if (GetSize(port(shift, \B)) < factor_bits + GetSize(mul_din) + + log2scale + 1) + reject; + } + + did_something = true; + log("left shiftmul pattern in %s: shift=%s, mul=%s\n", log_id(module), log_id(shift), log_id(mul)); + + int const_factor = mul_const.as_int(); + int new_const_factor = 1 << factor_bits; + SigSpec padding(State::Sm, new_const_factor-const_factor); + SigSpec old_y = port(shift, \Y), new_y; + int trunc = 0; + + if (GetSize(old_y) % const_factor != 0) { + trunc = const_factor - GetSize(old_y) % const_factor; + old_y.append(SigSpec(State::Sm, trunc)); + } + + for (int i = 0; i*const_factor < GetSize(old_y); i++) { + SigSpec slice = old_y.extract(i*const_factor, const_factor); + new_y.append(slice); + new_y.append(padding); + } + + if (trunc > 0) + new_y.remove(GetSize(new_y)-trunc, trunc); + + { + // Now replace occurences of Sm in new_y with bits + // of a dummy wire + int padbits = 0; + for (auto bit : new_y) + if (bit == SigBit(State::Sm)) + padbits++; + + SigSpec padwire = module->addWire(NEW_ID, padbits); + + for (int i = new_y.size() - 1; i >= 0; i--) + if (new_y[i] == SigBit(State::Sm)) { + new_y[i] = padwire.bits().back(); + padwire.remove(padwire.size() - 1); + } + } + + SigSpec new_b = {mul_din, SigSpec(State::S0, factor_bits)}; + + shift->setPort(\Y, new_y); + shift->setParam(\Y_WIDTH, GetSize(new_y)); + if (shift->type == $shl) { + if (param(shift, \B_SIGNED).as_bool()) + new_b.append(State::S0); + shift->setPort(\B, new_b); + shift->setParam(\B_WIDTH, GetSize(new_b)); + } else { + SigSpec b_neg = module->addWire(NEW_ID, GetSize(new_b) + 1); + module->addNeg(NEW_ID, new_b, b_neg); + shift->setPort(\B, b_neg); + shift->setParam(\B_WIDTH, GetSize(b_neg)); + } + + blacklist(shift); + accept; +} +endcode diff --git a/passes/pmgen/peepopt_shiftmul_right.pmg b/passes/pmgen/peepopt_shiftmul_right.pmg new file mode 100644 index 000000000..71e098023 --- /dev/null +++ b/passes/pmgen/peepopt_shiftmul_right.pmg @@ -0,0 +1,113 @@ +pattern shiftmul_right +// +// Optimize mul+shift pairs that result from expressions such as foo[s*W+:W] +// + +match shift + select shift->type.in($shift, $shiftx, $shr) + filter !port(shift, \B).empty() +endmatch + +// the right shift amount +state shift_amount +// log2 scale factor in interpreting of shift_amount +// due to zero padding on the shift cell's B port +state log2scale + +code shift_amount log2scale + shift_amount = port(shift, \B); + if (shift->type.in($shr) || !param(shift, \B_SIGNED).as_bool()) + shift_amount.append(State::S0); + + // at this point shift_amount is signed, make + // sure we can never go negative + if (shift_amount.bits().back() != State::S0) + reject; + + while (shift_amount.bits().back() == State::S0) { + shift_amount.remove(GetSize(shift_amount) - 1); + if (shift_amount.empty()) reject; + } + + log2scale = 0; + while (shift_amount[0] == State::S0) { + shift_amount.remove(0); + if (shift_amount.empty()) reject; + log2scale++; + } + + if (GetSize(shift_amount) > 20) + reject; +endcode + +state mul_din +state mul_const + +match mul + select mul->type.in($mul) + index port(mul, \Y) === shift_amount + filter !param(mul, \A_SIGNED).as_bool() + + choice constport {\A, \B} + filter port(mul, constport).is_fully_const() + + define varport (constport == \A ? \B : \A) + set mul_const SigSpec({port(mul, constport), SigSpec(State::S0, log2scale)}).as_const() + // get mul_din unmapped (so no `port()` shorthand) + // because we will be using it to set the \A port + // on the shift cell, and we want to stay close + // to the original design + set mul_din mul->getPort(varport) +endmatch + +code +{ + if (mul_const.empty() || GetSize(mul_const) > 20) + reject; + + // make sure there's no overlap in the signal + // selections by the shiftmul pattern + if (GetSize(port(shift, \Y)) > mul_const.as_int()) + reject; + + int factor_bits = ceil_log2(mul_const.as_int()); + // make sure the multiplication never wraps around + if (GetSize(shift_amount) + log2scale < factor_bits + GetSize(mul_din)) + reject; + + did_something = true; + log("right shiftmul pattern in %s: shift=%s, mul=%s\n", log_id(module), log_id(shift), log_id(mul)); + + int const_factor = mul_const.as_int(); + int new_const_factor = 1 << factor_bits; + SigSpec padding(State::Sx, new_const_factor-const_factor); + SigSpec old_a = port(shift, \A), new_a; + int trunc = 0; + + if (GetSize(old_a) % const_factor != 0) { + trunc = const_factor - GetSize(old_a) % const_factor; + old_a.append(SigSpec(State::Sx, trunc)); + } + + for (int i = 0; i*const_factor < GetSize(old_a); i++) { + SigSpec slice = old_a.extract(i*const_factor, const_factor); + new_a.append(slice); + new_a.append(padding); + } + + if (trunc > 0) + new_a.remove(GetSize(new_a)-trunc, trunc); + + SigSpec new_b = {mul_din, SigSpec(State::S0, factor_bits)}; + if (param(shift, \B_SIGNED).as_bool()) + new_b.append(State::S0); + + shift->setPort(\A, new_a); + shift->setParam(\A_WIDTH, GetSize(new_a)); + shift->setPort(\B, new_b); + shift->setParam(\B_WIDTH, GetSize(new_b)); + + blacklist(shift); + accept; +} +endcode diff --git a/passes/sat/recover_names.cc b/passes/sat/recover_names.cc index 2d7e7f01c..4c30a3632 100644 --- a/passes/sat/recover_names.cc +++ b/passes/sat/recover_names.cc @@ -29,13 +29,6 @@ USING_YOSYS_NAMESPACE -template<> struct hashlib::hash_ops : hashlib::hash_int_ops -{ - static inline unsigned int hash(uint64_t a) { - return mkhash((unsigned int)(a), (unsigned int)(a >> 32)); - } -}; - PRIVATE_NAMESPACE_BEGIN // xorshift128 params @@ -453,7 +446,7 @@ struct RecoverNamesWorker { pool comb_whiteboxes, buffer_types; // class -> (gold, (gate, inverted)) - dict, dict>> cls2bits; + dict, dict>> cls2bits; void analyse_boxes() { diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index 1e6645303..a8516470c 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -111,6 +111,7 @@ struct SimShared int step = 0; std::vector triggered_assertions; bool serious_asserts = false; + bool initstate = true; }; void zinit(State &v) @@ -218,9 +219,13 @@ struct SimInstance log_assert(module); if (module->get_blackbox_attribute(true)) - log_error("Cannot simulate blackbox module %s (instanced at %s).\n", + log_error("Cannot simulate blackbox module %s (instantiated at %s).\n", log_id(module->name), hiername().c_str()); + if (module->has_processes()) + log_error("Found processes in simulation hierarchy (in module %s at %s). Run 'proc' first.\n", + log_id(module), hiername().c_str()); + if (parent) { log_assert(parent->children.count(instance) == 0); parent->children[instance] = this; @@ -578,7 +583,7 @@ struct SimInstance Const data = Const(State::Sx, mem.width << port.wide_log2); if (port.clk_enable) - log_error("Memory %s.%s has clocked read ports. Run 'memory' with -nordff.\n", log_id(module), log_id(mem.memid)); + log_error("Memory %s.%s has clocked read ports. Run 'memory_nordff' to transform the circuit to remove those.\n", log_id(module), log_id(mem.memid)); if (addr.is_fully_def()) { int addr_int = addr.as_int(); @@ -1356,6 +1361,8 @@ struct SimWorker : SimShared set_inports(clock, State::Sx); set_inports(clockn, State::Sx); + top->set_initstate_outputs(initstate ? State::S1 : State::S0); + update(false); register_output_step(0); @@ -1372,6 +1379,9 @@ struct SimWorker : SimShared update(true); register_output_step(10*cycle + 5); + if (cycle == 0) + top->set_initstate_outputs(State::S0); + if (debug) log("\n===== %d =====\n", 10*cycle + 10); else if (verbose) @@ -1953,7 +1963,7 @@ struct SimWorker : SimShared if (yw.steps.empty()) { log_warning("Yosys witness file `%s` contains no time steps\n", yw.filename.c_str()); } else { - top->set_initstate_outputs(State::S1); + top->set_initstate_outputs(initstate ? State::S1 : State::S0); set_yw_state(yw, hierarchy, 0); set_yw_clocks(yw, hierarchy, true); initialize_stable_past(); @@ -2546,6 +2556,9 @@ struct SimPass : public Pass { log(" -n \n"); log(" number of clock cycles to simulate (default: 20)\n"); log("\n"); + log(" -noinitstate\n"); + log(" do not activate $initstate cells during the first cycle\n"); + log("\n"); log(" -a\n"); log(" use all nets in VCD/FST operations, not just those with public names\n"); log("\n"); @@ -2646,6 +2659,10 @@ struct SimPass : public Pass { worker.cycles_set = true; continue; } + if (args[argidx] == "-noinitstate") { + worker.initstate = false; + continue; + } if (args[argidx] == "-rstlen" && argidx+1 < args.size()) { worker.rstlen = atoi(args[++argidx].c_str()); continue; diff --git a/passes/techmap/booth.cc b/passes/techmap/booth.cc index e74916852..e1e6b360a 100644 --- a/passes/techmap/booth.cc +++ b/passes/techmap/booth.cc @@ -52,6 +52,9 @@ or in generic synthesis call with -booth argument: synth -top my_design -booth */ +//FIXME: These debug prints are broken now, should be fixed or removed. +//#define DEBUG_CPA + #include "kernel/sigtools.h" #include "kernel/yosys.h" @@ -66,170 +69,89 @@ struct BoothPassWorker { BoothPassWorker(RTLIL::Module *module) : module(module), sigmap(module) { booth_counter = 0; } - // Helper routines for building architecture subcomponents - - RTLIL::Wire *mk_wireFromSigSpec(const SigSpec &v) - { - - auto g = module->addCell(NEW_ID, ID($pos)); - Wire *ret = module->addWire(NEW_ID, 1); - g->setPort(ID::A, v); - g->setPort(ID::Y, ret); - g->setParam(ID::A_WIDTH, 1); - g->setParam(ID::Y_WIDTH, 1); - g->setParam(ID::A_SIGNED, false); - return ret; - } - - // fuse wires. - void join_wires_with_buffer(RTLIL::Wire *ip, RTLIL::Wire *op) - { - std::string wire_name = "join_"; - auto g = module->addCell(new_id(wire_name, __LINE__, ""), ID($pos)); - g->setParam(ID::A_WIDTH, 1); - g->setParam(ID::Y_WIDTH, 1); - g->setParam(ID::A_SIGNED, false); - g->setPort(ID::A, ip); - g->setPort(ID::Y, op); - } - - // Unary gate - RTLIL::Wire *mk_ugate1(const RTLIL::IdString &red_typ, std::string &name, RTLIL::Wire *ip1, std::string &op_name) - { - std::string op_wire_name; - if (op_name.empty()) - op_wire_name = name + "_o"; - else - op_wire_name = op_name; - RTLIL::Wire *ret = module->addWire(new_id(op_wire_name, __LINE__, ""), 1); - auto g = module->addCell(new_id(name, __LINE__, ""), red_typ); - g->setPort(ID::A, ip1); - g->setPort(ID::Y, ret); - g->setParam(ID::A_SIGNED, false); - g->setParam(ID::A_WIDTH, 1); - g->setParam(ID::Y_WIDTH, 1); - return ret; - } - - // Binary gate - RTLIL::Wire *mk_ugate2(const RTLIL::IdString &red_typ, std::string &name, RTLIL::Wire *ip1, RTLIL::Wire *ip2, std::string &op_name) - { - auto g = module->addCell(new_id(name, __LINE__, ""), red_typ); - std::string op_wire_name; - if (op_name.empty()) - op_wire_name = name + "_o"; - else - op_wire_name = op_name; - - auto ret = module->addWire(new_id(op_wire_name, __LINE__, ""), 1); - - g->setPort(ID::A, ip1); - g->setPort(ID::B, ip2); - g->setPort(ID::Y, ret); - g->setParam(ID::A_SIGNED, false); - g->setParam(ID::B_SIGNED, false); - g->setParam(ID::A_WIDTH, 1); - g->setParam(ID::B_WIDTH, 1); - g->setParam(ID::Y_WIDTH, 1); - return ret; - } - // Booth unsigned decoder lsb - void BuildBur4d_lsb(std::string &name, RTLIL::Wire *lsb_i, RTLIL::Wire *one_i, RTLIL::Wire *s_i, RTLIL::Wire *&ppij_o, - std::string op_wire_name) + SigBit Bur4d_lsb(std::string name, SigBit lsb_i, SigBit one_i, SigBit s_i) { - std::string empty; - auto and_op = mk_ugate2(ID($and), name, lsb_i, one_i, empty); - ppij_o = mk_ugate2(ID($xor), name, and_op, s_i, op_wire_name); + SigBit and_op = module->AndGate(NEW_ID_SUFFIX(name), lsb_i, one_i); + return module->XorGate(NEW_ID_SUFFIX(name), and_op, s_i); } // Booth unsigned radix4 decoder - void BuildBur4d_n(std::string &name, RTLIL::Wire *yn_i, RTLIL::Wire *ynm1_i, RTLIL::Wire *one_i, RTLIL::Wire *two_i, RTLIL::Wire *s_i, - RTLIL::Wire *&ppij_o) + SigBit Bur4d_n(std::string name, SigBit yn_i, SigBit ynm1_i, SigBit one_i, SigBit two_i, SigBit s_i) { // ppij = ((yn & one) | (ynm1 & two)) ^ s; - std::string empty; - auto an1 = mk_ugate2(ID($and), name, yn_i, one_i, empty); - auto an2 = mk_ugate2(ID($and), name, ynm1_i, two_i, empty); - auto or1 = mk_ugate2(ID($or), name, an1, an2, empty); - ppij_o = mk_ugate2(ID($xor), name, s_i, or1, empty); + SigBit an1 = module->AndGate(NEW_ID_SUFFIX(name), yn_i, one_i); + SigBit an2 = module->AndGate(NEW_ID_SUFFIX(name), ynm1_i, two_i); + SigBit or1 = module->OrGate(NEW_ID_SUFFIX(name), an1, an2); + return module->XorGate(NEW_ID_SUFFIX(name), s_i, or1); } // Booth unsigned radix4 decoder - void BuildBur4d_msb(std::string &name, RTLIL::Wire *msb_i, RTLIL::Wire *two_i, RTLIL::Wire *s_i, RTLIL::Wire *&ppij_o) + SigBit Bur4d_msb(std::string name, SigBit msb_i, SigBit two_i, SigBit s_i) { // ppij = (msb & two) ^ s; - std::string empty; - auto an1 = mk_ugate2(ID($and), name, msb_i, two_i, empty); - ppij_o = mk_ugate2(ID($xor), name, s_i, an1, empty); + SigBit an1 = module->AndGate(NEW_ID_SUFFIX(name), msb_i, two_i); + return module->XorGate(NEW_ID_SUFFIX(name), s_i, an1); } // half adder, used in CPA - void BuildHa(std::string &name, RTLIL::Wire *a_i, RTLIL::Wire *b_i, RTLIL::Wire *&s_o, RTLIL::Wire *&c_o) + void BuildHa(std::string name, SigBit a_i, SigBit b_i, SigBit &s_o, SigBit &c_o) { - std::string empty; - s_o = mk_ugate2(ID($xor), name, a_i, b_i, empty); - c_o = mk_ugate2(ID($and), name, a_i, b_i, empty); + s_o = module->XorGate(NEW_ID_SUFFIX(name), a_i, b_i); + c_o = module->AndGate(NEW_ID_SUFFIX(name), a_i, b_i); } // Booth unsigned radix 4 encoder - void BuildBur4e(std::string &name, RTLIL::Wire *y0_i, RTLIL::Wire *y1_i, RTLIL::Wire *y2_i, - - RTLIL::Wire *&one_o, RTLIL::Wire *&two_o, RTLIL::Wire *&s_o, RTLIL::Wire *&sb_o) + void BuildBur4e(std::string name, SigBit y0_i, SigBit y1_i, SigBit y2_i, + SigBit &one_o, SigBit &two_o, SigBit &s_o, SigBit &sb_o) { - - std::string empty; - one_o = mk_ugate2(ID($xor), name, y0_i, y1_i, empty); + one_o = module->XorGate(NEW_ID_SUFFIX(name), y0_i, y1_i); s_o = y2_i; - sb_o = mk_ugate1(ID($not), name, y2_i, empty); - auto inv_y1_xor_y2 = mk_ugate1(ID($not), name, mk_ugate2(ID($xor), name, y1_i, y2_i, empty), empty); - two_o = mk_ugate1(ID($not), name, mk_ugate2(ID($or), name, inv_y1_xor_y2, one_o, empty), empty); + sb_o = module->NotGate(NEW_ID_SUFFIX(name), y2_i); + SigBit y1_xnor_y2 = module->XnorGate(NEW_ID_SUFFIX(name), y1_i, y2_i); + two_o = module->NorGate(NEW_ID_SUFFIX(name), y1_xnor_y2, one_o); } - void BuildBr4e(std::string &name, RTLIL::Wire *y2_m1_i, - RTLIL::Wire *y2_i, // y2i - RTLIL::Wire *y2_p1_i, - - RTLIL::Wire *&negi_o, RTLIL::Wire *&twoi_n_o, RTLIL::Wire *&onei_n_o, RTLIL::Wire *&cori_o) + void BuildBr4e(std::string name, SigBit y2_m1_i, + SigBit y2_i, // y2i + SigBit y2_p1_i, + SigBit &negi_o, SigBit &twoi_n_o, SigBit &onei_n_o, SigBit &cori_o) { + auto y2_p1_n = module->NotGate(NEW_ID_SUFFIX(name), y2_p1_i); + auto y2_n = module->NotGate(NEW_ID_SUFFIX(name), y2_i); + auto y2_m1_n = module->NotGate(NEW_ID_SUFFIX(name), y2_m1_i); - std::string empty; - auto y2_p1_n = mk_ugate1(ID($not), name, y2_p1_i, empty); - auto y2_n = mk_ugate1(ID($not), name, y2_i, empty); - auto y2_m1_n = mk_ugate1(ID($not), name, y2_m1_i, empty); + negi_o = y2_p1_i; - // negi_o = y2_p1_i - negi_o = mk_ugate1(ID($pos), name, y2_p1_i, empty); // twoi_n = ~( // (y2_p1_n & y2_i & y2_m1_i) | // (y2_p1 & y2_n & y2_m1_n) // ) - auto and3_1 = mk_ugate2(ID($and), name, y2_p1_n, mk_ugate2(ID($and), name, y2_i, y2_m1_i, empty), empty); - auto and3_2 = mk_ugate2(ID($and), name, y2_p1_i, mk_ugate2(ID($and), name, y2_n, y2_m1_n, empty), empty); + twoi_n_o = module->NorGate(NEW_ID_SUFFIX(name), + module->AndGate(NEW_ID_SUFFIX(name), y2_p1_n, module->AndGate(NEW_ID_SUFFIX(name), y2_i, y2_m1_i)), + module->AndGate(NEW_ID_SUFFIX(name), y2_p1_i, module->AndGate(NEW_ID_SUFFIX(name), y2_n, y2_m1_n)) + ); - twoi_n_o = mk_ugate1(ID($not), name, mk_ugate2(ID($or), name, and3_1, and3_2, empty), empty); // onei_n = ~(y2_m1_i ^ y2_i); - onei_n_o = mk_ugate1(ID($not), name, mk_ugate2(ID($xor), name, y2_m1_i, y2_i, empty), empty); + onei_n_o = module->XnorGate(NEW_ID_SUFFIX(name), y2_m1_i, y2_i); // cori = (y2_m1_n | y2_n) & y2_p1_i; - cori_o = mk_ugate2(ID($and), name, y2_p1_i, mk_ugate2(ID($or), name, y2_m1_n, y2_n, empty), empty); + cori_o = module->AndGate(NEW_ID_SUFFIX(name), module->OrGate(NEW_ID_SUFFIX(name), y2_m1_n, y2_n), y2_p1_i); } // // signed booth radix 4 decoder // - void BuildBr4d(std::string &name, RTLIL::Wire *nxj_m1_i, RTLIL::Wire *twoi_n_i, RTLIL::Wire *xj_i, RTLIL::Wire *negi_i, RTLIL::Wire *onei_n_i, - - RTLIL::Wire *&ppij_o, RTLIL::Wire *&nxj_o) + void BuildBr4d(std::string name, SigBit nxj_m1_i, SigBit twoi_n_i, SigBit xj_i, SigBit negi_i, SigBit onei_n_i, + SigBit &ppij_o, SigBit &nxj_o) { - - std::string empty; // nxj_in = xnor(xj,negi) // nxj_o = xnj_in, // ppij = ~( (nxj_m1_i | twoi_n_i) & (nxj_int | onei_n_i)); - nxj_o = mk_ugate2(ID($xnor), name, xj_i, negi_i, empty); - RTLIL::Wire *or1 = mk_ugate2(ID($or), name, nxj_m1_i, twoi_n_i, empty); - RTLIL::Wire *or2 = mk_ugate2(ID($or), name, nxj_o, onei_n_i, empty); - ppij_o = mk_ugate1(ID($not), name, mk_ugate2(ID($and), name, or1, or2, empty), empty); + nxj_o = module->XnorGate(NEW_ID_SUFFIX(name), xj_i, negi_i); + ppij_o = module->NandGate(NEW_ID_SUFFIX(name), + module->OrGate(NEW_ID_SUFFIX(name), nxj_m1_i, twoi_n_i), + module->OrGate(NEW_ID_SUFFIX(name), nxj_o, onei_n_i) + ); } /* @@ -237,12 +159,9 @@ struct BoothPassWorker { using non-booth encoded logic. We can save a booth encoder for the first couple of bits. */ - void BuildBoothQ1(std::string &name, RTLIL::Wire *negi_i, RTLIL::Wire *cori_i, RTLIL::Wire *x0_i, RTLIL::Wire *x1_i, RTLIL::Wire *y0_i, - RTLIL::Wire *y1_i, - - RTLIL::Wire *&nxj_o, RTLIL::Wire *&cor_o, RTLIL::Wire *&pp0_o, RTLIL::Wire *&pp1_o - - ) + void BuildBoothQ1(std::string name, SigBit negi_i, SigBit cori_i, SigBit x0_i, SigBit x1_i, SigBit y0_i, + SigBit y1_i, + SigBit &nxj_o, SigBit &cor_o, SigBit &pp0_o, SigBit &pp1_o) { /* assign NXJO = ~(X1 ^ NEGI); @@ -255,122 +174,105 @@ struct BoothPassWorker { //correction propagation assign CORO = (~PP1 & ~PP0)? CORI : 1'b0; */ - std::string empty; - nxj_o = mk_ugate2(ID($xnor), name, x1_i, negi_i, empty); - pp0_o = mk_ugate2(ID($and), name, x0_i, y0_i, empty); - RTLIL::Wire *pp1_1_int = mk_ugate2(ID($and), name, x1_i, y0_i, empty); - RTLIL::Wire *pp1_2_int = mk_ugate2(ID($and), name, x0_i, y1_i, empty); - pp1_o = mk_ugate2(ID($xor), name, pp1_1_int, pp1_2_int, empty); + nxj_o = module->XnorGate(NEW_ID_SUFFIX(name), x1_i, negi_i); + pp0_o = module->AndGate(NEW_ID_SUFFIX(name), x0_i, y0_i); + SigBit pp1_1_int = module->AndGate(NEW_ID_SUFFIX(name), x1_i, y0_i); + SigBit pp1_2_int = module->AndGate(NEW_ID_SUFFIX(name), x0_i, y1_i); + pp1_o = module->XorGate(NEW_ID_SUFFIX(name), pp1_1_int, pp1_2_int); - RTLIL::Wire *pp1_nor_pp0 = mk_ugate1(ID($not), name, mk_ugate2(ID($or), name, pp1_o, pp0_o, empty), empty); - cor_o = mk_ugate2(ID($and), name, pp1_nor_pp0, cori_i, empty); + SigBit pp1_nor_pp0 = module->NorGate(NEW_ID_SUFFIX(name), pp1_o, pp0_o); + cor_o = module->AndGate(NEW_ID_SUFFIX(name), pp1_nor_pp0, cori_i); } void run() { for (auto cell : module->selected_cells()) { - if (cell->type.in(ID($mul))) { - RTLIL::SigSpec A = sigmap(cell->getPort(ID::A)); - RTLIL::SigSpec B = sigmap(cell->getPort(ID::B)); - RTLIL::SigSpec Y = sigmap(cell->getPort(ID::Y)); - if (GetSize(A) >= 4 && GetSize(B) >= 4 && GetSize(Y) >= 8 && - ((cell->getParam(ID::A_SIGNED).as_bool() && cell->getParam(ID::B_SIGNED).as_bool()) || - (!cell->getParam(ID::A_SIGNED).as_bool() && !cell->getParam(ID::B_SIGNED).as_bool()))) { - bool is_signed = false; - if (cell->getParam(ID::A_SIGNED).as_bool()) { - log(" By passing macc inferencing for signed multiplier -- generating booth\n"); - is_signed = true; - } else - log(" By passing macc inferencing for unsigned multiplier -- generating booth\n"); + if (cell->type != ID($mul)) + continue; - int x_sz = GetSize(A); - int y_sz = GetSize(B); - int z_sz = GetSize(Y); + SigSpec A = cell->getPort(ID::A); + SigSpec B = cell->getPort(ID::B); + SigSpec Y = cell->getPort(ID::Y); + int x_sz = GetSize(A), y_sz = GetSize(B), z_sz = GetSize(Y); - // To simplify the generator size the arguments - // to be the same. Then allow logic synthesis to - // clean things up. Size to biggest + if (x_sz < 4 || y_sz < 4 || z_sz < 8) { + log_debug("Not mapping cell %s sized at %dx%x, %x: size below threshold\n", + log_id(cell), x_sz, y_sz, z_sz); + continue; + } - int x_sz_revised = x_sz; - int y_sz_revised = y_sz; + log_assert(cell->getParam(ID::A_SIGNED).as_bool() == cell->getParam(ID::B_SIGNED).as_bool()); + bool is_signed = cell->getParam(ID::A_SIGNED).as_bool(); - if (x_sz != y_sz) { - if (x_sz < y_sz) { - if (y_sz % 2 != 0) { - x_sz_revised = y_sz + 1; - y_sz_revised = y_sz + 1; - } else - x_sz_revised = y_sz; + log("Mapping cell %s to %s Booth multiplier\n", log_id(cell), is_signed ? "signed" : "unsigned"); - } else { - if (x_sz % 2 != 0) { - y_sz_revised = x_sz + 1; - x_sz_revised = x_sz + 1; - } else - y_sz_revised = x_sz; - } + // To simplify the generator size the arguments + // to be the same. Then allow logic synthesis to + // clean things up. Size to biggest + + int x_sz_revised = x_sz; + int y_sz_revised = y_sz; + + if (x_sz != y_sz) { + if (x_sz < y_sz) { + if (y_sz % 2 != 0) { + x_sz_revised = y_sz + 1; + y_sz_revised = y_sz + 1; } else { - if (x_sz % 2 != 0) { - y_sz_revised = y_sz + 1; - x_sz_revised = x_sz + 1; - } + x_sz_revised = y_sz; + } + } else { + if (x_sz % 2 != 0) { + y_sz_revised = x_sz + 1; + x_sz_revised = x_sz + 1; + } else { + y_sz_revised = x_sz; } - - log_assert((x_sz_revised == y_sz_revised) && (x_sz_revised % 2 == 0) && (y_sz_revised % 2 == 0)); - - Wire *expanded_A = module->addWire(NEW_ID, x_sz_revised); - Wire *expanded_B = module->addWire(NEW_ID, y_sz_revised); - - std::string buf_name = "expand_a_buf_"; - auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setParam(ID::A_WIDTH, x_sz); - buf->setParam(ID::Y_WIDTH, x_sz_revised); - buf->setPort(ID::A, SigSpec(A)); - buf->setParam(ID::A_SIGNED, is_signed ? true : false); - buf->setPort(ID::Y, SigSpec(expanded_A)); - - buf_name = "expand_b_buf_"; - buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setPort(ID::A, SigSpec(B)); - buf->setParam(ID::A_WIDTH, y_sz); - buf->setParam(ID::Y_WIDTH, y_sz_revised); - buf->setParam(ID::A_SIGNED, is_signed ? true : false); - buf->setPort(ID::Y, SigSpec(expanded_B)); - - // Make sure output domain is big enough to take - // all combinations. - // Later logic synthesis will kill unused - // portions of the output domain. - - unsigned required_op_size = x_sz_revised + y_sz_revised; - Wire *expanded_Y = module->addWire(NEW_ID, required_op_size); - // now connect the expanded_Y with a tap to fill out sig Spec Y - buf_name = "reducer_buf_"; - buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setPort(ID::A, expanded_Y); - buf->setParam(ID::A_WIDTH, required_op_size); - buf->setParam(ID::Y_WIDTH, z_sz); // The real user width - buf->setParam(ID::A_SIGNED, is_signed ? true : false); - // wire in output Y - buf->setPort(ID::Y, SigSpec(Y)); - - if (is_signed == false) /* unsigned multiplier */ - CreateBoothUMult(module, x_sz_revised, y_sz_revised, required_op_size, - expanded_A, // multiplicand - expanded_B, // multiplier(scanned) - expanded_Y // result - ); - else /*signed multiplier */ - CreateBoothSMult(module, x_sz_revised, y_sz_revised, required_op_size, - expanded_A, // multiplicand - expanded_B, // multiplier(scanned) - expanded_Y // result (sized) - ); - module->remove(cell); - booth_counter++; - continue; + } + } else { + if (x_sz % 2 != 0) { + y_sz_revised = y_sz + 1; + x_sz_revised = x_sz + 1; } } + + log_assert((x_sz_revised == y_sz_revised) && (x_sz_revised % 2 == 0) && (y_sz_revised % 2 == 0)); + + + A.extend_u0(x_sz_revised, is_signed); + B.extend_u0(y_sz_revised, is_signed); + + // Make sure output domain is big enough to take + // all combinations. + // Later logic synthesis will kill unused + // portions of the output domain. + + int required_op_size = x_sz_revised + y_sz_revised; + + if (required_op_size != z_sz) { + SigSpec expanded_Y = module->addWire(NEW_ID, required_op_size); + SigSpec Y_driver = expanded_Y; + Y_driver.extend_u0(Y.size(), is_signed); + module->connect(Y, Y_driver); + Y = expanded_Y; + } + log_assert(GetSize(Y) == required_op_size); + + if (!is_signed) /* unsigned multiplier */ + CreateBoothUMult(module, + A, // multiplicand + B, // multiplier(scanned) + Y // result + ); + else /* signed multiplier */ + CreateBoothSMult(module, + A, // multiplicand + B, // multiplier(scanned) + Y // result (sized) + ); + + module->remove(cell); + booth_counter++; } } @@ -382,19 +284,17 @@ struct BoothPassWorker { extra row of decoders and extended multiplier */ - void CreateBoothUMult(RTLIL::Module *module, int x_sz, int y_sz, int z_sz, - RTLIL::Wire *X, // multiplicand - RTLIL::Wire *Y, // multiplier - RTLIL::Wire *Z) + void CreateBoothUMult(RTLIL::Module *module, + SigSpec X, // multiplicand + SigSpec Y, // multiplier + SigSpec Z) { // result + int x_sz = X.size(), z_sz = Z.size(); - std::vector one_int; - std::vector two_int; - std::vector s_int; - std::vector sb_int; + SigSpec one_int, two_int, s_int, sb_int; int encoder_count = 0; - BuildBoothUMultEncoders(Y, y_sz, one_int, two_int, s_int, sb_int, module, encoder_count); + BuildBoothUMultEncoders(Y, one_int, two_int, s_int, sb_int, module, encoder_count); // Build the decoder rows // format of each Partial product to be passed to CSA @@ -404,31 +304,10 @@ struct BoothPassWorker { // Shift // Sign bit to be added // - std::vector, int, RTLIL::Wire *>> ppij_int; - - static int constant_ix; - constant_ix++; - std::string buf_name = "constant_buf_" + std::to_string(constant_ix); - auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - RTLIL::Wire *constant_one = module->addWire(new_id(buf_name, __LINE__, ""), 1); - buf->setPort(ID::A, State::S1); - buf->setParam(ID::A_WIDTH, 1); - buf->setParam(ID::Y_WIDTH, 1); - buf->setParam(ID::A_SIGNED, true); - buf->setPort(ID::Y, constant_one); - - constant_ix++; - buf_name = "constant_buf_" + std::to_string(constant_ix); - buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - RTLIL::Wire *constant_zero = module->addWire(new_id(buf_name, __LINE__, ""), 1); - buf->setPort(ID::A, State::S0); - buf->setParam(ID::A_WIDTH, 1); - buf->setParam(ID::Y_WIDTH, 1); - buf->setParam(ID::A_SIGNED, true); - buf->setPort(ID::Y, constant_zero); + std::vector> ppij_int; // Row 0: special case 1. Format S/.S.S.C.Data - std::vector ppij_row_0; + SigSpec ppij_row_0; BuildBoothUMultDecoderRow0(module, X, s_int, sb_int, one_int, two_int, ppij_row_0); // data, shift, sign @@ -436,11 +315,11 @@ struct BoothPassWorker { for (int i = 1; i < encoder_count - 2; i++) { // format 1,S.Data.shift = encoder_ix*2,sign = sb_int[i] - std::vector ppij_row_n; + SigSpec ppij_row_n; BuildBoothUMultDecoderRowN(module, X, // multiplicand - one_int[i], two_int[i], s_int[i], sb_int[i], ppij_row_n, constant_one, i, + one_int[i], two_int[i], s_int[i], sb_int[i], ppij_row_n, i, false, // include sign false // include constant ); @@ -450,18 +329,18 @@ struct BoothPassWorker { // Build second to last row // format S/,Data + sign bit - std::vector ppij_row_em1; + SigSpec ppij_row_em1; BuildBoothUMultDecoderRowN(module, X, one_int[encoder_count - 2], two_int[encoder_count - 2], s_int[encoder_count - 2], - sb_int[encoder_count - 2], ppij_row_em1, constant_one, encoder_count - 2, + sb_int[encoder_count - 2], ppij_row_em1, encoder_count - 2, false, // include sign true // no constant ); ppij_int.push_back(std::make_tuple(ppij_row_em1, (encoder_count - 2) * 2, s_int[encoder_count - 2])); // Build last row // format Data + sign bit - std::vector ppij_row_e; + SigSpec ppij_row_e; BuildBoothUMultDecoderRowN(module, X, one_int[encoder_count - 1], two_int[encoder_count - 1], s_int[encoder_count - 1], - sb_int[encoder_count - 1], ppij_row_e, constant_one, encoder_count - 1, + sb_int[encoder_count - 1], ppij_row_e, encoder_count - 1, true, // no sign true // no constant ); @@ -471,13 +350,13 @@ struct BoothPassWorker { // DebugDumpPP(ppij_int); // Summation of Partial Products (Wallace Tree) - std::vector> aligned_pp; + std::vector aligned_pp; aligned_pp.resize(encoder_count + 1); // make an entirely redundant row // just for sign bit in lsb. (We then filter this out). // resize all to be same size as z for (int i = 0; i < encoder_count + 1; i++) - aligned_pp[i].resize(z_sz); + aligned_pp[i].extend_u0(z_sz); AlignPP(x_sz, z_sz, ppij_int, aligned_pp); @@ -485,8 +364,8 @@ struct BoothPassWorker { // Later on yosys will clean up unused constants // DebugDumpAlignPP(aligned_pp); - std::vector s_vec; - std::vector c_vec; + SigSpec s_vec; + SigSpec c_vec; std::vector> debug_csa_trees; debug_csa_trees.resize(z_sz); @@ -504,84 +383,59 @@ struct BoothPassWorker { */ void BuildBoothUMultDecoderRow0(RTLIL::Module *module, - RTLIL::Wire *X, // multiplicand - std::vector &s_int, std::vector &sb_int, std::vector &one_int, - std::vector &two_int, std::vector &ppij_vec) + SigSpec X, // multiplicand + SigSpec s_int, SigSpec sb_int, SigSpec one_int, + SigSpec two_int, SigSpec &ppij_vec) { (void)module; int x_sz = GetSize(X); + SigBit ppij; // lsb - std::string dec_name = "row0_lsb_dec"; - - RTLIL::Wire *ppij; - std::string ppij_name = "ppij_0_0"; - BuildBur4d_lsb(dec_name, mk_wireFromSigSpec(SigSpec(X, 0, 1)), one_int[0], s_int[0], ppij, ppij_name); - ppij_vec.push_back(ppij); + ppij_vec.append(Bur4d_lsb("row0_lsb_dec", X[0], one_int[0], s_int[0])); // 1..xsize -1 - for (int i = 1; i < x_sz; i++) { - dec_name = "row0_dec_" + std::to_string(i); - RTLIL::Wire *ppij; - BuildBur4d_n(dec_name, mk_wireFromSigSpec(SigSpec(X, i, 1)), mk_wireFromSigSpec(SigSpec(X, i - 1, 1)), one_int[0], two_int[0], - s_int[0], ppij); - ppij_vec.push_back(ppij); - } + for (int i = 1; i < x_sz; i++) + ppij_vec.append(Bur4d_n(stringf("row0_dec_%d", i), X[i], X[i - 1], + one_int[0], two_int[0], s_int[0])); // The redundant bit. Duplicate decoding of last bit. - dec_name = "row0_dec_msb"; - BuildBur4d_msb(dec_name, mk_wireFromSigSpec(SigSpec(X, x_sz - 1, 1)), two_int[0], s_int[0], ppij); - ppij_vec.push_back(ppij); + ppij_vec.append(Bur4d_msb("row0_dec_msb", X[x_sz - 1], two_int[0], s_int[0])); // append the sign bits - ppij_vec.push_back(s_int[0]); - ppij_vec.push_back(s_int[0]); - ppij_vec.push_back(sb_int[0]); + ppij_vec.append(s_int[0]); + ppij_vec.append(s_int[0]); + ppij_vec.append(sb_int[0]); } // Build a generic row of decoders. void BuildBoothUMultDecoderRowN(RTLIL::Module *module, - RTLIL::Wire *X, // multiplicand - RTLIL::Wire *one_int, RTLIL::Wire *two_int, RTLIL::Wire *s_int, RTLIL::Wire *sb_int, - std::vector &ppij_vec, RTLIL::Wire *constant_one, int row_ix, bool no_sign, bool no_constant) + SigSpec X, // multiplicand + SigSpec one_int, SigSpec two_int, SigSpec s_int, SigSpec sb_int, + SigSpec &ppij_vec, int row_ix, bool no_sign, bool no_constant) { (void)module; int x_sz = GetSize(X); // lsb - std::string ppij_name = "ppij_" + std::to_string(row_ix) + "_0"; - RTLIL::Wire *ppij = nullptr; - std::string empty; - std::string dec_name = "row" + std::to_string(row_ix) + "_lsb_dec"; - BuildBur4d_lsb(dec_name, mk_wireFromSigSpec(SigSpec(X, 0, 1)), one_int, s_int, ppij, empty); - - ppij_vec.push_back(ppij); + ppij_vec.append(Bur4d_lsb(stringf("row_%d_lsb_dec", row_ix), X[0], one_int, s_int)); // core bits - for (int i = 1; i < x_sz; i++) { - - dec_name = "row_" + std::to_string(row_ix) + "_dec_" + std::to_string(i); - RTLIL::Wire *ppij = nullptr; - BuildBur4d_n(dec_name, mk_wireFromSigSpec(SigSpec(X, i, 1)), mk_wireFromSigSpec(SigSpec(X, i - 1, 1)), one_int, two_int, - s_int, ppij); - ppij_vec.push_back(ppij); - } + for (int i = 1; i < x_sz; i++) + ppij_vec.append(Bur4d_n(stringf("row_%d_dec_%d", row_ix, i), X[i], X[i - 1], + one_int, two_int, s_int)); // redundant bit - - dec_name = "row_dec_red"; - BuildBur4d_msb(dec_name, mk_wireFromSigSpec(SigSpec(X, x_sz - 1, 1)), two_int, s_int, ppij); - ppij_vec.push_back(ppij); + ppij_vec.append(Bur4d_msb("row_dec_red", X[x_sz - 1], two_int, s_int)); // sign bit - if (no_sign == false) // if no sign is false then make a sign bit - ppij_vec.push_back(sb_int); + if (!no_sign) // if no sign is false then make a sign bit + ppij_vec.append(sb_int); // constant bit - if (no_constant == false) { // if non constant is false make a constant bit - ppij_vec.push_back(constant_one); - } + if (!no_constant) // if non constant is false make a constant bit + ppij_vec.append(State::S1); } void DebugDumpAlignPP(std::vector> &aligned_pp) @@ -663,8 +517,8 @@ struct BoothPassWorker { } } - void BuildCSATree(RTLIL::Module *module, std::vector> &bits_to_reduce, std::vector &s_vec, - std::vector &c_vec, std::vector> &debug_csa_trees) + void BuildCSATree(RTLIL::Module *module, std::vector &bits_to_reduce, SigSpec &s_vec, + SigSpec &c_vec, std::vector> &debug_csa_trees) { if (!(bits_to_reduce.size() > 0)) @@ -672,24 +526,24 @@ struct BoothPassWorker { int column_size = bits_to_reduce[0].size(); int row_size = bits_to_reduce.size(); - std::vector carry_bits_to_add_to_next_column; + SigSpec carry_bits_to_add_to_next_column; for (int column_ix = 0; column_ix < column_size; column_ix++) { // get the bits in this column. - std::vector column_bits; + SigSpec column_bits; for (int row_ix = 0; row_ix < row_size; row_ix++) { - if (bits_to_reduce[row_ix].at(column_ix)) - column_bits.push_back(bits_to_reduce[row_ix].at(column_ix)); + if (bits_to_reduce[row_ix][column_ix] != State::S0) + column_bits.append(bits_to_reduce[row_ix][column_ix]); } for (auto c : carry_bits_to_add_to_next_column) { #ifdef DEBUG_CSA printf("\t Propagating column bit %s to column %d from column %d\n", c->name.c_str(), column_ix, column_ix - 1); #endif - column_bits.push_back(c); + column_bits.append(c); } - carry_bits_to_add_to_next_column.resize(0); + carry_bits_to_add_to_next_column = {}; #ifdef DEBUG_CSA printf("Column %d Reducing %d bits\n", column_ix, column_bits.size()); @@ -699,16 +553,15 @@ struct BoothPassWorker { printf("\n"); #endif - RTLIL::Wire *s = nullptr; - RTLIL::Wire *c = nullptr; + SigBit s, c; #ifdef DEBUG_CSA int csa_count_before = debug_csa_trees[column_ix].size(); #endif ReduceBits(module, column_ix, column_bits, s, c, carry_bits_to_add_to_next_column, debug_csa_trees); - s_vec.push_back(s); - c_vec.push_back(c); + s_vec.append(s); + c_vec.append(c); #ifdef DEBUG_CSA int csa_count_after = debug_csa_trees[column_ix].size(); @@ -738,8 +591,8 @@ struct BoothPassWorker { Pad out rows with zeros and left the opt pass clean them up. */ - void AlignPP(int x_sz, int z_sz, std::vector, int, RTLIL::Wire *>> &ppij_int, - std::vector> &aligned_pp) + void AlignPP(int x_sz, int z_sz, std::vector> &ppij_int, + std::vector &aligned_pp) { unsigned aligned_pp_ix = aligned_pp.size() - 1; @@ -748,7 +601,7 @@ struct BoothPassWorker { for (unsigned i = 0; i < aligned_pp.size(); i++) { for (int j = 0; j < z_sz; j++) { - aligned_pp[i][j] = nullptr; + aligned_pp[i][j] = State::S0; } } @@ -758,21 +611,19 @@ struct BoothPassWorker { // in first column of the last partial product // which is at index corresponding to size of multiplicand { - RTLIL::Wire *prior_row_sign = nullptr; - prior_row_sign = get<2>(ppij_int[aligned_pp_ix - 1]); - if (prior_row_sign) { + SigBit prior_row_sign = get<2>(ppij_int[aligned_pp_ix - 1]); + //if (prior_row_sign) { log_assert(aligned_pp_ix < aligned_pp.size()); log_assert(x_sz - 1 < (int)(aligned_pp[aligned_pp_ix].size())); aligned_pp[aligned_pp_ix][x_sz - 1] = prior_row_sign; - } + //} } for (int row_ix = aligned_pp_ix - 1; row_ix >= 0; row_ix--) { int shift_amount = get<1>(ppij_int[row_ix]); - RTLIL::Wire *prior_row_sign = nullptr; // copy in data - unsigned copy_ix = shift_amount; + int copy_ix = shift_amount; for (auto w : get<0>(ppij_int[row_ix])) { if (copy_ix < aligned_pp[row_ix].size()) { aligned_pp[row_ix][copy_ix] = w; @@ -786,7 +637,7 @@ struct BoothPassWorker { // the destination of the sign bit is the (row_ix -1)*2 // eg destination for sign bit for row 0 is 0. // eg destination for sign bit for row 1 is 1 - prior_row_sign = get<2>(ppij_int[row_ix - 1]); + SigBit prior_row_sign = get<2>(ppij_int[row_ix - 1]); copy_ix = (row_ix - 1) * 2; aligned_pp[row_ix][copy_ix] = prior_row_sign; } @@ -797,32 +648,22 @@ struct BoothPassWorker { Build a Carry Propagate Adder ----------------------------- First build the sum and carry vectors to be added. - Axioms: - c_vec.size() == s_vec.size() - result.size() == s_vec.size() + 2; (assume result is reserved to hold correct size) */ - void BuildCPA(RTLIL::Module *module, std::vector &s_vec, std::vector &c_vec, RTLIL::Wire *result) + void BuildCPA(RTLIL::Module *module, SigSpec s_vec, SigSpec c_vec, SigSpec result) { - static int cpa_id; cpa_id++; - RTLIL::Wire *carry = nullptr; + log_assert(c_vec.size() == s_vec.size()); + log_assert(result.size() == s_vec.size()); - log_assert(s_vec.size() == c_vec.size()); - - for (unsigned n = 0; n < s_vec.size(); n++) { + SigBit carry; + for (int n = 0; n < s_vec.size(); n++) { std::string carry_name; // Base Case: Bit 0 is sum 0 if (n == 0) { - std::string buf_name = "base_buf_" + std::to_string(cpa_id) + "_" + std::to_string(n); - auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setPort(ID::A, s_vec[0]); - buf->setParam(ID::A_WIDTH, 1); - buf->setParam(ID::Y_WIDTH, 1); - buf->setParam(ID::A_SIGNED, false); - buf->setPort(ID::Y, SigSpec(result, 0, 1)); + module->addBufGate(NEW_ID_SUFFIX(stringf("base_buf_%d_%d", cpa_id, n)), s_vec[0], result[0]); #ifdef DEBUG_CPA printf("CPA bit [%d] Cell %s IP 0 %s \n", n, buf->name.c_str(), s_vec[0]->name.c_str()); @@ -835,10 +676,9 @@ struct BoothPassWorker { // else if (n == 1) { std::string ha_name = "cpa_" + std::to_string(cpa_id) + "_ha_" + std::to_string(n); - RTLIL::Wire *ha_op; + SigBit ha_op; BuildHa(ha_name, s_vec[n], c_vec[n - 1], ha_op, carry); - - module->connect(ha_op, SigSpec(result, n, 1)); + module->connect(result[n], ha_op); #ifdef DEBUG_CPA printf("CPA bit [%d] Cell %s IPs [%s] [%s] \n", n, ha_cell->name.c_str(), s_vec[n]->name.c_str(), @@ -847,54 +687,45 @@ struct BoothPassWorker { } // End Case - else if (n == (unsigned)((s_vec.size() - 1))) { + else if (n == s_vec.size() - 1) { // Make the carry results.. Two extra bits after fa. - std::string fa_name = "cpa_" + std::to_string(cpa_id) + "_fa_" + std::to_string(n); - auto fa_cell = module->addCell(new_id(fa_name, __LINE__, ""), ID($fa)); - fa_cell->setParam(ID::WIDTH, 1); - carry_name = "cpa_" + std::to_string(cpa_id) + "carry_" + std::to_string(n); - fa_cell->setPort(ID::A, s_vec[n]); - fa_cell->setPort(ID::B, c_vec[n - 1]); - fa_cell->setPort(ID::C, carry); - // wire in result and carry out - fa_cell->setPort(ID::Y, SigSpec(result, n, 1)); - - // make a new carry bit for carry out... - carry = module->addWire(new_id(carry_name, __LINE__, ""), 1); - fa_cell->setPort(ID::X, carry); + SigBit carry_out = module->addWire(NEW_ID, 1); + module->addFa(NEW_ID_SUFFIX(stringf("cpa_%d_fa_%d", cpa_id, n)), + /* A */ s_vec[n], + /* B */ c_vec[n - 1], + /* C */ carry, + /* X */ carry_out, + /* Y */ result[n] + ); + carry = carry_out; #ifdef DEBUG_CPA printf("CPA bit [%d] Cell %s IPs [%s] [%s] [%s]\n", n, fa_cell->name.c_str(), s_vec[n]->name.c_str(), c_vec[n - 1]->name.c_str(), carry->name.c_str()); #endif - if (n + 1 < (unsigned)(GetSize(result))) { + if (n + 1 < GetSize(result)) { // Now make a half adder: c_vec[n] = carry std::string ha_name = "cpa_" + std::to_string(cpa_id) + "_ha_" + std::to_string(n); - RTLIL::Wire *ha_sum; - RTLIL::Wire *ha_carry; + SigBit ha_sum; + SigBit ha_carry; BuildHa(ha_name, c_vec[n], carry, ha_sum, ha_carry); - if (n + 1 < (unsigned)GetSize(result)) - module->connect(ha_sum, SigSpec(result, n + 1, 1)); - if (n + 2 < (unsigned)GetSize(result)) - module->connect(ha_carry, SigSpec(result, n + 2, 1)); + if (n + 1 < GetSize(result)) + module->connect(result[n + 1], ha_sum); + if (n + 2 < GetSize(result)) + module->connect(result[n + 2], ha_carry); } } // Step case else { - std::string fa_name = "cpa_" + std::to_string(cpa_id) + "_fa_" + std::to_string(n); - auto fa_cell = module->addCell(new_id(fa_name, __LINE__, ""), ID($fa)); - fa_cell->setParam(ID::WIDTH, 1); - - carry_name = "cpa_" + std::to_string(cpa_id) + "carry_" + std::to_string(n); - fa_cell->setPort(ID::A, s_vec[n]); - fa_cell->setPort(ID::B, c_vec[n - 1]); - fa_cell->setPort(ID::C, carry); - // wire in result and carry out - fa_cell->setPort(ID::Y, SigSpec(result, n, 1)); - // make a new carry bit for carry out... - carry = module->addWire(new_id(carry_name, __LINE__, ""), 1); - fa_cell->setPort(ID::X, carry); - + SigBit carry_out = module->addWire(NEW_ID_SUFFIX(stringf("cpa_%d_carry_%d", cpa_id, n)), 1); + module->addFa(NEW_ID_SUFFIX(stringf("cpa_%d_fa_%d", cpa_id, n)), + /* A */ s_vec[n], + /* B */ c_vec[n - 1], + /* C */ carry, + /* X */ carry_out, + /* Y */ result[n] + ); + carry = carry_out; #ifdef DEBUG_CPA printf("CPA bit [%d] Cell %s IPs [%s] [%s] [%s]\n", n, fa_cell->name.c_str(), s_vec[n]->name.c_str(), c_vec[n - 1]->name.c_str(), carry->name.c_str()); @@ -907,99 +738,72 @@ struct BoothPassWorker { // Pass the carry bits from each csa to the next // column for summation. - void ReduceBits(RTLIL::Module *module, int column_ix, std::vector &column_bits, RTLIL::Wire *&s_result, RTLIL::Wire *&c_result, - std::vector &carry_bits_to_sum, std::vector> &debug_csa_trees) + void ReduceBits(RTLIL::Module *module, int column_ix, SigSpec column_bits, SigBit &s_result, SigBit &c_result, + SigSpec &carry_bits_to_sum, std::vector> &debug_csa_trees) { int csa_ix = 0; int column_size = column_bits.size(); - static int unique_id = 0; - - unique_id++; if (column_size > 0) { - unsigned var_ix = 0; - std::vector first_csa_ips; + int var_ix = 0; + SigSpec first_csa_ips; // get the first 3 inputs, if possible for (var_ix = 0; var_ix < column_bits.size() && first_csa_ips.size() != 3; var_ix++) { - if (column_bits[var_ix]) - first_csa_ips.push_back(column_bits[var_ix]); + if (column_bits[var_ix] != State::S0) + first_csa_ips.append(column_bits[var_ix]); } if (first_csa_ips.size() > 0) { // build the first csa - std::string csa_name = - "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_" + std::to_string(unique_id) + "_"; - auto csa = module->addCell(NEW_ID, - // new_id(csa_name, - // __LINE__, - // ""), - ID($fa)); - csa->setParam(ID::WIDTH, 1); - debug_csa_trees[column_ix].push_back(csa); - csa_ix++; + auto s_wire = module->addWire(NEW_ID_SUFFIX(stringf("csa_%d_%d_s", column_ix, csa_ix + 1)), 1); + auto c_wire = module->addWire(NEW_ID_SUFFIX(stringf("csa_%d_%d_c", column_ix, csa_ix + 1)), 1); - csa->setPort(ID::A, first_csa_ips[0]); + auto csa = module->addFa(NEW_ID_SUFFIX(stringf("csa_%d_%d", column_ix, csa_ix)), + /* A */ first_csa_ips[0], + /* B */ first_csa_ips.size() > 1 ? first_csa_ips[1] : State::S0, + /* C */ first_csa_ips.size() > 2 ? first_csa_ips[2] : State::S0, + /* X */ c_wire, + /* Y */ s_wire + ); - if (first_csa_ips.size() > 1) - csa->setPort(ID::B, first_csa_ips[1]); - else - csa->setPort(ID::B, State::S0); - - if (first_csa_ips.size() > 2) - csa->setPort(ID::C, first_csa_ips[2]); - else - csa->setPort(ID::C, State::S0); - - std::string sum_wire_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_s"; - auto s_wire = module->addWire(new_id(sum_wire_name, __LINE__, ""), 1); - csa->setPort(ID::Y, s_wire); s_result = s_wire; - std::string carry_wire_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_c"; - auto c_wire = module->addWire(new_id(carry_wire_name, __LINE__, ""), 1); - csa->setPort(ID::X, c_wire); c_result = c_wire; + debug_csa_trees[column_ix].push_back(csa); + csa_ix++; + if (var_ix <= column_bits.size() - 1) - carry_bits_to_sum.push_back(c_wire); + carry_bits_to_sum.append(c_wire); // Now build the rest of the tree if we can while (var_ix <= column_bits.size() - 1) { - std::vector csa_ips; + SigSpec csa_ips; // get the next two variables to sum for (; var_ix <= column_bits.size() - 1 && csa_ips.size() < 2;) { // skip any empty bits - if (column_bits[var_ix] != nullptr) - csa_ips.push_back(column_bits[var_ix]); + if (column_bits[var_ix] != State::S0) + csa_ips.append(column_bits[var_ix]); var_ix++; } if (csa_ips.size() > 0) { - csa_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix); - auto csa = module->addCell(new_id(csa_name, __LINE__, ""), ID($fa)); - csa->setParam(ID::WIDTH, 1); + auto c_wire = module->addWire(NEW_ID_SUFFIX(stringf("csa_%d_%d_c", column_ix, csa_ix + 1)), 1); + auto s_wire = module->addWire(NEW_ID_SUFFIX(stringf("csa_%d_%d_s", column_ix, csa_ix + 1)), 1); + + auto csa = module->addFa(NEW_ID_SUFFIX(stringf("csa_%d_%d", column_ix, csa_ix)), + /* A */ s_result, + /* B */ csa_ips[0], + /* C */ csa_ips.size() > 1 ? csa_ips[1] : State::S0, + /* X */ c_wire, + /* Y */ s_wire + ); + debug_csa_trees[column_ix].push_back(csa); - csa_ix++; - // prior level - csa->setPort(ID::A, s_wire); - csa->setPort(ID::B, csa_ips[0]); - if (csa_ips.size() > 1) - csa->setPort(ID::C, csa_ips[1]); - else - csa->setPort(ID::C, State::S0); - - carry_wire_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_c"; - c_wire = module->addWire(new_id(carry_wire_name, __LINE__, ""), 1); if (var_ix <= column_bits.size() - 1) - carry_bits_to_sum.push_back(c_wire); - - sum_wire_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_s"; - s_wire = module->addWire(new_id(sum_wire_name, __LINE__, ""), 1); - - csa->setPort(ID::X, c_wire); - csa->setPort(ID::Y, s_wire); + carry_bits_to_sum.append(c_wire); s_result = s_wire; c_result = c_wire; @@ -1009,28 +813,22 @@ struct BoothPassWorker { } } - void BuildBoothUMultEncoders(RTLIL::Wire *Y, int y_sz, std::vector &one_int, std::vector &two_int, - std::vector &s_int, std::vector &sb_int, RTLIL::Module *module, int &encoder_ix) + void BuildBoothUMultEncoders(SigSpec Y, SigSpec &one_int, SigSpec &two_int, + SigSpec &s_int, SigSpec &sb_int, RTLIL::Module *module, int &encoder_ix) { + int y_sz = GetSize(Y); + for (int y_ix = 0; y_ix < y_sz;) { - std::string enc_name = "bur_enc_" + std::to_string(encoder_ix) + "_"; + std::string enc_name = stringf("bur_enc_%d", encoder_ix); - std::string two_name = "two_int" + std::to_string(encoder_ix); - two_int.push_back(module->addWire(new_id(two_name, __LINE__, ""), 1)); - - std::string one_name = "one_int" + std::to_string(encoder_ix); - one_int.push_back(module->addWire(new_id(one_name, __LINE__, ""), 1)); - - std::string s_name = "s_int" + std::to_string(encoder_ix); - s_int.push_back(module->addWire(new_id(s_name, __LINE__, ""), 1)); - - std::string sb_name = "sb_int" + std::to_string(encoder_ix); - sb_int.push_back(module->addWire(new_id(sb_name, __LINE__, ""), 1)); + two_int.append(module->addWire(NEW_ID_SUFFIX(stringf("two_int_%d", encoder_ix)), 1)); + one_int.append(module->addWire(NEW_ID_SUFFIX(stringf("one_int_%d", encoder_ix)), 1)); + s_int.append(module->addWire(NEW_ID_SUFFIX(stringf("s_int_%d", encoder_ix)), 1)); + sb_int.append(module->addWire(NEW_ID_SUFFIX(stringf("sb_int_%d", encoder_ix)), 1)); if (y_ix == 0) { - - BuildBur4e(enc_name, mk_wireFromSigSpec(State::S0), mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)), - mk_wireFromSigSpec(SigSpec(Y, y_ix + 1, 1)), one_int[encoder_ix], two_int[encoder_ix], s_int[encoder_ix], + BuildBur4e(enc_name, State::S0, Y[y_ix], + Y[y_ix + 1], one_int[encoder_ix], two_int[encoder_ix], s_int[encoder_ix], sb_int[encoder_ix]); y_ix = y_ix + 1; @@ -1041,71 +839,61 @@ struct BoothPassWorker { // then add an extra booth encoder bounded by // zeroes to ensure unsigned works. // - RTLIL::Wire *y0_wire; - RTLIL::Wire *y1_wire; - RTLIL::Wire *y2_wire; + SigBit y0, y1, y2; bool need_padded_cell = false; if (y_ix > y_sz - 1) { - y0_wire = mk_wireFromSigSpec(SigSpec(Y, State::S0)); + y0 = State::S0; need_padded_cell = false; } else { - y0_wire = mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)); + y0 = Y[y_ix]; y_ix++; } if (y_ix > y_sz - 1) { need_padded_cell = false; - y1_wire = mk_wireFromSigSpec(SigSpec(Y, State::S0)); + y1 = State::S0; } else { - y1_wire = mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)); + y1 = Y[y_ix]; y_ix++; } if (y_ix > y_sz - 1) { need_padded_cell = false; - y2_wire = mk_wireFromSigSpec(SigSpec(Y, State::S0)); + y2 = State::S0; } else { if (y_ix == y_sz - 1) need_padded_cell = true; else need_padded_cell = false; - y2_wire = mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)); + y2 = Y[y_ix]; - BuildBur4e(enc_name, y0_wire, y1_wire, y2_wire, one_int[encoder_ix], two_int[encoder_ix], s_int[encoder_ix], + BuildBur4e(enc_name, y0, y1, y2, one_int[encoder_ix], two_int[encoder_ix], s_int[encoder_ix], sb_int[encoder_ix]); } encoder_ix++; if (need_padded_cell == true) { - // make extra encoder cell // y_ix at y0, rest 0 - std::string enc_name = "br_enc_pad" + std::to_string(encoder_ix) + "_"; + std::string enc_name = stringf("br_enc_pad_%d", encoder_ix); - std::string two_name = "two_int" + std::to_string(encoder_ix); - two_int.push_back(module->addWire(new_id(two_name, __LINE__, ""), 1)); + two_int.append(module->addWire(NEW_ID_SUFFIX(stringf("two_int_%d", encoder_ix)), 1)); + one_int.append(module->addWire(NEW_ID_SUFFIX(stringf("one_int_%d", encoder_ix)), 1)); + s_int.append(module->addWire(NEW_ID_SUFFIX(stringf("s_int_%d", encoder_ix)), 1)); + sb_int.append(module->addWire(NEW_ID_SUFFIX(stringf("sb_int_%d", encoder_ix)), 1)); - std::string one_name = "one_int" + std::to_string(encoder_ix); - one_int.push_back(module->addWire(new_id(two_name, __LINE__, ""), 1)); + SigBit one_o_int, two_o_int, s_o_int, sb_o_int; + BuildBur4e(enc_name, Y[y_ix], State::S0, + State::S0, one_o_int, two_o_int, s_o_int, sb_o_int); - std::string s_name = "s_int" + std::to_string(encoder_ix); - s_int.push_back(module->addWire(new_id(s_name, __LINE__, ""), 1)); - - std::string sb_name = "sb_int" + std::to_string(encoder_ix); - sb_int.push_back(module->addWire(new_id(sb_name, __LINE__, ""), 1)); - - RTLIL::Wire *one_o_int, *two_o_int, *s_o_int, *sb_o_int; - BuildBur4e(enc_name, mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)), mk_wireFromSigSpec(State::S0), - mk_wireFromSigSpec(State::S0), one_o_int, two_o_int, s_o_int, sb_o_int); - - join_wires_with_buffer(one_o_int, one_int[encoder_ix]); - join_wires_with_buffer(two_o_int, two_int[encoder_ix]); - join_wires_with_buffer(s_o_int, s_int[encoder_ix]); - join_wires_with_buffer(sb_o_int, sb_int[encoder_ix]); + module->connect(one_int[encoder_ix], one_o_int); + module->connect(two_int[encoder_ix], two_o_int); + module->connect(s_int[encoder_ix], s_o_int); + module->connect(sb_int[encoder_ix], sb_o_int); y_ix++; encoder_ix++; } @@ -1116,87 +904,76 @@ struct BoothPassWorker { /* Signed Multiplier */ - void CreateBoothSMult(RTLIL::Module *module, int x_sz, int y_sz, int z_sz, RTLIL::Wire *X, RTLIL::Wire *Y, RTLIL::Wire *Z) + void CreateBoothSMult(RTLIL::Module *module, SigSpec X, SigSpec Y, SigSpec Z) { // product + int x_sz = X.size(), y_sz = Y.size(), z_sz = Z.size(); + unsigned enc_count = (y_sz / 2) + (((y_sz % 2) != 0) ? 1 : 0); int dec_count = x_sz + 1; int fa_count = x_sz + 4; int fa_row_count = enc_count - 1; - log("Signed multiplier generator using low Power Negative First Booth Algorithm. Multiplicand of size %d Multiplier of size %d. " - "Result of size %d. %d encoders %d decoders\n", - x_sz, y_sz, z_sz, enc_count, dec_count); + log_debug("Mapping %d x %d -> %d multiplier: %d encoders %d decoders\n", x_sz, y_sz, z_sz, enc_count, dec_count); - RTLIL::Wire **negi_n_int = new RTLIL::Wire *[enc_count]; - RTLIL::Wire **twoi_n_int = new RTLIL::Wire *[enc_count]; - RTLIL::Wire **onei_n_int = new RTLIL::Wire *[enc_count]; - RTLIL::Wire **cori_n_int = new RTLIL::Wire *[enc_count]; + SigSpec negi_n_int, twoi_n_int, onei_n_int, cori_n_int; + + negi_n_int.extend_u0(enc_count); + twoi_n_int.extend_u0(enc_count); + onei_n_int.extend_u0(enc_count); + cori_n_int.extend_u0(enc_count); for (unsigned encoder_ix = 1; encoder_ix <= enc_count; encoder_ix++) { - std::string enc_name = "enc_" + std::to_string(encoder_ix) + "_"; - std::string negi_name = "negi_n_int" + std::to_string(encoder_ix) + "_"; - negi_n_int[encoder_ix - 1] = module->addWire(new_id(negi_name, __LINE__, ""), 1); - std::string twoi_name = "twoi_n_int_" + std::to_string(encoder_ix) + "_"; - twoi_n_int[encoder_ix - 1] = module->addWire(new_id(twoi_name, __LINE__, ""), 1); - std::string onei_name = "onei_n_int_" + std::to_string(encoder_ix) + "_"; - onei_n_int[encoder_ix - 1] = module->addWire(new_id(onei_name, __LINE__, ""), 1); - std::string cori_name = "cori_n_int_" + std::to_string(encoder_ix) + "_"; - cori_n_int[encoder_ix - 1] = module->addWire(new_id(cori_name, __LINE__, ""), 1); + std::string enc_name = stringf("enc_%d", encoder_ix); + negi_n_int[encoder_ix - 1] = module->addWire(NEW_ID_SUFFIX(stringf("negi_n_int_%d", encoder_ix)), 1); + twoi_n_int[encoder_ix - 1] = module->addWire(NEW_ID_SUFFIX(stringf("twoi_n_int_%d", encoder_ix)), 1); + onei_n_int[encoder_ix - 1] = module->addWire(NEW_ID_SUFFIX(stringf("onei_n_int_%d", encoder_ix)), 1); + cori_n_int[encoder_ix - 1] = module->addWire(NEW_ID_SUFFIX(stringf("cori_n_int_%d", encoder_ix)), 1); if (encoder_ix == 1) { - - BuildBr4e(enc_name, mk_wireFromSigSpec(SigSpec(State::S0)), mk_wireFromSigSpec(SigSpec(Y, 0, 1)), - mk_wireFromSigSpec(SigSpec(Y, 1, 1)), - + BuildBr4e(enc_name, State::S0, Y[0], Y[1], negi_n_int[encoder_ix - 1], twoi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], cori_n_int[encoder_ix - 1]); } else { - RTLIL::Wire *y1_wire; - RTLIL::Wire *y2_wire; - RTLIL::Wire *y3_wire; + SigBit y1, y2, y3; + + y1 = Y[(encoder_ix - 1) * 2 - 1]; - y1_wire = mk_wireFromSigSpec(SigSpec(Y, ((encoder_ix - 1) * 2 - 1), 1)); //-1 if ((encoder_ix - 1) * 2 >= (unsigned)y_sz) - y2_wire = mk_wireFromSigSpec(SigSpec(State::S0)); // constant 0 + y2 = State::S0; // constant 0 else - y2_wire = mk_wireFromSigSpec(SigSpec(Y, ((encoder_ix - 1) * 2), 1)); // 0 + y2 = Y[(encoder_ix - 1) * 2]; // 0 if (((encoder_ix - 1) * 2 + 1) >= (unsigned)y_sz) - y3_wire = mk_wireFromSigSpec(SigSpec(State::S0)); // constant 0 + y3 = State::S0; // constant 0 else - y3_wire = mk_wireFromSigSpec(SigSpec(Y, ((encoder_ix - 1) * 2 + 1), 1)); //+1 - - BuildBr4e(enc_name, y1_wire, y2_wire, y3_wire, + y3 = Y[(encoder_ix - 1) * 2 + 1]; //+1 + BuildBr4e(enc_name, y1, y2, y3, negi_n_int[encoder_ix - 1], twoi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], cori_n_int[encoder_ix - 1]); } } // Decoders and PP generation - RTLIL::Wire **PPij = new RTLIL::Wire *[enc_count * dec_count]; - RTLIL::Wire **nxj = new RTLIL::Wire *[enc_count * dec_count]; + SigSpec PPij(State::S0, enc_count * dec_count); + SigSpec nxj(State::S0, enc_count * dec_count); for (int encoder_ix = 1; encoder_ix <= (int)enc_count; encoder_ix++) { for (int decoder_ix = 1; decoder_ix <= dec_count; decoder_ix++) { - std::string ppij_name = "ppij_" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; - PPij[((encoder_ix - 1) * dec_count) + decoder_ix - 1] = module->addWire(new_id(ppij_name, __LINE__, ""), 1); - std::string nxj_name; - if (decoder_ix == 1) - nxj_name = "nxj_pre_dec" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; - else - nxj_name = "nxj_" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; + PPij[((encoder_ix - 1) * dec_count) + decoder_ix - 1] = + module->addWire(NEW_ID_SUFFIX(stringf("ppij_%d_%d", encoder_ix, decoder_ix)), 1); - nxj[((encoder_ix - 1) * dec_count) + decoder_ix - 1] = module->addWire(new_id(nxj_name, __LINE__, ""), 1); + nxj[((encoder_ix - 1) * dec_count) + decoder_ix - 1] = + module->addWire(NEW_ID_SUFFIX(stringf("nxj_%s%d_%d", decoder_ix == 1 ? "pre_dec_" : "", + encoder_ix, decoder_ix)), 1); } } // // build decoder array // - for (int encoder_ix = 1; encoder_ix <= (int)enc_count; encoder_ix++) { // pre-decoder std::string pre_dec_name = "pre_dec_" + std::to_string(encoder_ix) + "_"; @@ -1204,10 +981,10 @@ struct BoothPassWorker { if (encoder_ix == 1) { // quadrant 1 optimization } else { - auto cell = module->addCell(new_id(pre_dec_name, __LINE__, ""), ID($_NOT_)); - cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); - cell->setPort(ID::A, negi_n_int[encoder_ix - 1]); - cell->setPort(ID::Y, nxj[(encoder_ix - 1) * dec_count]); + module->addNotGate(NEW_ID_SUFFIX(stringf("pre_dec_%d", encoder_ix)), + negi_n_int[encoder_ix - 1], + nxj[(encoder_ix - 1) * dec_count] + ); } for (int decoder_ix = 1; decoder_ix < dec_count; decoder_ix++) { @@ -1217,19 +994,18 @@ struct BoothPassWorker { if ((decoder_ix == 1 || decoder_ix == 2) && encoder_ix == 1) continue; - std::string dec_name = "dec_" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; - + std::string dec_name = stringf("dec_%d_%d", encoder_ix, decoder_ix); BuildBr4d(dec_name, nxj[((encoder_ix - 1) * dec_count) + decoder_ix - 1], twoi_n_int[encoder_ix - 1], - mk_wireFromSigSpec(SigSpec(X, decoder_ix - 1, 1)), negi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], + X[decoder_ix - 1], negi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], PPij[((encoder_ix - 1) * dec_count) + decoder_ix - 1], nxj[((encoder_ix - 1) * dec_count) + decoder_ix]); } // duplicate end for sign fix // applies to 9th decoder (xsz+1 decoder). - std::string dec_name = "dec_" + std::to_string(encoder_ix) + "_" + std::to_string(x_sz + 1) + "_"; - RTLIL::Wire *unused_op = nullptr; + std::string dec_name = stringf("dec_%d_%d", encoder_ix, x_sz + 1); + SigBit unused_op; BuildBr4d(dec_name, nxj[((encoder_ix - 1) * dec_count) + dec_count - 1], twoi_n_int[encoder_ix - 1], - mk_wireFromSigSpec(SigSpec(X, dec_count - 2, 1)), negi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], + X[dec_count - 2], negi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], PPij[((encoder_ix - 1) * dec_count) + dec_count - 1], unused_op); } @@ -1239,16 +1015,15 @@ struct BoothPassWorker { int fa_el_ix = 0; int fa_row_ix = 0; // use 1 d arrays (2d cannot have variable sized indices) - RTLIL::Wire **fa_sum_n = new RTLIL::Wire *[fa_row_count * fa_count]; - RTLIL::Wire **fa_carry_n = new RTLIL::Wire *[fa_row_count * fa_count]; + SigSpec fa_sum_n(State::S0, fa_row_count * fa_count); + SigSpec fa_carry_n(State::S0, fa_row_count * fa_count); for (fa_row_ix = 0; fa_row_ix < fa_row_count; fa_row_ix++) { for (fa_el_ix = 0; fa_el_ix < fa_count; fa_el_ix++) { - - std::string fa_sum_name = "fa_sum_n_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_"; - fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] = module->addWire(new_id(fa_sum_name, __LINE__, ""), 1); - std::string fa_carry_name = "fa_carry_n" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_"; - fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix] = module->addWire(new_id(fa_carry_name, __LINE__, ""), 1); + fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] = + module->addWire(NEW_ID_SUFFIX(stringf("fa_sum_n_%d_%d", fa_row_ix, fa_el_ix)), 1); + fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix] = + module->addWire(NEW_ID_SUFFIX(stringf("fa_carry_n_%d_%d", fa_row_ix, fa_el_ix)), 1); } } @@ -1271,67 +1046,52 @@ struct BoothPassWorker { // step case else if (fa_el_ix >= 2 && fa_el_ix <= x_sz) { // middle (2...x_sz cells) - bfa_name = "bfa_0_step_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; - auto cell = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell->setParam(ID::WIDTH, 1); - cell->setPort(ID::A, PPij[(0 * dec_count) + fa_el_ix]); - cell->setPort(ID::B, PPij[(1 * dec_count) + fa_el_ix - 2]); - cell->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + module->addFa(NEW_ID_SUFFIX(stringf("bfa_0_step_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ PPij[(0 * dec_count) + fa_el_ix], + /* B */ PPij[(1 * dec_count) + fa_el_ix - 2], + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); } // end 3 cells: x_sz+1.2.3 // else { // fa_el_ix = x_sz+1 - bfa_name = "bfa_0_se_0" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; - auto cell1 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell1->setParam(ID::WIDTH, 1); - cell1->setPort(ID::A, PPij[(0 * dec_count) + x_sz]); - cell1->setPort(ID::B, PPij[(1 * dec_count) + fa_el_ix - 2]); - cell1->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell1->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell1->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + module->addFa(NEW_ID_SUFFIX(stringf("bfa_0_se_0_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ PPij[(0 * dec_count) + x_sz], + /* B */ PPij[(1 * dec_count) + fa_el_ix - 2], + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); // exception:invert ppi fa_el_ix++; - exc_inv_name = "bfa_0_exc_inv1_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; - auto cellinv1 = module->addCell(new_id(exc_inv_name, __LINE__, ""), ID($_NOT_)); - cellinv1->add_strpool_attribute(ID::src, cellinv1->get_strpool_attribute(ID::src)); + SigBit d08_inv = module->NotGate(NEW_ID_SUFFIX(stringf("bfa_0_exc_inv1_%d_%d_L", fa_row_ix, fa_el_ix)), + PPij[(0 * dec_count) + dec_count - 1]); - RTLIL::Wire *d08_inv = module->addWire(NEW_ID, 1); + SigBit d18_inv = module->NotGate(NEW_ID_SUFFIX(stringf("bfa_0_exc_inv2_%d_%d_L", fa_row_ix, fa_el_ix)), + PPij[(1 * dec_count) + dec_count - 1]); - cellinv1->setPort(ID::A, PPij[(0 * dec_count) + dec_count - 1]); - cellinv1->setPort(ID::Y, d08_inv); - - exc_inv_name = "bfa_0_exc_inv2_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; - - auto cellinv2 = module->addCell(new_id(exc_inv_name, __LINE__, ""), ID($_NOT_)); - cellinv2->add_strpool_attribute(ID::src, cellinv2->get_strpool_attribute(ID::src)); - RTLIL::Wire *d18_inv = module->addWire(NEW_ID, 1); - cellinv2->setPort(ID::A, PPij[(1 * dec_count) + dec_count - 1]); - cellinv2->setPort(ID::Y, d18_inv); - - bfa_name = "bfa_0_se_1_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; - - auto cell2 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell2->setParam(ID::WIDTH, 1); - cell2->setPort(ID::A, d08_inv); - cell2->setPort(ID::B, d18_inv); - cell2->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell2->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell2->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + module->addFa(NEW_ID_SUFFIX(stringf("bfa_0_se_1_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ d08_inv, + /* B */ d18_inv, + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); // sign extension fa_el_ix++; - bfa_name = "bfa_0_se_2_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; - auto cell3 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell3->setParam(ID::WIDTH, 1); - cell3->setPort(ID::A, State::S0); - cell3->setPort(ID::B, State::S1); - cell3->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell3->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell3->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + + module->addFa(NEW_ID_SUFFIX(stringf("bfa_0_se_2_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ State::S0, + /* B */ State::S1, + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); } } @@ -1342,89 +1102,71 @@ struct BoothPassWorker { if (fa_el_ix == 0) { // first two cells: have B input hooked to 0. // column is offset by row_ix*2 - bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_base_" + std::to_string(fa_row_ix) + "_" + - std::to_string(fa_el_ix) + "_L"; - auto cell1 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell1->setParam(ID::WIDTH, 1); - cell1->setPort(ID::A, fa_sum_n[(fa_row_ix - 1) * fa_count + 2]); // from prior full adder row - cell1->setPort(ID::B, State::S0); - cell1->setPort(ID::C, cori_n_int[fa_row_ix]); - cell1->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell1->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + + module->addFa(NEW_ID_SUFFIX(stringf("bfa_base_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ fa_sum_n[(fa_row_ix - 1) * fa_count + 2], + /* B */ State::S0, + /* C */ cori_n_int[fa_row_ix], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); fa_el_ix++; - bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_base_" + std::to_string(fa_row_ix) + "_" + - std::to_string(fa_el_ix) + "_L"; - auto cell2 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell2->setParam(ID::WIDTH, 1); - cell2->setPort(ID::A, - fa_sum_n[(fa_row_ix - 1) * fa_count + 3]); // from prior full adder row - cell2->setPort(ID::B, State::S0); - cell2->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell2->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell2->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + module->addFa(NEW_ID_SUFFIX(stringf("bfa_base_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ fa_sum_n[(fa_row_ix - 1) * fa_count + 3], // from prior full adder row + /* B */ State::S0, + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); + } else if (fa_el_ix >= 2 && fa_el_ix <= x_sz + 1) { // middle (2...x_sz+1 cells) - bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_step_" + std::to_string(fa_row_ix) + "_" + - std::to_string(fa_el_ix) + "_L"; - auto cell = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell->setParam(ID::WIDTH, 1); - cell->setPort(ID::A, fa_sum_n[(fa_row_ix - 1) * fa_count + fa_el_ix + 2]); - cell->setPort(ID::B, PPij[(fa_row_ix + 1) * dec_count + fa_el_ix - 2]); - cell->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + module->addFa(NEW_ID_SUFFIX(stringf("bfa_step_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ fa_sum_n[(fa_row_ix - 1) * fa_count + fa_el_ix + 2], + /* B */ PPij[(fa_row_ix + 1) * dec_count + fa_el_ix - 2], + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); } else if (fa_el_ix > x_sz + 1) { // end two bits: sign extension - std::string se_inv_name; - se_inv_name = "bfa_" + std::to_string(fa_row_ix) + "_se_inv_" + std::to_string(fa_row_ix) + "_" + - std::to_string(fa_el_ix) + "_L"; - auto cellinv = module->addCell(new_id(se_inv_name, __LINE__, ""), ID($_NOT_)); - cellinv->add_strpool_attribute(ID::src, cellinv->get_strpool_attribute(ID::src)); - RTLIL::Wire *d_inv = module->addWire(NEW_ID, 1); - cellinv->setPort(ID::A, PPij[((fa_row_ix + 1) * dec_count) + dec_count - 1]); - cellinv->setPort(ID::Y, d_inv); + SigBit d_inv = module->NotGate(NEW_ID_SUFFIX(stringf("bfa_se_inv_%d_%d_L", fa_row_ix, fa_el_ix)), + PPij[((fa_row_ix + 1) * dec_count) + dec_count - 1]); - bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_se_" + std::to_string(fa_row_ix) + "_" + - std::to_string(fa_el_ix) + "_L"; - auto cell1 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell1->setParam(ID::WIDTH, 1); - cell1->setPort(ID::A, fa_carry_n[((fa_row_ix - 1) * fa_count) + fa_count - 1]); - cell1->setPort(ID::B, d_inv); - cell1->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell1->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell1->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + module->addFa(NEW_ID_SUFFIX(stringf("bfa_se_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ fa_carry_n[((fa_row_ix - 1) * fa_count) + fa_count - 1], + /* B */ d_inv, + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); fa_el_ix++; // sign extension - bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_se_" + std::to_string(fa_row_ix) + "_" + - std::to_string(fa_el_ix) + "_L"; - auto cell2 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell2->setParam(ID::WIDTH, 1); - cell2->setPort(ID::A, State::S0); - cell2->setPort(ID::B, State::S1); - cell2->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell2->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell2->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + module->addFa(NEW_ID_SUFFIX(stringf("bfa_se_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ State::S0, + /* B */ State::S1, + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); } } } } // instantiate the cpa - RTLIL::Wire **cpa_carry = new RTLIL::Wire *[z_sz]; + SigSpec cpa_carry; - for (int cix = 0; cix < z_sz; cix++) { - std::string cpa_cix_name = "cpa_carry_" + std::to_string(cix) + "_"; - cpa_carry[cix] = module->addWire(new_id(cpa_cix_name, __LINE__, ""), 1); - } + for (int cix = 0; cix < z_sz; cix++) + cpa_carry.append(module->addWire(NEW_ID_SUFFIX(stringf("cpa_carry_%d", cix)), 1)); for (int cpa_ix = 0; cpa_ix < z_sz; cpa_ix++) { - // The end case where we pass the last two summands // from prior row directly to product output // without using a cpa cell. This is always @@ -1432,38 +1174,27 @@ struct BoothPassWorker { if (cpa_ix <= fa_row_count * 2 - 1) { int fa_row_ix = cpa_ix / 2; - std::string buf_name = - "pp_buf_" + std::to_string(cpa_ix) + "_" + "driven_by_fa_row_" + std::to_string(fa_row_ix) + "_"; - auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setPort(ID::A, fa_sum_n[(fa_row_ix * fa_count) + 0]); - buf->setParam(ID::A_WIDTH, 1); - buf->setParam(ID::Y_WIDTH, 1); - buf->setParam(ID::A_SIGNED, true); - buf->setPort(ID::Y, SigSpec(Z, cpa_ix, 1)); + module->addBufGate(NEW_ID_SUFFIX(stringf("pp_buf_%d_driven_by_fa_row_%d", cpa_ix, fa_row_ix)), + fa_sum_n[(fa_row_ix * fa_count) + 0], Z[cpa_ix]); cpa_ix++; - buf_name = "pp_buf_" + std::to_string(cpa_ix) + "_" + "driven_by_fa_row_" + std::to_string(fa_row_ix) + "_"; - buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setPort(ID::A, fa_sum_n[(fa_row_ix * fa_count) + 1]); - buf->setParam(ID::A_WIDTH, 1); - buf->setParam(ID::Y_WIDTH, 1); - buf->setParam(ID::A_SIGNED, true); - buf->setPort(ID::Y, SigSpec(Z, cpa_ix, 1)); + module->addBufGate(NEW_ID_SUFFIX(stringf("pp_buf_%d_driven_by_fa_row_%d", cpa_ix, fa_row_ix)), + fa_sum_n[(fa_row_ix * fa_count) + 1], Z[cpa_ix]); } else { int offset = fa_row_count * 2; bool base_case = cpa_ix - offset == 0 ? true : false; - std::string cpa_name = "cpa_" + std::to_string(cpa_ix - offset) + "_"; + std::string cpa_name = stringf("cpa_%d", cpa_ix - offset); - RTLIL::Wire *ci_wire; + SigBit ci; if (base_case) - ci_wire = cori_n_int[enc_count - 1]; + ci = cori_n_int[enc_count - 1]; else - ci_wire = cpa_carry[cpa_ix - offset - 1]; + ci = cpa_carry[cpa_ix - offset - 1]; - RTLIL::Wire *op_wire = module->addWire(NEW_ID, 1); - BuildHa(cpa_name, fa_sum_n[(fa_row_count - 1) * fa_count + cpa_ix - offset + 2], ci_wire, op_wire, + SigBit op; + BuildHa(cpa_name, fa_sum_n[(fa_row_count - 1) * fa_count + cpa_ix - offset + 2], ci, op, cpa_carry[cpa_ix - offset]); - module->connect(op_wire, SigSpec(Z, cpa_ix, 1)); + module->connect(Z[cpa_ix], op); } } @@ -1473,51 +1204,72 @@ struct BoothPassWorker { // std::string q1_name = "icb_booth_q1_"; - RTLIL::Wire *pp0_o_int; - RTLIL::Wire *pp1_o_int; - RTLIL::Wire *nxj_o_int; - RTLIL::Wire *cor_o_int; + SigBit pp0_o_int; + SigBit pp1_o_int; + SigBit nxj_o_int; + SigBit cor_o_int; BuildBoothQ1(q1_name, negi_n_int[0], // negi cori_n_int[0], // cori - mk_wireFromSigSpec(SigSpec(X, 0, 1)), // x0 - mk_wireFromSigSpec(SigSpec(X, 1, 1)), // x1 - mk_wireFromSigSpec(SigSpec(Y, 0, 1)), // y0 - mk_wireFromSigSpec(SigSpec(Y, 1, 1)), // y1 + X[0], X[1], Y[0], Y[1], nxj_o_int, cor_o_int, pp0_o_int, pp1_o_int); - join_wires_with_buffer(pp0_o_int, fa_sum_n[(0 * fa_count) + 0]); - join_wires_with_buffer(pp1_o_int, fa_sum_n[(0 * fa_count) + 1]); - join_wires_with_buffer(cor_o_int, fa_carry_n[(0 * fa_count) + 1]); - join_wires_with_buffer(nxj_o_int, nxj[(0 * dec_count) + 2]); - - delete[] negi_n_int; - delete[] twoi_n_int; - delete[] onei_n_int; - delete[] cori_n_int; - - delete[] fa_sum_n; - delete[] fa_carry_n; - delete[] cpa_carry; + module->connect(fa_sum_n[(0 * fa_count) + 0], pp0_o_int); + module->connect(fa_sum_n[(0 * fa_count) + 1], pp1_o_int); + module->connect(fa_carry_n[(0 * fa_count) + 1], cor_o_int); + module->connect(nxj[(0 * dec_count) + 2], nxj_o_int); } }; struct BoothPass : public Pass { - BoothPass() : Pass("booth", "Map $mul to booth multipliers") {} + BoothPass() : Pass("booth", "map $mul cells to Booth multipliers") {} + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" booth [selection]\n"); + log("\n"); + log("This pass replaces multiplier cells with an implementation based on the Booth\n"); + log("algorithm. It operates on $mul cells whose width of operands is at least 4x4\n"); + log("and whose width of result is at least 8. The detailed architecture is selected\n"); + log("from two options based on the signedness of the operands to the $mul cell.\n"); + log("\n"); + log("See the references below for the description of the architectures.\n"); + log("\n"); + log("Signed-multiplier architecture:\n"); + log("Y. J. Chang, Y. C. Cheng, S. C. Liao and C. H. Hsiao, \"A Low Power Radix-4 Booth\n"); + log("Multiplier With Pre-Encoded Mechanism,\" in IEEE Access, vol. 8, pp. 114842-114853,\n"); + log("2020, doi: 10.1109/ACCESS.2020.3003684\n"); + log("\n"); + log("Unsigned-multiplier architecture:\n"); + log("G. W. Bewick, \"Fast Multiplication: Algorithms and Implementations,\" PhD Thesis,\n"); + log("Department of Electrical Engineering, Stanford University, 1994\n"); + log("\n"); + } void execute(vector args, RTLIL::Design *design) override { - (void)args; - log_header(design, - "Executing booth pass. Generating Booth Multiplier structures for signed/unsigned multipliers of 4 bits or more\n"); - for (auto mod : design->selected_modules()) + log_header(design, "Executing BOOTH pass (map to Booth multipliers).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + break; + } + extra_args(args, argidx, design); + + int total = 0; + + for (auto mod : design->selected_modules()) { if (!mod->has_processes_warn()) { BoothPassWorker worker(mod); worker.run(); - log_header(design, "Created %d booth multipliers.\n", worker.booth_counter); + total += worker.booth_counter; } + } + + log("Mapped %d multipliers.\n", total); } } MultPass; diff --git a/passes/techmap/flatten.cc b/passes/techmap/flatten.cc index 7e6df5d2c..4ddc4aff1 100644 --- a/passes/techmap/flatten.cc +++ b/passes/techmap/flatten.cc @@ -312,7 +312,7 @@ struct FlattenPass : public Pass { for (auto cell : module->selected_cells()) { RTLIL::Module *tpl = design->module(cell->type); if (tpl != nullptr) { - if (topo_modules.database.count(tpl) == 0) + if (!topo_modules.has_node(tpl)) worklist.insert(tpl); topo_modules.edge(tpl, module); } diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc index 11692b715..7461460fe 100644 --- a/passes/techmap/simplemap.cc +++ b/passes/techmap/simplemap.cc @@ -36,7 +36,7 @@ void simplemap_not(RTLIL::Module *module, RTLIL::Cell *cell) for (int i = 0; i < GetSize(sig_y); i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_NOT_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a[i]); gate->setPort(ID::Y, sig_y[i]); } @@ -73,7 +73,7 @@ void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell) for (int i = 0; i < GetSize(sig_y); i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a[i]); gate->setPort(ID::B, sig_b[i]); gate->setPort(ID::Y, sig_y[i]); @@ -124,7 +124,7 @@ void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell) } RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a[i]); gate->setPort(ID::B, sig_a[i+1]); gate->setPort(ID::Y, sig_t[i/2]); @@ -137,7 +137,7 @@ void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell) if (cell->type == ID($reduce_xnor)) { RTLIL::SigSpec sig_t = module->addWire(NEW_ID); RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_NOT_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a); gate->setPort(ID::Y, sig_t); last_output_cell = gate; @@ -165,7 +165,7 @@ static void logic_reduce(RTLIL::Module *module, RTLIL::SigSpec &sig, RTLIL::Cell } RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_OR_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig[i]); gate->setPort(ID::B, sig[i+1]); gate->setPort(ID::Y, sig_t[i/2]); @@ -194,7 +194,7 @@ void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell) } RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_NOT_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a); gate->setPort(ID::Y, sig_y); } @@ -223,7 +223,7 @@ void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell) log_assert(!gate_type.empty()); RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a); gate->setPort(ID::B, sig_b); gate->setPort(ID::Y, sig_y); @@ -239,20 +239,20 @@ void simplemap_eqne(RTLIL::Module *module, RTLIL::Cell *cell) RTLIL::SigSpec xor_out = module->addWire(NEW_ID, max(GetSize(sig_a), GetSize(sig_b))); RTLIL::Cell *xor_cell = module->addXor(NEW_ID, sig_a, sig_b, xor_out, is_signed); - xor_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + xor_cell->attributes[ID::src] = cell->attributes[ID::src]; simplemap_bitop(module, xor_cell); module->remove(xor_cell); RTLIL::SigSpec reduce_out = is_ne ? sig_y : module->addWire(NEW_ID); RTLIL::Cell *reduce_cell = module->addReduceOr(NEW_ID, xor_out, reduce_out); - reduce_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + reduce_cell->attributes[ID::src] = cell->attributes[ID::src]; simplemap_reduce(module, reduce_cell); module->remove(reduce_cell); if (!is_ne) { RTLIL::Cell *not_cell = module->addLogicNot(NEW_ID, reduce_out, sig_y); - not_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); - simplemap_lognot(module, not_cell); + not_cell->attributes[ID::src] = cell->attributes[ID::src]; + simplemap_lognot(module, not_cell); module->remove(not_cell); } } @@ -265,7 +265,7 @@ void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell) for (int i = 0; i < GetSize(sig_y); i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a[i]); gate->setPort(ID::B, sig_b[i]); gate->setPort(ID::S, cell->getPort(ID::S)); @@ -282,7 +282,7 @@ void simplemap_bwmux(RTLIL::Module *module, RTLIL::Cell *cell) for (int i = 0; i < GetSize(sig_y); i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a[i]); gate->setPort(ID::B, sig_b[i]); gate->setPort(ID::S, sig_s[i]); @@ -298,7 +298,7 @@ void simplemap_tribuf(RTLIL::Module *module, RTLIL::Cell *cell) for (int i = 0; i < GetSize(sig_y); i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_TBUF_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a[i]); gate->setPort(ID::E, sig_e); gate->setPort(ID::Y, sig_y[i]); @@ -316,7 +316,7 @@ void simplemap_bmux(RTLIL::Module *module, RTLIL::Cell *cell) for (int i = 0; i < GetSize(new_data); i += width) { for (int k = 0; k < width; k++) { RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, data[i*2+k]); gate->setPort(ID::B, data[i*2+width+k]); gate->setPort(ID::S, sel[idx]); @@ -339,7 +339,7 @@ void simplemap_lut(RTLIL::Module *module, RTLIL::Cell *cell) SigSpec new_lut_data = module->addWire(NEW_ID, GetSize(lut_data)/2); for (int i = 0; i < GetSize(lut_data); i += 2) { RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, lut_data[i]); gate->setPort(ID::B, lut_data[i+1]); gate->setPort(ID::S, lut_ctrl[idx]); diff --git a/techlibs/gowin/cells_sim.v b/techlibs/gowin/cells_sim.v index 86bd677e2..b26869080 100644 --- a/techlibs/gowin/cells_sim.v +++ b/techlibs/gowin/cells_sim.v @@ -197,7 +197,7 @@ module DFFE (output reg Q, input D, CLK, CE); end endmodule // DFFE (positive clock edge; clock enable) -(* abc9_box, lib_whitebox *) +(* abc9_flop, lib_whitebox *) module DFFS (output reg Q, input D, CLK, SET); parameter [0:0] INIT = 1'b1; initial Q = INIT; @@ -216,7 +216,7 @@ module DFFS (output reg Q, input D, CLK, SET); end endmodule // DFFS (positive clock edge; synchronous set) -(* abc9_box, lib_whitebox *) +(* abc9_flop, lib_whitebox *) module DFFSE (output reg Q, input D, CLK, CE, SET); parameter [0:0] INIT = 1'b1; initial Q = INIT; @@ -282,7 +282,7 @@ module DFFP (output reg Q, input D, CLK, PRESET); specify (posedge CLK => (Q : D)) = (480, 660); - (posedge PRESET => (Q : 1'b1)) = (1800, 2679); + (PRESET => Q) = (1800, 2679); $setup(D, posedge CLK, 576); endspecify @@ -301,7 +301,7 @@ module DFFPE (output reg Q, input D, CLK, CE, PRESET); specify if (CE) (posedge CLK => (Q : D)) = (480, 660); - (posedge PRESET => (Q : 1'b1)) = (1800, 2679); + (PRESET => Q) = (1800, 2679); $setup(D, posedge CLK &&& CE, 576); $setup(CE, posedge CLK, 63); endspecify @@ -321,7 +321,7 @@ module DFFC (output reg Q, input D, CLK, CLEAR); specify (posedge CLK => (Q : D)) = (480, 660); - (posedge CLEAR => (Q : 1'b0)) = (1800, 2679); + (CLEAR => Q) = (1800, 2679); $setup(D, posedge CLK, 576); endspecify @@ -340,7 +340,7 @@ module DFFCE (output reg Q, input D, CLK, CE, CLEAR); specify if (CE) (posedge CLK => (Q : D)) = (480, 660); - (posedge CLEAR => (Q : 1'b0)) = (1800, 2679); + (CLEAR => Q) = (1800, 2679); $setup(D, posedge CLK &&& CE, 576); $setup(CE, posedge CLK, 63); endspecify @@ -384,7 +384,7 @@ module DFFNE (output reg Q, input D, CLK, CE); end endmodule // DFFNE (negative clock edge; clock enable) -(* abc9_box, lib_whitebox *) +(* abc9_flop, lib_whitebox *) module DFFNS (output reg Q, input D, CLK, SET); parameter [0:0] INIT = 1'b1; initial Q = INIT; @@ -403,7 +403,7 @@ module DFFNS (output reg Q, input D, CLK, SET); end endmodule // DFFNS (negative clock edge; synchronous set) -(* abc9_box, lib_whitebox *) +(* abc9_flop, lib_whitebox *) module DFFNSE (output reg Q, input D, CLK, CE, SET); parameter [0:0] INIT = 1'b1; initial Q = INIT; @@ -469,7 +469,7 @@ module DFFNP (output reg Q, input D, CLK, PRESET); specify (negedge CLK => (Q : D)) = (480, 660); - (posedge PRESET => (Q : 1'b1)) = (1800, 2679); + (PRESET => Q) = (1800, 2679); $setup(D, negedge CLK, 576); endspecify @@ -488,7 +488,7 @@ module DFFNPE (output reg Q, input D, CLK, CE, PRESET); specify if (CE) (negedge CLK => (Q : D)) = (480, 660); - (posedge PRESET => (Q : 1'b1)) = (1800, 2679); + (PRESET => Q) = (1800, 2679); $setup(D, negedge CLK &&& CE, 576); $setup(CE, negedge CLK, 63); endspecify @@ -508,7 +508,7 @@ module DFFNC (output reg Q, input D, CLK, CLEAR); specify (negedge CLK => (Q : D)) = (480, 660); - (posedge CLEAR => (Q : 1'b0)) = (1800, 2679); + (CLEAR => Q) = (1800, 2679); $setup(D, negedge CLK, 576); endspecify @@ -527,7 +527,7 @@ module DFFNCE (output reg Q, input D, CLK, CE, CLEAR); specify if (CE) (negedge CLK => (Q : D)) = (480, 660); - (posedge CLEAR => (Q : 1'b0)) = (1800, 2679); + (CLEAR => Q) = (1800, 2679); $setup(D, negedge CLK &&& CE, 576); $setup(CE, negedge CLK, 63); endspecify @@ -957,7 +957,7 @@ end endmodule - +(* abc9_flop, lib_whitebox *) module RAM16S1 (DO, DI, AD, WRE, CLK); parameter INIT_0 = 16'h0000; @@ -992,7 +992,7 @@ end endmodule - +(* abc9_flop, lib_whitebox *) module RAM16S2 (DO, DI, AD, WRE, CLK); parameter INIT_0 = 16'h0000; @@ -1031,7 +1031,7 @@ end endmodule - +(* abc9_flop, lib_whitebox *) module RAM16S4 (DO, DI, AD, WRE, CLK); parameter INIT_0 = 16'h0000; diff --git a/tests/arch/quicklogic/dffs.ys b/tests/arch/quicklogic/dffs.ys index 2e0a34540..e1fbef635 100644 --- a/tests/arch/quicklogic/dffs.ys +++ b/tests/arch/quicklogic/dffs.ys @@ -7,14 +7,27 @@ hierarchy -top my_dff proc equiv_opt -async2sync -assert -map +/quicklogic/pp3_cells_sim.v -map +/quicklogic/cells_sim.v synth_quicklogic # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) -cd dff # Constrain all select calls below inside the top module -select -assert-none t:* +cd my_dff # Constrain all select calls below inside the top module +select -assert-count 1 t:ckpad +select -assert-count 1 t:dffepc +select -assert-count 1 t:inpad +select -assert-count 1 t:logic_0 +select -assert-count 1 t:logic_1 +select -assert-count 1 t:outpad + +select -assert-none t:ckpad t:dffepc t:inpad t:logic_0 t:logic_1 t:outpad %% t:* %D design -load read hierarchy -top my_dffe proc equiv_opt -async2sync -assert -map +/quicklogic/pp3_cells_sim.v -map +/quicklogic/cells_sim.v synth_quicklogic # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) -cd dffe # Constrain all select calls below inside the top module +cd my_dffe # Constrain all select calls below inside the top module -select -assert-none t:* \ No newline at end of file +select -assert-count 1 t:ckpad +select -assert-count 1 t:dffepc +select -assert-count 2 t:inpad +select -assert-count 1 t:logic_0 +select -assert-count 1 t:outpad + +select -assert-none t:ckpad t:dffepc t:inpad t:logic_0 t:outpad %% t:* %D diff --git a/tests/sva/sva_value_change_changed.sv b/tests/sva/sva_value_change_changed.sv index 8f3a05a2f..3ce207850 100644 --- a/tests/sva/sva_value_change_changed.sv +++ b/tests/sva/sva_value_change_changed.sv @@ -8,9 +8,11 @@ module top ( $changed(b) ); + wire x = 'x; + `ifndef FAIL assume property ( - b !== 'x ##1 $changed(b) + b !== x ##1 $changed(b) ); `endif diff --git a/tests/techmap/booth.ys b/tests/techmap/booth.ys index f1dce1f3b..55dfdb8e9 100644 --- a/tests/techmap/booth.ys +++ b/tests/techmap/booth.ys @@ -1 +1,15 @@ -test_cell -s 1694091355 -n 1000 -script booth_map_script.ys_ $mul +read_verilog <>= 2) * 4; + check(96, 200, 24); + y = (z >>= 1'sb1) * 2; // shift is implicitly cast to unsigned + check(96, 24, 12); + + // check width of post-increment expressions + z = (y = 0); + begin + byte w; + w = 0; + x = {1'b1, ++w}; + check(257, 0, 0); + assert (w == 1); + x = {2'b10, w++}; + check(513, 0, 0); + assert (w == 2); + end + end +endmodule diff --git a/tests/verilog/asgn_expr.ys b/tests/verilog/asgn_expr.ys new file mode 100644 index 000000000..18180c785 --- /dev/null +++ b/tests/verilog/asgn_expr.ys @@ -0,0 +1,3 @@ +read_verilog -sv asgn_expr.sv +proc +sat -verify -prove-asserts -show-all diff --git a/tests/verilog/asgn_expr_not_proc_1.ys b/tests/verilog/asgn_expr_not_proc_1.ys new file mode 100644 index 000000000..72ba0bd89 --- /dev/null +++ b/tests/verilog/asgn_expr_not_proc_1.ys @@ -0,0 +1,7 @@ +logger -expect error "Assignments within expressions are only permitted within procedures." 1 +read_verilog -sv <