Merge pull request #531 from antmicro/kr/adapt_surelog
systemverilog plugin: changes required for newer Surelog version
diff --git a/systemverilog-plugin/UhdmAst.cc b/systemverilog-plugin/UhdmAst.cc
index f1b81a9..0be44d7 100644
--- a/systemverilog-plugin/UhdmAst.cc
+++ b/systemverilog-plugin/UhdmAst.cc
@@ -156,6 +156,31 @@
}
}
+template <typename T> class ScopedValueChanger
+{
+ T &ref;
+ const T prev_val;
+
+ public:
+ ScopedValueChanger() = delete;
+
+ explicit ScopedValueChanger(T &r) : ref(r), prev_val(ref) {}
+
+ ScopedValueChanger(T &r, const T &val) : ref(r), prev_val(ref) { ref = val; }
+
+ ScopedValueChanger(ScopedValueChanger &&) = delete;
+ ScopedValueChanger &operator=(ScopedValueChanger &&) = delete;
+
+ ScopedValueChanger(const ScopedValueChanger &) = delete;
+ ScopedValueChanger &operator=(const ScopedValueChanger &) = delete;
+
+ ~ScopedValueChanger() { ref = prev_val; }
+};
+
+template <typename T> ScopedValueChanger(T &)->ScopedValueChanger<T>;
+
+template <typename T> ScopedValueChanger(T &, const T &)->ScopedValueChanger<T>;
+
// Delete all children nodes.
// Does *not* delete attributes.
// This function exists as Yosys's function node->delete_children() does remove all children and attributes.
@@ -182,93 +207,6 @@
}
}
-static std::string get_parent_name(vpiHandle parent_h)
-{
- std::string parent_name;
- if (auto p = vpi_get_str(vpiFullName, parent_h)) {
- parent_name = p;
- } else if (auto p = vpi_get_str(vpiName, parent_h)) {
- parent_name = p;
- } else if (auto p = vpi_get_str(vpiDefName, parent_h)) {
- parent_name = p;
- }
- return parent_name;
-}
-
-// Warning: Takes ownership of `parent_h` and releases it.
-static void find_ancestor_name(vpiHandle parent_h, std::string &name, std::string &parent_name)
-{
-
- while (!parent_name.empty()) {
- parent_name = parent_name + ".";
- if ((name.rfind(parent_name) != std::string::npos)) {
- name = name.substr(name.rfind(parent_name) + parent_name.size());
- break;
- } else {
- auto old_parent_h = parent_h;
- parent_h = vpi_handle(vpiParent, parent_h);
- vpi_release_handle(old_parent_h);
-
- if (parent_h) {
- parent_name = get_parent_name(parent_h);
- } else {
- parent_name.clear();
- }
- }
- }
- vpi_release_handle(parent_h);
-}
-
-static std::string get_name(vpiHandle obj_h, bool prefer_full_name = false)
-{
- auto first_check = prefer_full_name ? vpiFullName : vpiName;
- auto last_check = prefer_full_name ? vpiName : vpiFullName;
- std::string name;
- if (auto s = vpi_get_str(first_check, obj_h)) {
- name = s;
- } else if (auto s = vpi_get_str(vpiDefName, obj_h)) {
- name = s;
- } else if (auto s = vpi_get_str(last_check, obj_h)) {
- name = s;
- }
- // We are looking for the ancestor name to use it as a delimeter
- // when stripping the name of the current node.
- // We used to strip the name by searching for "." in it, but this
- // approach didn't work for the names whith "." as an escaped
- // character.
- vpiHandle parent_h = vpi_handle(vpiParent, obj_h);
-
- if (parent_h) {
- std::string parent_name;
- parent_name = get_parent_name(parent_h);
-
- if (parent_name.empty()) {
- // Nodes of certain types, like param_assign, don't have
- // a name, so we need to look further for the ancestor.
- auto old_parent_h = parent_h;
- parent_h = vpi_handle(vpiParent, parent_h);
- vpi_release_handle(old_parent_h);
-
- if (parent_h) {
- parent_name = get_parent_name(parent_h);
- }
- }
- find_ancestor_name(parent_h, name, parent_name);
- }
- sanitize_symbol_name(name);
- return name;
-}
-
-static std::string strip_package_name(std::string name)
-{
- auto sep_index = name.find("::");
- if (sep_index != string::npos) {
- name = name.substr(sep_index + 1);
- name[0] = '\\';
- }
- return name;
-}
-
static std::string get_object_name(vpiHandle obj_h, const std::vector<int> &name_fields = {vpiName})
{
std::string objectName;
@@ -282,6 +220,18 @@
return objectName;
}
+static std::string get_name(vpiHandle obj_h) { return get_object_name(obj_h, {vpiName, vpiDefName}); }
+
+static std::string strip_package_name(std::string name)
+{
+ auto sep_index = name.find("::");
+ if (sep_index != string::npos) {
+ name = name.substr(sep_index + 1);
+ name[0] = '\\';
+ }
+ return name;
+}
+
static AST::AstNode *mkconst_real(double d)
{
AST::AstNode *node = new AST::AstNode(AST::AST_REALVALUE);
@@ -1796,9 +1746,9 @@
}
}
-void UhdmAst::apply_name_from_current_obj(AST::AstNode &target_node, bool prefer_full_name) const
+void UhdmAst::apply_name_from_current_obj(AST::AstNode &target_node) const
{
- target_node.str = get_name(obj_h, prefer_full_name);
+ target_node.str = get_name(obj_h);
auto it = node_renames.find(target_node.str);
if (it != node_renames.end())
target_node.str = it->second;
@@ -1811,11 +1761,11 @@
return AstNodeBuilder(std::move(node));
};
-AstNodeBuilder UhdmAst::make_named_node(AST::AstNodeType type, bool prefer_full_name) const
+AstNodeBuilder UhdmAst::make_named_node(AST::AstNodeType type) const
{
auto node = std::make_unique<AST::AstNode>(type);
apply_location_from_current_obj(*node);
- apply_name_from_current_obj(*node, prefer_full_name);
+ apply_name_from_current_obj(*node);
return AstNodeBuilder(std::move(node));
};
@@ -1835,10 +1785,10 @@
return make_node(AST::AST_CONSTANT).value(value, false, width);
};
-AST::AstNode *UhdmAst::make_ast_node(AST::AstNodeType type, std::vector<AST::AstNode *> children, bool prefer_full_name)
+AST::AstNode *UhdmAst::make_ast_node(AST::AstNodeType type, std::vector<AST::AstNode *> children)
{
auto node = new AST::AstNode(type);
- apply_name_from_current_obj(*node, prefer_full_name);
+ apply_name_from_current_obj(*node);
apply_location_from_current_obj(*node);
node->children = children;
return node;
@@ -2264,7 +2214,13 @@
});
}
} else {
- // Not a top module, create instance
+ // A module instance inside another uhdmTopModules' module.
+ // Create standalone module instance AST and embed it in the instantiating module using AST_CELL.
+
+ const uhdm_handle *const handle = (const uhdm_handle *)obj_h;
+ const auto *const uhdm_obj = (const UHDM::any *)handle->object;
+ const auto current_instance_changer = ScopedValueChanger(shared.current_instance, uhdm_obj);
+
current_node = make_ast_node(AST::AST_CELL);
std::vector<std::pair<RTLIL::IdString, RTLIL::Const>> parameters;
@@ -2586,7 +2542,6 @@
{
log_assert(expr);
log_assert(inst);
- log_assert(pexpr);
bool invalidvalue = false;
UHDM::ExprEval eval;
@@ -2611,11 +2566,36 @@
if (current_node->str.empty()) {
// anonymous typespec, check if not already created
- if (const auto enum_iter = shared.anonymous_enums.find(enum_object); enum_iter != shared.anonymous_enums.end()) {
- // we already created typedef for this.
- delete current_node;
- current_node = make_node(AST::AST_WIRETYPE);
- current_node->str = enum_iter->second;
+ log_assert(shared.current_top_node);
+ auto check_created_anonymous_enums = [enum_object, this](std::string top_module_name) -> bool {
+ for (auto pair : shared.anonymous_enums[top_module_name]) {
+ UHDM::CompareContext ctx;
+ if (pair.first->Compare(enum_object, &ctx) == 0) {
+ // we already created typedef for this.
+ delete current_node;
+ current_node = make_node(AST::AST_WIRETYPE);
+ current_node->str = pair.second;
+ return true;
+ }
+ }
+ return false;
+ };
+ std::string top_module_name = shared.current_top_node->str;
+ if (check_created_anonymous_enums(top_module_name)) {
+ return;
+ }
+ // in case of parametrized module, also check unparametrized top module
+ // as we could add this enum there and then copy it to parametrized
+ // version
+ if (top_module_name.find("$paramod") != std::string::npos) {
+ // possible names:
+ // $paramod\module_name\PARAM=VAL
+ // $paramod$81af6bf473845aee480c993b90a1ed0117ae9091\module_name
+ top_module_name = top_module_name.substr(top_module_name.find("\\"));
+ if (auto params = top_module_name.find("\\", 1 /* skip first \ */) != std::string::npos)
+ top_module_name = top_module_name.substr(0, params);
+ }
+ if (check_created_anonymous_enums(top_module_name)) {
return;
}
}
@@ -2640,13 +2620,17 @@
if (leftrange_obj->UhdmType() == UHDM::uhdmoperation) {
// Substitute the previous leftrange with the resolved operation result.
- range_obj->Left_expr(reduce_expression(leftrange_obj, enum_object->Instance() ? enum_object->Instance() : enum_object->VpiParent(),
- enum_object->VpiParent()));
+ const UHDM::any *const instance =
+ enum_object->Instance() ? enum_object->Instance() : enum_object->VpiParent() ? enum_object->VpiParent() : shared.current_instance;
+
+ range_obj->Left_expr(reduce_expression(leftrange_obj, instance, enum_object->VpiParent()));
}
if (rightrange_obj->UhdmType() == UHDM::uhdmoperation) {
// Substitute the previous rightrange with the resolved operation result.
- range_obj->Right_expr(reduce_expression(rightrange_obj, enum_object->Instance() ? enum_object->Instance() : enum_object->VpiParent(),
- enum_object->VpiParent()));
+ const UHDM::any *const instance =
+ enum_object->Instance() ? enum_object->Instance() : enum_object->VpiParent() ? enum_object->VpiParent() : shared.current_instance;
+
+ range_obj->Right_expr(reduce_expression(rightrange_obj, instance, enum_object->VpiParent()));
}
}
}
@@ -2716,7 +2700,7 @@
move_type_to_new_typedef(shared.current_top_node, current_node);
current_node = make_node(AST::AST_WIRETYPE);
current_node->str = typedef_name;
- shared.anonymous_enums[enum_object] = std::move(typedef_name);
+ shared.anonymous_enums[shared.current_top_node->str][enum_object] = std::move(typedef_name);
}
}
@@ -3988,23 +3972,13 @@
void UhdmAst::process_bit_select()
{
current_node = make_ast_node(AST::AST_IDENTIFIER);
- visit_one_to_one({vpiIndex}, obj_h, [&](AST::AstNode *node) {
- auto range_node = new AST::AstNode(AST::AST_RANGE, node);
- range_node->filename = current_node->filename;
- range_node->location = current_node->location;
- current_node->children.push_back(range_node);
- });
+ visit_one_to_one({vpiIndex}, obj_h, [&](AST::AstNode *node) { current_node->children.push_back(make_node(AST::AST_RANGE)({node})); });
}
void UhdmAst::process_part_select()
{
current_node = make_ast_node(AST::AST_IDENTIFIER);
- vpiHandle parent_h = vpi_handle(vpiParent, obj_h);
- current_node->str = get_name(parent_h);
- vpi_release_handle(parent_h);
- auto range_node = new AST::AstNode(AST::AST_RANGE);
- range_node->filename = current_node->filename;
- range_node->location = current_node->location;
+ AST::AstNode *range_node = make_node(AST::AST_RANGE);
visit_one_to_one({vpiLeftRange, vpiRightRange}, obj_h, [&](AST::AstNode *node) { range_node->children.push_back(node); });
current_node->children.push_back(range_node);
}
@@ -4012,24 +3986,18 @@
void UhdmAst::process_indexed_part_select()
{
current_node = make_ast_node(AST::AST_IDENTIFIER);
- vpiHandle parent_h = vpi_handle(vpiParent, obj_h);
- current_node->str = get_name(parent_h);
- vpi_release_handle(parent_h);
// TODO: check if there are other types, for now only handle 1 and 2 (+: and -:)
auto indexed_part_select_type = vpi_get(vpiIndexedPartSelectType, obj_h) == 1 ? AST::AST_ADD : AST::AST_SUB;
- auto range_node = new AST::AstNode(AST::AST_RANGE);
- range_node->filename = current_node->filename;
- range_node->location = current_node->location;
+ AST::AstNode *range_node = make_node(AST::AST_RANGE);
visit_one_to_one({vpiBaseExpr}, obj_h, [&](AST::AstNode *node) { range_node->children.push_back(node); });
visit_one_to_one({vpiWidthExpr}, obj_h, [&](AST::AstNode *node) {
- auto right_range_node = new AST::AstNode(indexed_part_select_type);
+ AST::AstNode *right_range_node = make_node(indexed_part_select_type);
right_range_node->children.push_back(range_node->children[0]->clone());
right_range_node->children.push_back(node);
- auto sub = new AST::AstNode(indexed_part_select_type == AST::AST_ADD ? AST::AST_SUB : AST::AST_ADD);
+ AST::AstNode *sub = make_node(indexed_part_select_type == AST::AST_ADD ? AST::AST_SUB : AST::AST_ADD);
sub->children.push_back(right_range_node);
sub->children.push_back(AST::AstNode::mkconst_int(1, false, 1));
range_node->children.push_back(sub);
- // range_node->children.push_back(right_range_node);
});
if (indexed_part_select_type == AST::AST_ADD) {
std::reverse(range_node->children.begin(), range_node->children.end());
@@ -4286,8 +4254,6 @@
void UhdmAst::process_hier_path()
{
- current_node = make_ast_node(AST::AST_IDENTIFIER);
- current_node->str = "\\";
AST::AstNode *top_node = nullptr;
visit_one_to_many({vpiActual}, obj_h, [&](AST::AstNode *node) {
if (node) {
@@ -4295,20 +4261,17 @@
node->str = node->str.substr(0, node->str.find('['));
// for first node, just set correct string and move any children
if (!top_node) {
- current_node->str += node->str.substr(1);
- current_node->children = std::move(node->children);
- node->children.clear();
+ current_node = node;
top_node = current_node;
- delete node;
} else {
- if (!node->children.empty() && node->children[0]->type == AST::AST_RANGE && (node->str == "\\" || node->str.empty())) {
- top_node->children.push_back(node->children[0]);
- node->children.erase(node->children.begin());
- delete node;
- } else {
+ if (node->type == AST::AST_IDENTIFIER && !node->str.empty()) {
node->type = static_cast<AST::AstNodeType>(AST::Extended::AST_DOT);
top_node->children.push_back(node);
top_node = node;
+ } else {
+ top_node->children.push_back(node->children[0]);
+ node->children.erase(node->children.begin());
+ delete node;
}
}
}
@@ -4468,12 +4431,24 @@
current_node->children.push_back(node);
}
});
- // Prefer fully qualified name of a function (prefixed with a scope).
- // This is important when a single function which has been imported from a package
- // calls another function that is not imported in the calling scope.
- if (vpiHandle function_h = vpi_handle(vpiFunction, obj_h)) {
- current_node->str = get_name(function_h, true);
- vpi_release_handle(function_h);
+
+ // Calls to functions imported from packages do not contain package name in vpiName. A full function name, containing package name,
+ // is necessary e.g. when call to a function is used as a value assigned to a port of a module instantiated inside generate for loop.
+ // However, we can't use full function name when it refers to a module's local function.
+ // To make it work the called function name is used instead of vpiName from the call object only when it contains package name (detected here
+ // by presence of "::").
+ // TODO(mglb): This can fail when "::" is just a part of an escaped identifier. Handle such cases properly here and in other places.
+ const uhdm_handle *const handle = (const uhdm_handle *)obj_h;
+ if (handle->type == UHDM::uhdmfunc_call) {
+ const auto *const base_object = (const UHDM::BaseClass *)handle->object;
+ const auto *const fcall = base_object->Cast<const UHDM::func_call *>();
+ if (fcall->Function()) {
+ auto fname = fcall->Function()->VpiFullName();
+ if (fname.find("::") != std::string_view::npos) {
+ current_node->str = fname;
+ sanitize_symbol_name(current_node->str);
+ }
+ }
}
}
@@ -4814,7 +4789,7 @@
void UhdmAst::process_parameter()
{
auto type = vpi_get(vpiLocalParam, obj_h) == 1 ? AST::AST_LOCALPARAM : AST::AST_PARAMETER;
- current_node = make_ast_node(type, {}, true);
+ current_node = make_ast_node(type);
std::vector<AST::AstNode *> packed_ranges; // comes before wire name
std::vector<AST::AstNode *> unpacked_ranges; // comes after wire name
visit_one_to_many({vpiRange}, obj_h, [&](AST::AstNode *node) { unpacked_ranges.push_back(node); });
@@ -5092,7 +5067,8 @@
const uhdm_handle *const handle = (const uhdm_handle *)obj_h;
const UHDM::BaseClass *const object = (const UHDM::BaseClass *)handle->object;
for (auto *obj : shared.nonSynthesizableObjects) {
- if (!object->Compare(obj)) {
+ UHDM::CompareContext ctx;
+ if (!object->Compare(obj, &ctx)) {
log_warning("%.*s:%d: Skipping non-synthesizable object of type '%s'\n", (int)object->VpiFile().length(), object->VpiFile().data(),
object->VpiLineNo(), UHDM::VpiTypeName(obj_h).c_str());
return nullptr;
diff --git a/systemverilog-plugin/UhdmAst.h b/systemverilog-plugin/UhdmAst.h
index bf2d1b5..d60e827 100644
--- a/systemverilog-plugin/UhdmAst.h
+++ b/systemverilog-plugin/UhdmAst.h
@@ -39,12 +39,12 @@
// Reads location info (start/end line/column numbers, file name) from `obj_h` and sets them on `target_node`.
void apply_location_from_current_obj(::Yosys::AST::AstNode &target_node) const;
// Reads object name from `obj_h` and assigns it to `target_node`.
- void apply_name_from_current_obj(::Yosys::AST::AstNode &target_node, bool prefer_full_name = false) const;
+ void apply_name_from_current_obj(::Yosys::AST::AstNode &target_node) const;
// Creates node of specified `type` with location properties read from `obj_h`.
AstNodeBuilder make_node(::Yosys::AST::AstNodeType type) const;
// Creates node of specified `type` with location properties and name read from `obj_h`.
- AstNodeBuilder make_named_node(::Yosys::AST::AstNodeType type, bool prefer_full_name = false) const;
+ AstNodeBuilder make_named_node(::Yosys::AST::AstNodeType type) const;
// Creates AST_IDENTIFIER node with specified `id` and location properties read from `obj_h`.
AstNodeBuilder make_ident(std::string id) const;
// Creates signed AST_CONSTANT node with specified `value` and location properties read from `obj_h`.
@@ -55,8 +55,7 @@
// Create an AstNode of the specified type with metadata extracted from
// the given vpiHandle.
// OBSOLETE: use `make_node` or `make_named_node` instead.
- ::Yosys::AST::AstNode *make_ast_node(::Yosys::AST::AstNodeType type, std::vector<::Yosys::AST::AstNode *> children = {},
- bool prefer_full_name = false);
+ ::Yosys::AST::AstNode *make_ast_node(::Yosys::AST::AstNodeType type, std::vector<::Yosys::AST::AstNode *> children = {});
// Create an identifier AstNode
// OBSOLETE: use `make_ident` instead.
diff --git a/systemverilog-plugin/uhdmastshared.h b/systemverilog-plugin/uhdmastshared.h
index a25acf3..ef4ea04 100644
--- a/systemverilog-plugin/uhdmastshared.h
+++ b/systemverilog-plugin/uhdmastshared.h
@@ -88,11 +88,15 @@
::Yosys::AST::AstNode *current_top_node = nullptr;
+ // Currently processed UHDM module instance.
+ // Used as a fallback when obj->Instance() and obj->vpiParent() are not available.
+ const UHDM::any *current_instance = nullptr;
+
// Set of non-synthesizable objects to skip in current design;
std::set<const UHDM::BaseClass *> nonSynthesizableObjects;
// Map of anonymous enum types to generated typedefs
- std::unordered_map<const UHDM::enum_typespec *, std::string> anonymous_enums;
+ std::unordered_map<std::string, std::unordered_map<const UHDM::enum_typespec *, std::string>> anonymous_enums;
};
} // namespace systemverilog_plugin
diff --git a/systemverilog-plugin/uhdmsurelogastfrontend.cc b/systemverilog-plugin/uhdmsurelogastfrontend.cc
index 86ddc78..2d03e6f 100644
--- a/systemverilog-plugin/uhdmsurelogastfrontend.cc
+++ b/systemverilog-plugin/uhdmsurelogastfrontend.cc
@@ -180,6 +180,7 @@
} else {
clp->setCompile(true);
clp->setElaborate(true);
+ clp->setElabUhdm(true);
}
if (this->shared.link) {
clp->setLink(true);