Skip to content

Commit e648e9a

Browse files
committed
systemverilog-plugin: add parameter type propagation through hierarchy
1 parent e0a923c commit e648e9a

File tree

3 files changed

+167
-6
lines changed

3 files changed

+167
-6
lines changed

systemverilog-plugin/UhdmAst.cc

Lines changed: 160 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,36 @@ static void visitEachDescendant(AST::AstNode *node, const std::function<void(AST
188188
}
189189
}
190190

191+
static void visitEachDescendantIdentifier(AST::AstNode *node, std::unordered_set<std::string> &identifiers, const std::function<void(AST::AstNode *, std::unordered_set<std::string> &)> &f)
192+
{
193+
for (auto child : node->children) {
194+
f(child, identifiers);
195+
visitEachDescendantIdentifier(child, identifiers, f);
196+
}
197+
}
198+
199+
static void check_range_for_identifier(AST::AstNode *node, std::unordered_set<std::string> &identifiers)
200+
{
201+
if (node->attributes.count(UhdmAst::packed_ranges())) {
202+
for (auto r : node->attributes[UhdmAst::packed_ranges()]->children) {
203+
visitEachDescendantIdentifier(r, identifiers, [](AST::AstNode *node, std::unordered_set<std::string> &identifiers) {
204+
if (node->type == AST::AST_IDENTIFIER) {
205+
identifiers.insert(node->str);
206+
}
207+
});
208+
}
209+
}
210+
if (node->attributes.count(UhdmAst::unpacked_ranges())) {
211+
for (auto r : node->attributes[UhdmAst::unpacked_ranges()]->children) {
212+
visitEachDescendantIdentifier(r, identifiers, [](AST::AstNode *node, std::unordered_set<std::string> &identifiers) {
213+
if (node->type == AST::AST_IDENTIFIER) {
214+
identifiers.insert(node->str);
215+
}
216+
});
217+
}
218+
}
219+
}
220+
191221
static void add_multirange_wire(AST::AstNode *node, std::vector<AST::AstNode *> packed_ranges, std::vector<AST::AstNode *> unpacked_ranges,
192222
bool reverse = true)
193223
{
@@ -345,10 +375,14 @@ static void resolve_wiretype(AST::AstNode *wire_node)
345375
AST::AstNode *wiretype_ast = nullptr;
346376
log_assert(AST_INTERNAL::current_scope.count(wiretype_node->str));
347377
wiretype_ast = AST_INTERNAL::current_scope[wiretype_node->str];
378+
379+
auto wiretype_ast_clone = wiretype_ast->clone();
348380
// we need to setup current top ast as this simplify
349381
// needs to have access to all already defined ids
350-
while (wire_node->simplify(true, false, false, 1, -1, false, false)) {
351-
}
382+
while (wire_node->simplify(true, false, false, 1, -1, false, false)) {}
383+
// retain original type if type is reused multiple times as yosys will simplify it to a unusable type later or set even a nullptr
384+
AST_INTERNAL::current_scope[wiretype_ast_clone->str] = wiretype_ast_clone;
385+
352386
if (wiretype_ast->children[0]->type == AST::AST_STRUCT && wire_node->type == AST::AST_WIRE) {
353387
auto struct_width = get_max_offset_struct(wiretype_ast->children[0]);
354388
wire_node->range_left = struct_width;
@@ -767,6 +801,10 @@ static void setup_current_scope(std::unordered_map<std::string, AST::AstNode *>
767801
}
768802
for (auto &o : current_top_node->children) {
769803
if (o->type == AST::AST_TYPEDEF || o->type == AST::AST_PARAMETER || o->type == AST::AST_LOCALPARAM) {
804+
// debatable if needed :-)
805+
// if (AST_INTERNAL::current_scope.count(o->str)) {
806+
// log_warning("multiple typedefs for %s, %d, %d\n", o->str.c_str(), o->type, AST_INTERNAL::current_scope[o->str]->type);
807+
// }
770808
AST_INTERNAL::current_scope[o->str] = o;
771809
} else if (o->type == AST::AST_ENUM) {
772810
AST_INTERNAL::current_scope[o->str] = o;
@@ -1193,6 +1231,24 @@ void UhdmAst::visit_one_to_one(const std::vector<int> child_node_types, vpiHandl
11931231
}
11941232
}
11951233

1234+
void UhdmAst::visit_one_to_two_levels(int child_node_type_level1, const std::vector<int> child_node_types, vpiHandle parent_handle, const std::function<void(AST::AstNode *)> &f)
1235+
{
1236+
vpiHandle first_level = vpi_iterate(child_node_type_level1, parent_handle);
1237+
while (vpiHandle vpi_child_obj = vpi_scan(first_level)) {
1238+
for (auto child : child_node_types) {
1239+
vpiHandle itr = vpi_handle(child, vpi_child_obj);
1240+
if (itr) {
1241+
UhdmAst uhdm_ast(this, shared, indent + " ");
1242+
auto *child_node = uhdm_ast.process_object(itr);
1243+
f(child_node);
1244+
}
1245+
vpi_release_handle(itr);
1246+
}
1247+
vpi_release_handle(vpi_child_obj);
1248+
}
1249+
vpi_release_handle(first_level);
1250+
}
1251+
11961252
void UhdmAst::visit_range(vpiHandle obj_h, const std::function<void(AST::AstNode *)> &f)
11971253
{
11981254
std::vector<AST::AstNode *> range_nodes;
@@ -1690,15 +1746,35 @@ void UhdmAst::move_type_to_new_typedef(AST::AstNode *current_node, AST::AstNode
16901746
typedef_node->location = type_node->location;
16911747
typedef_node->filename = type_node->filename;
16921748
typedef_node->str = strip_package_name(type_node->str);
1749+
bool isReplace = false;
1750+
AST::AstNode *replaceNode = nullptr;
16931751
for (auto c : current_node->children) {
16941752
if (c->str == typedef_node->str) {
1695-
return;
1753+
log_assert(c->children[0]);
1754+
if (c->children[0]->type < type_node->type) {
1755+
if (type_node->type == AST::AST_ENUM && type_node->attributes.count("\\enum_base_type") == 0) {
1756+
// redefine enum we can skip
1757+
return;
1758+
}
1759+
// replace type used for parameter propagation
1760+
isReplace = true;
1761+
replaceNode = c;
1762+
log_experimental("Info: will be replacing type %s, %d, new %d\n", c->str.c_str(), c->children[c->children.size() - 1]->type, type_node->type);
1763+
continue;
1764+
} else {
1765+
// assume it the same, maybe add warning for type parameter propagation through hierarchy
1766+
return;
1767+
}
16961768
}
16971769
}
16981770
if (type_node->type == AST::AST_STRUCT) {
16991771
type_node->str.clear();
17001772
typedef_node->children.push_back(type_node);
1701-
current_node->children.push_back(typedef_node);
1773+
if (isReplace) {
1774+
*replaceNode = *typedef_node;
1775+
} else {
1776+
current_node->children.push_back(typedef_node);
1777+
}
17021778
} else if (type_node->type == AST::AST_ENUM) {
17031779
if (type_node->attributes.count("\\enum_base_type")) {
17041780
auto base_type = type_node->attributes["\\enum_base_type"];
@@ -1718,7 +1794,11 @@ void UhdmAst::move_type_to_new_typedef(AST::AstNode *current_node, AST::AstNode
17181794
wire_node->attributes[enum_item_str.c_str()] = AST::AstNode::mkconst_str(c->str);
17191795
}
17201796
typedef_node->children.push_back(wire_node);
1721-
current_node->children.push_back(typedef_node);
1797+
if (isReplace) {
1798+
*replaceNode = *typedef_node;
1799+
} else {
1800+
current_node->children.push_back(typedef_node);
1801+
}
17221802
delete type_node;
17231803
} else {
17241804
type_node->str = "$enum" + std::to_string(shared.next_enum_id());
@@ -1738,7 +1818,11 @@ void UhdmAst::move_type_to_new_typedef(AST::AstNode *current_node, AST::AstNode
17381818
} else {
17391819
type_node->str.clear();
17401820
typedef_node->children.push_back(type_node);
1741-
current_node->children.push_back(typedef_node);
1821+
if (isReplace) {
1822+
*replaceNode = *typedef_node;
1823+
} else {
1824+
current_node->children.push_back(typedef_node);
1825+
}
17421826
}
17431827
}
17441828

@@ -1918,6 +2002,12 @@ void UhdmAst::process_module()
19182002
delete node;
19192003
}
19202004
});
2005+
// adding type parameter name to instantiated module name
2006+
visit_one_to_two_levels(vpiParameter, {vpiTypespec}, obj_h, [&](AST::AstNode *node) {
2007+
if (node) {
2008+
parameters.push_back(std::make_pair(node->str, RTLIL::Const::from_string(node->str)));
2009+
}
2010+
});
19212011
// We need to rename module to prevent name collision with the same module, but with different parameters
19222012
std::string module_name = !parameters.empty() ? AST::derived_module_name(type, parameters).c_str() : type;
19232013
auto module_node = shared.top_nodes[module_name];
@@ -1972,6 +2062,56 @@ void UhdmAst::process_module()
19722062
current_node->children.insert(current_node->children.begin(), typeNode);
19732063
auto old_top = shared.current_top_node;
19742064
shared.current_top_node = module_node;
2065+
shared.elaborated_nodes.push_back(old_top);
2066+
2067+
std::unordered_set<std::string> visited_identifiers;
2068+
visitEachDescendant(module_node, [&](AST::AstNode *current_scope_node) {
2069+
check_range_for_identifier(current_scope_node, visited_identifiers);
2070+
});
2071+
2072+
visit_one_to_two_levels(vpiParameter, {vpiTypespec}, obj_h, [&](AST::AstNode *node) {
2073+
if (node && node->str.size()) {
2074+
move_type_to_new_typedef(module_node, node);
2075+
}
2076+
});
2077+
2078+
// vpiVariables need to be checked after vpiParameter as they are processed in that order and pointers are swapped in surelog
2079+
visit_one_to_two_levels(vpiVariables, {vpiTypespec}, obj_h, [&](AST::AstNode *node) {
2080+
if (node && node->str.size()) {
2081+
move_type_to_new_typedef(module_node, node);
2082+
}
2083+
});
2084+
2085+
visitEachDescendant(module_node, [&](AST::AstNode *current_scope_node) {
2086+
check_range_for_identifier(current_scope_node, visited_identifiers);
2087+
});
2088+
2089+
visitEachDescendant(module_node, [&](AST::AstNode *current_scope_node) {
2090+
if (visited_identifiers.count(current_scope_node->str) > 0) {
2091+
// identifier is already defined in this scope does not need to be copied
2092+
visited_identifiers.erase(current_scope_node->str);
2093+
}
2094+
});
2095+
2096+
if (visited_identifiers.size() > 0){
2097+
// couldn't copy all identifiers copied
2098+
for (int i = shared.elaborated_nodes.size() - 1; i >= 0; i--) {
2099+
// trying to copy from elaborated nodes before hand
2100+
auto parent_of_parent = shared.elaborated_nodes.at(i);
2101+
visitEachDescendant(parent_of_parent, [&](AST::AstNode *current_scope_node) {
2102+
if (visited_identifiers.count(current_scope_node->str) > 0) {
2103+
// copy identifier and replace
2104+
visited_identifiers.erase(current_scope_node->str);
2105+
add_or_replace_child(module_node, current_scope_node->clone());
2106+
}
2107+
});
2108+
if (visited_identifiers.size() == 0) {
2109+
break;
2110+
}
2111+
}
2112+
}
2113+
log_assert(visited_identifiers.size() == 0);
2114+
19752115
visit_one_to_many({vpiVariables, vpiNet, vpiArrayNet, vpiInterface, vpiModule, vpiPort, vpiGenScopeArray, vpiContAssign, vpiTaskFunc}, obj_h,
19762116
[&](AST::AstNode *node) {
19772117
if (node) {
@@ -1980,6 +2120,7 @@ void UhdmAst::process_module()
19802120
});
19812121
make_cell(obj_h, current_node, module_node);
19822122
shared.current_top_node = old_top;
2123+
shared.elaborated_nodes.pop_back();
19832124
}
19842125
}
19852126

@@ -4415,6 +4556,16 @@ void UhdmAst::process_unsupported_stmt(const UHDM::BaseClass *object, bool is_er
44154556
log_func("%sCurrently not supported object of type '%s'\n", prefix.c_str(), UHDM::VpiTypeName(obj_h).c_str());
44164557
}
44174558

4559+
void UhdmAst::process_type_parameter()
4560+
{
4561+
visit_one_to_one({vpiTypespec}, obj_h, [&](AST::AstNode *node) {
4562+
if (node) {
4563+
current_node = make_ast_node(AST::AST_TYPEDEF);
4564+
current_node->children.push_back(node);
4565+
}
4566+
});
4567+
}
4568+
44184569
AST::AstNode *UhdmAst::process_object(vpiHandle obj_handle)
44194570
{
44204571
obj_h = obj_handle;
@@ -4687,6 +4838,9 @@ AST::AstNode *UhdmAst::process_object(vpiHandle obj_handle)
46874838
process_unsupported_stmt(object);
46884839
break;
46894840
case vpiTypeParameter:
4841+
// for type parameter propagation we need to instantiate a base type (often logic)
4842+
// that will be replaced later
4843+
process_type_parameter();
46904844
// Instances in an `uhdmTopModules` tree already have all parameter references
46914845
// substituted with the parameter type/value by Surelog,
46924846
// so the plugin doesn't need to process the parameter itself.

systemverilog-plugin/UhdmAst.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ class UhdmAst
2424
// ChildrenNodeTypes that are present in the given object.
2525
void visit_one_to_one(const std::vector<int> child_node_types, vpiHandle parent_handle, const std::function<void(::Yosys::AST::AstNode *)> &f);
2626

27+
// Walks through two-level relationships from given parent
28+
// mainly used for type parameter propagation
29+
void visit_one_to_two_levels(int child_node_type_level1, const std::vector<int> child_node_types, vpiHandle parent_handle, const std::function<void(::Yosys::AST::AstNode *)> &f);
30+
2731
// Visit children of type vpiRange that belong to the given parent node.
2832
void visit_range(vpiHandle obj_h, const std::function<void(::Yosys::AST::AstNode *)> &f);
2933

@@ -152,6 +156,7 @@ class UhdmAst
152156
void process_primterm();
153157
void simplify_parameter(::Yosys::AST::AstNode *parameter, ::Yosys::AST::AstNode *module_node = nullptr);
154158
void process_unsupported_stmt(const UHDM::BaseClass *object, bool is_error = true);
159+
void process_type_parameter();
155160

156161
UhdmAst(UhdmAst *p, UhdmAstShared &s, const std::string &i) : parent(p), shared(s), indent(i)
157162
{

systemverilog-plugin/uhdmastshared.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ class UhdmAstShared
6666
std::unordered_map<std::string, ::Yosys::AST::AstNode *> param_types;
6767

6868
::Yosys::AST::AstNode *current_top_node = nullptr;
69+
70+
std::vector<::Yosys::AST::AstNode *> elaborated_nodes;
6971
// Set of non-synthesizable objects to skip in current design;
7072
std::set<const UHDM::BaseClass *> nonSynthesizableObjects;
7173
};

0 commit comments

Comments
 (0)