mirror of https://github.com/YosysHQ/yosys.git
Merge branch 'master' into krys/docs
Fix failing verific tests
This commit is contained in:
commit
8fad77bd0f
|
@ -4,6 +4,7 @@
|
|||
*.gch
|
||||
*.gcda
|
||||
*.gcno
|
||||
*~
|
||||
__pycache__
|
||||
/.cproject
|
||||
/.project
|
||||
|
|
26
CHANGELOG
26
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
|
||||
|
|
10
Makefile
10
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)
|
||||
|
|
|
@ -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
|
||||
==========================
|
||||
|
|
|
@ -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<size_t Bits>
|
||||
|
@ -1118,6 +1122,7 @@ struct debug_item : ::cxxrtl_object {
|
|||
curr = const_cast<chunk_t*>(item.data);
|
||||
next = nullptr;
|
||||
outline = nullptr;
|
||||
attrs = nullptr;
|
||||
}
|
||||
|
||||
template<size_t Bits>
|
||||
|
@ -1134,6 +1139,7 @@ struct debug_item : ::cxxrtl_object {
|
|||
curr = item.curr.data;
|
||||
next = item.next.data;
|
||||
outline = nullptr;
|
||||
attrs = nullptr;
|
||||
}
|
||||
|
||||
template<size_t Width>
|
||||
|
@ -1149,6 +1155,7 @@ struct debug_item : ::cxxrtl_object {
|
|||
curr = item.data ? item.data[0].data : nullptr;
|
||||
next = nullptr;
|
||||
outline = nullptr;
|
||||
attrs = nullptr;
|
||||
}
|
||||
|
||||
template<size_t Bits>
|
||||
|
@ -1164,6 +1171,7 @@ struct debug_item : ::cxxrtl_object {
|
|||
curr = const_cast<chunk_t*>(item.data);
|
||||
next = nullptr;
|
||||
outline = nullptr;
|
||||
attrs = nullptr;
|
||||
}
|
||||
|
||||
template<size_t Bits>
|
||||
|
@ -1180,6 +1188,7 @@ struct debug_item : ::cxxrtl_object {
|
|||
curr = const_cast<chunk_t*>(item.curr.data);
|
||||
next = nullptr;
|
||||
outline = nullptr;
|
||||
attrs = nullptr;
|
||||
}
|
||||
|
||||
template<size_t Bits>
|
||||
|
@ -1195,6 +1204,7 @@ struct debug_item : ::cxxrtl_object {
|
|||
curr = const_cast<chunk_t*>(item.data);
|
||||
next = nullptr;
|
||||
outline = &group;
|
||||
attrs = nullptr;
|
||||
}
|
||||
|
||||
template<size_t Bits, class IntegerT>
|
||||
|
@ -1215,10 +1225,28 @@ struct debug_item : ::cxxrtl_object {
|
|||
};
|
||||
static_assert(std::is_standard_layout<debug_item>::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<std::string, std::vector<debug_item>> table;
|
||||
std::map<std::string, std::unique_ptr<debug_attrs>> 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<debug_attrs> &attrs = attrs_table[name];
|
||||
if (attrs.get() == nullptr)
|
||||
attrs = std::unique_ptr<debug_attrs>(new debug_attrs);
|
||||
for (auto attr : item_attrs)
|
||||
attrs->map.insert(attr);
|
||||
item.attrs = attrs.get();
|
||||
std::vector<debug_item> &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(),
|
||||
|
|
|
@ -2120,6 +2120,46 @@ struct CxxrtlWorker {
|
|||
dec_indent();
|
||||
}
|
||||
|
||||
void dump_metadata_map(const dict<RTLIL::IdString, RTLIL::Const> &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<RTLIL::IdString, RTLIL::Const> 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<RTLIL::IdString, RTLIL::Const> &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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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 dict<RTLIL::Id
|
|||
|
||||
AstNode *new_ast = ast->clone();
|
||||
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 dict<RTLIL::Id
|
|||
new_ast->children.push_back(defparam);
|
||||
}
|
||||
|
||||
new_ast->fixup_hierarchy_flags(true);
|
||||
(*new_ast_out) = new_ast;
|
||||
return modname;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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<RTLIL::IdString, RTLIL::Const> &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::map<std::string,std::strin
|
|||
for (const auto &i : parameters)
|
||||
verific_params.Insert(i.first.c_str(), i.second.c_str());
|
||||
|
||||
#ifdef YOSYSHQ_VERIFIC_EXTENSIONS
|
||||
VerificExtensions::ElaborateAndRewrite("work", &verific_params);
|
||||
verific_error_msg.clear();
|
||||
#endif
|
||||
|
||||
if (top.empty()) {
|
||||
|
||||
#ifdef YOSYSHQ_VERIFIC_EXTENSIONS
|
||||
VerificExtensions::ElaborateAndRewrite("work", &verific_params);
|
||||
verific_error_msg.clear();
|
||||
#endif
|
||||
netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, &verific_params);
|
||||
}
|
||||
else {
|
||||
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) ;
|
||||
#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::map<std::string,std::strin
|
|||
continue;
|
||||
nl->AddAtt(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::map<std::string,std::strin
|
|||
if (nl_done.count(it->first) == 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<std::string> 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);
|
||||
}
|
||||
|
|
|
@ -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<IdString, AstNode*> *stmt_attr, AstNode *lhs,
|
||||
dict<IdString, AstNode*> *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<IdString, AstNode*> *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<IdString, AstNode*> *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> integer_atom_type integer_vector_type
|
||||
%type <al> attr case_attr
|
||||
%type <ast> struct_union
|
||||
%type <ast_node_type> asgn_binop
|
||||
%type <ast_node_type> asgn_binop inc_or_dec_op
|
||||
%type <ast> genvar_identifier
|
||||
|
||||
%type <specify_target_ptr> 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:
|
||||
|
|
|
@ -90,6 +90,12 @@ template<> struct hash_ops<uint32_t> : hash_int_ops
|
|||
return a;
|
||||
}
|
||||
};
|
||||
template<> struct hash_ops<uint64_t> : hash_int_ops
|
||||
{
|
||||
static inline unsigned int hash(uint64_t a) {
|
||||
return mkhash((unsigned int)(a), (unsigned int)(a >> 32));
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct hash_ops<std::string> {
|
||||
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);
|
||||
|
|
|
@ -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<RTLIL::SigBit, int> 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];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 = "");
|
||||
|
|
132
kernel/utils.h
132
kernel/utils.h
|
@ -128,41 +128,103 @@ public:
|
|||
// A simple class for topological sorting
|
||||
// ------------------------------------------------
|
||||
|
||||
template<typename T, typename C = std::less<T>>
|
||||
struct TopoSort
|
||||
template <typename T, typename C = std::less<T>, typename OPS = hash_ops<T>> class TopoSort
|
||||
{
|
||||
bool analyze_loops, found_loops;
|
||||
std::map<T, std::set<T, C>, C> database;
|
||||
std::set<std::set<T, C>> loops;
|
||||
std::vector<T> 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<T> &nodes) : node_cmp_(), nodes_(nodes) {}
|
||||
bool operator()(int a, int b) const
|
||||
{
|
||||
log_assert(static_cast<size_t>(a) < nodes_.size());
|
||||
log_assert(static_cast<size_t>(b) < nodes_.size());
|
||||
return node_cmp_(nodes_[a], nodes_[b]);
|
||||
}
|
||||
const C node_cmp_;
|
||||
const std::vector<T> &nodes_;
|
||||
};
|
||||
|
||||
TopoSort()
|
||||
bool analyze_loops;
|
||||
std::map<T, int, C> node_to_index;
|
||||
std::vector<std::set<int, IndirectCmp>> edges;
|
||||
std::vector<T> sorted;
|
||||
std::set<std::set<T, C>> 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<T, C>();
|
||||
auto rv = node_to_index.emplace(n, static_cast<int>(nodes.size()));
|
||||
if (rv.second) {
|
||||
nodes.push_back(n);
|
||||
edges.push_back(std::set<int, IndirectCmp>(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<bool> marked_cells(edges.size(), false);
|
||||
std::vector<bool> active_cells(edges.size(), false);
|
||||
std::vector<int> 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<T, C> &marked_cells, std::set<T, C> &active_cells, std::vector<T> &active_stack)
|
||||
// Build the more expensive representation of edges for
|
||||
// a few passes that use it directly.
|
||||
std::map<T, std::set<T, C>, C> get_database()
|
||||
{
|
||||
if (active_cells.count(n)) {
|
||||
std::map<T, std::set<T, C>, C> database;
|
||||
for (size_t i = 0; i < nodes.size(); ++i) {
|
||||
std::set<T, C> 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<T> nodes;
|
||||
const IndirectCmp indirect_cmp;
|
||||
|
||||
void sort_worker(const int root_index, std::vector<bool> &marked_cells, std::vector<bool> &active_cells, std::vector<int> &active_stack)
|
||||
{
|
||||
if (active_cells[root_index]) {
|
||||
found_loops = true;
|
||||
if (analyze_loops) {
|
||||
std::set<T, C> 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<T, C> marked_cells;
|
||||
std::set<T, C> active_cells;
|
||||
std::vector<T> 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]);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<std::string> split_tokens(const std::string &text, const char *sep = " \t\r\n");
|
||||
|
|
|
@ -24,8 +24,8 @@ PRIVATE_NAMESPACE_BEGIN
|
|||
|
||||
int autoname_worker(Module *module, const dict<Wire*, int>& wire_score)
|
||||
{
|
||||
dict<Cell*, pair<int, IdString>> proposed_cell_names;
|
||||
dict<Wire*, pair<int, IdString>> proposed_wire_names;
|
||||
dict<Cell*, pair<int, string>> proposed_cell_names;
|
||||
dict<Wire*, pair<int, string>> 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*, int>& 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*, int>& 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*, int>& 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*, int>& 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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include "kernel/log.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <set>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
@ -39,18 +38,18 @@ struct SccWorker
|
|||
SigMap sigmap;
|
||||
CellTypes ct, specifyCells;
|
||||
|
||||
std::set<RTLIL::Cell*> workQueue;
|
||||
std::map<RTLIL::Cell*, std::set<RTLIL::Cell*>> cellToNextCell;
|
||||
std::map<RTLIL::Cell*, RTLIL::SigSpec> cellToPrevSig, cellToNextSig;
|
||||
pool<RTLIL::Cell*> workQueue;
|
||||
dict<RTLIL::Cell*, pool<RTLIL::Cell*>> cellToNextCell;
|
||||
dict<RTLIL::Cell*, RTLIL::SigSpec> cellToPrevSig, cellToNextSig;
|
||||
|
||||
std::map<RTLIL::Cell*, std::pair<int, int>> cellLabels;
|
||||
std::map<RTLIL::Cell*, int> cellDepth;
|
||||
std::set<RTLIL::Cell*> cellsOnStack;
|
||||
dict<RTLIL::Cell*, std::pair<int, int>> cellLabels;
|
||||
dict<RTLIL::Cell*, int> cellDepth;
|
||||
pool<RTLIL::Cell*> cellsOnStack;
|
||||
std::vector<RTLIL::Cell*> cellStack;
|
||||
int labelCounter;
|
||||
|
||||
std::map<RTLIL::Cell*, int> cell2scc;
|
||||
std::vector<std::set<RTLIL::Cell*>> sccList;
|
||||
dict<RTLIL::Cell*, int> cell2scc;
|
||||
std::vector<pool<RTLIL::Cell*>> sccList;
|
||||
|
||||
void run(RTLIL::Cell *cell, int depth, int maxDepth)
|
||||
{
|
||||
|
@ -85,7 +84,7 @@ struct SccWorker
|
|||
else
|
||||
{
|
||||
log("Found an SCC:");
|
||||
std::set<RTLIL::Cell*> scc;
|
||||
pool<RTLIL::Cell*> 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<RTLIL::Cell*> scc;
|
||||
pool<RTLIL::Cell*> 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<RTLIL::Cell*> &cells = sccList[i];
|
||||
pool<RTLIL::Cell*> &cells = sccList[i];
|
||||
RTLIL::SigSpec prevsig, nextsig, sig;
|
||||
|
||||
for (auto cell : cells) {
|
||||
|
@ -295,7 +294,7 @@ struct SccPass : public Pass {
|
|||
}
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||
{
|
||||
std::map<std::string, std::string> setAttr;
|
||||
dict<std::string, std::string> setAttr;
|
||||
bool allCellTypes = false;
|
||||
bool selectMode = false;
|
||||
bool nofeedbackMode = false;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -41,7 +41,6 @@ struct OptMergeWorker
|
|||
|
||||
CellTypes ct;
|
||||
int total_count;
|
||||
SHA1 checksum;
|
||||
|
||||
static void sort_pmux_conn(dict<RTLIL::IdString, RTLIL::SigSpec> &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<string> 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<std::string>{}(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<std::string, RTLIL::Cell*> sharemap;
|
||||
dict<uint64_t, RTLIL::Cell*> 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)) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -212,7 +212,7 @@ second argument, and the matcher will iterate over those options:
|
|||
index <SigSpec> 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`.
|
||||
|
|
|
@ -24,11 +24,8 @@ USING_YOSYS_NAMESPACE
|
|||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
bool did_something;
|
||||
dict<SigBit, State> initbits;
|
||||
pool<SigBit> 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<<K) where C and K are constants\n");
|
||||
log(" and A' is derived from A by appropriately inserting padding\n");
|
||||
log(" into the signal. (right variant)\n");
|
||||
log("\n");
|
||||
log(" Analogously, replace A<<(B*C) with appropriate selection of\n");
|
||||
log(" output bits from A<<(B<<K). (left variant)\n");
|
||||
log("\n");
|
||||
}
|
||||
void execute(std::vector<std::string> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,92 +0,0 @@
|
|||
pattern shiftmul
|
||||
//
|
||||
// Optimize mul+shift pairs that result from expressions such as foo[s*W+:W]
|
||||
//
|
||||
|
||||
state <SigSpec> shamt
|
||||
|
||||
match shift
|
||||
select shift->type.in($shift, $shiftx, $shr)
|
||||
endmatch
|
||||
|
||||
code shamt
|
||||
shamt = port(shift, \B);
|
||||
if (shamt.empty())
|
||||
reject;
|
||||
if (shamt[GetSize(shamt)-1] == State::S0) {
|
||||
do {
|
||||
shamt.remove(GetSize(shamt)-1);
|
||||
if (shamt.empty())
|
||||
reject;
|
||||
} while (shamt[GetSize(shamt)-1] == State::S0);
|
||||
} else
|
||||
if (shift->type.in($shift, $shiftx) && param(shift, \B_SIGNED).as_bool()) {
|
||||
reject;
|
||||
}
|
||||
if (GetSize(shamt) > 20)
|
||||
reject;
|
||||
endcode
|
||||
|
||||
match mul
|
||||
select mul->type.in($mul)
|
||||
select port(mul, \A).is_fully_const() || port(mul, \B).is_fully_const()
|
||||
index <SigSpec> port(mul, \Y) === shamt
|
||||
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
|
|
@ -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 <SigSpec> port(neg, \Y) === port(shift, \B)
|
||||
filter !port(shift, \A).empty()
|
||||
endmatch
|
||||
|
||||
// the left shift amount
|
||||
state <SigSpec> shift_amount
|
||||
// log2 scale factor in interpreting of shift_amount
|
||||
// due to zero padding on the shift cell's B port
|
||||
state <int> 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 <SigSpec> mul_din
|
||||
state <Const> mul_const
|
||||
|
||||
match mul
|
||||
select mul->type.in($mul)
|
||||
index <SigSpec> port(mul, \Y) === shift_amount
|
||||
filter !param(mul, \A_SIGNED).as_bool()
|
||||
|
||||
choice <IdString> constport {\A, \B}
|
||||
filter port(mul, constport).is_fully_const()
|
||||
|
||||
define <IdString> 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
|
|
@ -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 <SigSpec> shift_amount
|
||||
// log2 scale factor in interpreting of shift_amount
|
||||
// due to zero padding on the shift cell's B port
|
||||
state <int> 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 <SigSpec> mul_din
|
||||
state <Const> mul_const
|
||||
|
||||
match mul
|
||||
select mul->type.in($mul)
|
||||
index <SigSpec> port(mul, \Y) === shift_amount
|
||||
filter !param(mul, \A_SIGNED).as_bool()
|
||||
|
||||
choice <IdString> constport {\A, \B}
|
||||
filter port(mul, constport).is_fully_const()
|
||||
|
||||
define <IdString> 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
|
|
@ -29,13 +29,6 @@
|
|||
|
||||
USING_YOSYS_NAMESPACE
|
||||
|
||||
template<> struct hashlib::hash_ops<uint64_t> : 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<IdString> comb_whiteboxes, buffer_types;
|
||||
|
||||
// class -> (gold, (gate, inverted))
|
||||
dict<equiv_cls_t, std::pair<pool<IdBit>, dict<IdBit, bool>>> cls2bits;
|
||||
dict<equiv_cls_t, std::pair<pool<IdBit>, dict<IdBit, bool>>> cls2bits;
|
||||
|
||||
void analyse_boxes()
|
||||
{
|
||||
|
|
|
@ -111,6 +111,7 @@ struct SimShared
|
|||
int step = 0;
|
||||
std::vector<TriggeredAssertion> 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 <integer>\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;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:*
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -1 +1,15 @@
|
|||
test_cell -s 1694091355 -n 1000 -script booth_map_script.ys_ $mul
|
||||
read_verilog <<EOF
|
||||
module test(clk, a, b, y);
|
||||
input wire clk;
|
||||
input wire [9:0] a;
|
||||
input wire [6:0] b;
|
||||
output wire [20:0] y;
|
||||
|
||||
assign y = a * b;
|
||||
endmodule
|
||||
EOF
|
||||
booth
|
||||
sat -verify -set a 0 -set b 0 -prove y 0
|
||||
design -reset
|
||||
|
||||
test_cell -s 1694091355 -n 100 -script booth_map_script.ys_ $mul
|
|
@ -0,0 +1,94 @@
|
|||
verific -sv <<EOF
|
||||
|
||||
module top(clk);
|
||||
input wire clk;
|
||||
|
||||
parameter DEPTH_LOG2 = 4;
|
||||
parameter DEPTH = 2**DEPTH_LOG2;
|
||||
parameter BYTEWIDTH = 8;
|
||||
parameter WIDTH = BYTEWIDTH*4;
|
||||
parameter PRIME1 = 237481091;
|
||||
parameter PRIME2 = 296851369;
|
||||
|
||||
(* ram_style = "block" *)
|
||||
reg [WIDTH-1:0] mem [DEPTH-1:0];
|
||||
|
||||
integer i;
|
||||
initial begin
|
||||
for (i = 0; i < DEPTH; i = i + 1) begin
|
||||
// Make up data by multiplying a large prime with the address,
|
||||
// then cropping and retaining the lower bits
|
||||
mem[i] = PRIME1 * i;
|
||||
end
|
||||
end
|
||||
|
||||
reg [DEPTH_LOG2-1:0] counter = 0;
|
||||
reg done = 1'b0;
|
||||
always @(posedge clk) begin
|
||||
if (!done)
|
||||
counter = counter + 1;
|
||||
if (counter == 0)
|
||||
done = 1;
|
||||
end
|
||||
|
||||
wire [WIDTH-1:0] old_data = PRIME1 * counter;
|
||||
wire [WIDTH-1:0] new_data = PRIME2 * counter;
|
||||
|
||||
reg [WIDTH-1:0] expect_old_data;
|
||||
reg [WIDTH-1:0] expect_mixed_data;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (!done) begin
|
||||
expect_old_data <= mem[counter];
|
||||
mem[counter][31:24] <= new_data[31:24];
|
||||
mem[counter][23:16] = new_data[23:16]; // !!! is blocking
|
||||
mem[counter][15:8] <= new_data[15:8];
|
||||
mem[counter][7:0] <= new_data[7:0];
|
||||
expect_mixed_data <= mem[counter];
|
||||
end
|
||||
end
|
||||
|
||||
reg done_delay1 = 1'b1;
|
||||
reg [WIDTH-1:0] new_data_delay1 = 1'b1;
|
||||
reg [WIDTH-1:0] old_data_delay1 = 1'b1;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (!done_delay1) begin
|
||||
assert(expect_old_data == old_data_delay1);
|
||||
assert(expect_mixed_data[31:24] == old_data_delay1[31:24]);
|
||||
assert(expect_mixed_data[23:16] == new_data_delay1[23:16]);
|
||||
assert(expect_mixed_data[15:0] == old_data_delay1[15:0]);
|
||||
end
|
||||
end
|
||||
|
||||
reg [DEPTH_LOG2-1:0] counter_delay1;
|
||||
always @(posedge clk) begin
|
||||
counter_delay1 <= counter;
|
||||
done_delay1 <= done;
|
||||
new_data_delay1 <= new_data;
|
||||
old_data_delay1 <= old_data;
|
||||
end
|
||||
|
||||
reg [DEPTH_LOG2-1:0] counter_delay2;
|
||||
reg done_delay2 = 1'b1;
|
||||
reg [WIDTH-1:0] new_data_delay2 = 1'b1;
|
||||
always @(posedge clk) begin
|
||||
counter_delay2 <= counter_delay1;
|
||||
done_delay2 <= done_delay1;
|
||||
new_data_delay2 <= new_data_delay1;
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (!done_delay2)
|
||||
assert(mem[counter_delay2] == new_data_delay2);
|
||||
end
|
||||
|
||||
endmodule
|
||||
EOF
|
||||
|
||||
hierarchy -top top
|
||||
proc
|
||||
opt_clean
|
||||
memory -nomap
|
||||
select -assert-count 1 t:$mem_v2
|
||||
sim -assert -clock clk -n 20
|
|
@ -0,0 +1,73 @@
|
|||
module top;
|
||||
integer x, y, z;
|
||||
task check;
|
||||
input integer a, b, c;
|
||||
assert (x == a);
|
||||
assert (y == b);
|
||||
assert (z == c);
|
||||
endtask
|
||||
always_comb begin
|
||||
x = 0; y = 0; z = 0;
|
||||
check(0, 0, 0);
|
||||
|
||||
// post-increment/decrement statements
|
||||
x++;
|
||||
check(1, 0, 0);
|
||||
(* bar *) y (* foo *) ++;
|
||||
check(1, 1, 0);
|
||||
z--;
|
||||
check(1, 1, -1);
|
||||
(* bar *) z (* foo *) --;
|
||||
check(1, 1, -2);
|
||||
|
||||
// pre-increment/decrement statements are equivalent
|
||||
++z;
|
||||
check(1, 1, -1);
|
||||
(* bar *) ++ (* foo *) z;
|
||||
check(1, 1, 0);
|
||||
--x;
|
||||
check(0, 1, 0);
|
||||
(* bar *) -- (* foo *) y;
|
||||
check(0, 0, 0);
|
||||
|
||||
// procedural pre-increment/decrement expressions
|
||||
z = ++x;
|
||||
check(1, 0, 1);
|
||||
z = ++ (* foo *) x;
|
||||
check(2, 0, 2);
|
||||
y = --x;
|
||||
check(1, 1, 2);
|
||||
y = -- (* foo *) x;
|
||||
|
||||
// procedural post-increment/decrement expressions
|
||||
// TODO: support attributes on post-increment/decrement
|
||||
check(0, 0, 2);
|
||||
y = x++;
|
||||
check(1, 0, 2);
|
||||
y = x--;
|
||||
check(0, 1, 2);
|
||||
|
||||
// procedural assignment expressions
|
||||
x = (y = (z = 99) + 1) + 1;
|
||||
check(101, 100, 99);
|
||||
x = (y *= 2);
|
||||
check(200, 200, 99);
|
||||
x = (z >>= 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
|
|
@ -0,0 +1,3 @@
|
|||
read_verilog -sv asgn_expr.sv
|
||||
proc
|
||||
sat -verify -prove-asserts -show-all
|
|
@ -0,0 +1,7 @@
|
|||
logger -expect error "Assignments within expressions are only permitted within procedures." 1
|
||||
read_verilog -sv <<EOF
|
||||
module top;
|
||||
integer x, y;
|
||||
assign x = y++;
|
||||
endmodule
|
||||
EOF
|
|
@ -0,0 +1,7 @@
|
|||
logger -expect error "Assignments within expressions are only permitted within procedures." 1
|
||||
read_verilog -sv <<EOF
|
||||
module top;
|
||||
integer x;
|
||||
wire [++x:0] y;
|
||||
endmodule
|
||||
EOF
|
|
@ -0,0 +1,7 @@
|
|||
logger -expect error "Assignments within expressions are only permitted within procedures." 1
|
||||
read_verilog -sv <<EOF
|
||||
module top;
|
||||
integer x;
|
||||
integer y = --x;
|
||||
endmodule
|
||||
EOF
|
|
@ -0,0 +1,7 @@
|
|||
logger -expect error "Assignments within expressions are only permitted within procedures." 1
|
||||
read_verilog -sv <<EOF
|
||||
module top;
|
||||
integer x, y;
|
||||
assign x = (y = 1);
|
||||
endmodule
|
||||
EOF
|
|
@ -0,0 +1,7 @@
|
|||
logger -expect error "Assignments within expressions are only permitted within procedures." 1
|
||||
read_verilog -sv <<EOF
|
||||
module top;
|
||||
integer x, y;
|
||||
assign x = (y += 2);
|
||||
endmodule
|
||||
EOF
|
|
@ -0,0 +1,7 @@
|
|||
logger -expect error "Assignments within expressions are only supported in SystemVerilog mode." 1
|
||||
read_verilog <<EOF
|
||||
module top;
|
||||
integer x, y;
|
||||
initial y = ++x;
|
||||
endmodule
|
||||
EOF
|
|
@ -0,0 +1,7 @@
|
|||
logger -expect error "Assignments within expressions are only supported in SystemVerilog mode." 1
|
||||
read_verilog <<EOF
|
||||
module top;
|
||||
integer x, y;
|
||||
initial y = x++;
|
||||
endmodule
|
||||
EOF
|
|
@ -0,0 +1,7 @@
|
|||
logger -expect error "Assignments within expressions are only supported in SystemVerilog mode." 1
|
||||
read_verilog <<EOF
|
||||
module top;
|
||||
integer x, y;
|
||||
initial y = (x = 1);
|
||||
endmodule
|
||||
EOF
|
|
@ -0,0 +1,15 @@
|
|||
read_verilog -sv <<EOF
|
||||
module top;
|
||||
integer x, y;
|
||||
initial y = (x += 1);
|
||||
endmodule
|
||||
EOF
|
||||
design -reset
|
||||
|
||||
logger -expect error "syntax error, unexpected TOK_ID" 1
|
||||
read_verilog <<EOF
|
||||
module top;
|
||||
integer x, y;
|
||||
initial y = (x += 1);
|
||||
endmodule
|
||||
EOF
|
|
@ -15,7 +15,7 @@ EOT
|
|||
select -assert-none a:* a:src %d
|
||||
|
||||
|
||||
logger -expect error "syntax error, unexpected ATTR_BEGIN" 1
|
||||
logger -expect error "syntax error, unexpected ';', expecting ATTR_BEGIN or TOK_INCREMENT or TOK_DECREMENT" 1
|
||||
design -reset
|
||||
read_verilog <<EOT
|
||||
module top;
|
||||
|
|
Loading…
Reference in New Issue