@@ -188,6 +188,37 @@ static void visitEachDescendant(AST::AstNode *node, const std::function<void(AST
188
188
}
189
189
}
190
190
191
+ static void visitEachDescendantIdentifier (AST::AstNode *node, std::unordered_set<std::string> &identifiers,
192
+ const std::function<void (AST::AstNode *, std::unordered_set<std::string> &)> &f)
193
+ {
194
+ for (auto child : node->children ) {
195
+ f (child, identifiers);
196
+ visitEachDescendantIdentifier (child, identifiers, f);
197
+ }
198
+ }
199
+
200
+ static void check_range_for_identifier (AST::AstNode *node, std::unordered_set<std::string> &identifiers)
201
+ {
202
+ if (node->attributes .count (UhdmAst::packed_ranges ())) {
203
+ for (auto r : node->attributes [UhdmAst::packed_ranges ()]->children ) {
204
+ visitEachDescendantIdentifier (r, identifiers, [](AST::AstNode *node, std::unordered_set<std::string> &identifiers) {
205
+ if (node->type == AST::AST_IDENTIFIER) {
206
+ identifiers.insert (node->str );
207
+ }
208
+ });
209
+ }
210
+ }
211
+ if (node->attributes .count (UhdmAst::unpacked_ranges ())) {
212
+ for (auto r : node->attributes [UhdmAst::unpacked_ranges ()]->children ) {
213
+ visitEachDescendantIdentifier (r, identifiers, [](AST::AstNode *node, std::unordered_set<std::string> &identifiers) {
214
+ if (node->type == AST::AST_IDENTIFIER) {
215
+ identifiers.insert (node->str );
216
+ }
217
+ });
218
+ }
219
+ }
220
+ }
221
+
191
222
static void add_multirange_wire (AST::AstNode *node, std::vector<AST::AstNode *> packed_ranges, std::vector<AST::AstNode *> unpacked_ranges,
192
223
bool reverse = true )
193
224
{
@@ -345,10 +376,15 @@ static void resolve_wiretype(AST::AstNode *wire_node)
345
376
AST::AstNode *wiretype_ast = nullptr ;
346
377
log_assert (AST_INTERNAL::current_scope.count (wiretype_node->str ));
347
378
wiretype_ast = AST_INTERNAL::current_scope[wiretype_node->str ];
379
+
380
+ auto wiretype_ast_clone = wiretype_ast->clone ();
348
381
// we need to setup current top ast as this simplify
349
382
// needs to have access to all already defined ids
350
383
while (wire_node->simplify (true , false , false , 1 , -1 , false , false )) {
351
384
}
385
+ // retain original type if type is reused multiple times as yosys will simplify it to a unusable type later or set even a nullptr
386
+ AST_INTERNAL::current_scope[wiretype_ast_clone->str ] = wiretype_ast_clone;
387
+
352
388
if (wiretype_ast->children [0 ]->type == AST::AST_STRUCT && wire_node->type == AST::AST_WIRE) {
353
389
auto struct_width = get_max_offset_struct (wiretype_ast->children [0 ]);
354
390
wire_node->range_left = struct_width;
@@ -767,6 +803,10 @@ static void setup_current_scope(std::unordered_map<std::string, AST::AstNode *>
767
803
}
768
804
for (auto &o : current_top_node->children ) {
769
805
if (o->type == AST::AST_TYPEDEF || o->type == AST::AST_PARAMETER || o->type == AST::AST_LOCALPARAM) {
806
+ // debatable if needed :-)
807
+ // if (AST_INTERNAL::current_scope.count(o->str)) {
808
+ // log_warning("multiple typedefs for %s, %d, %d\n", o->str.c_str(), o->type, AST_INTERNAL::current_scope[o->str]->type);
809
+ // }
770
810
AST_INTERNAL::current_scope[o->str ] = o;
771
811
} else if (o->type == AST::AST_ENUM) {
772
812
AST_INTERNAL::current_scope[o->str ] = o;
@@ -1193,6 +1233,25 @@ void UhdmAst::visit_one_to_one(const std::vector<int> child_node_types, vpiHandl
1193
1233
}
1194
1234
}
1195
1235
1236
+ void UhdmAst::visit_one_to_two_levels (int child_node_type_level1, const std::vector<int > child_node_types, vpiHandle parent_handle,
1237
+ const std::function<void (AST::AstNode *)> &f)
1238
+ {
1239
+ vpiHandle first_level = vpi_iterate (child_node_type_level1, parent_handle);
1240
+ while (vpiHandle vpi_child_obj = vpi_scan (first_level)) {
1241
+ for (auto child : child_node_types) {
1242
+ vpiHandle itr = vpi_handle (child, vpi_child_obj);
1243
+ if (itr) {
1244
+ UhdmAst uhdm_ast (this , shared, indent + " " );
1245
+ auto *child_node = uhdm_ast.process_object (itr);
1246
+ f (child_node);
1247
+ }
1248
+ vpi_release_handle (itr);
1249
+ }
1250
+ vpi_release_handle (vpi_child_obj);
1251
+ }
1252
+ vpi_release_handle (first_level);
1253
+ }
1254
+
1196
1255
void UhdmAst::visit_range (vpiHandle obj_h, const std::function<void (AST::AstNode *)> &f)
1197
1256
{
1198
1257
std::vector<AST::AstNode *> range_nodes;
@@ -1690,15 +1749,36 @@ void UhdmAst::move_type_to_new_typedef(AST::AstNode *current_node, AST::AstNode
1690
1749
typedef_node->location = type_node->location ;
1691
1750
typedef_node->filename = type_node->filename ;
1692
1751
typedef_node->str = strip_package_name (type_node->str );
1752
+ bool isReplace = false ;
1753
+ AST::AstNode *replaceNode = nullptr ;
1693
1754
for (auto c : current_node->children ) {
1694
1755
if (c->str == typedef_node->str ) {
1695
- return ;
1756
+ log_assert (c->children [0 ]);
1757
+ if (c->children [0 ]->type < type_node->type ) {
1758
+ if (type_node->type == AST::AST_ENUM && type_node->attributes .count (" \\ enum_base_type" ) == 0 ) {
1759
+ // redefine enum we can skip
1760
+ return ;
1761
+ }
1762
+ // replace type used for parameter propagation
1763
+ isReplace = true ;
1764
+ replaceNode = c;
1765
+ log_experimental (" Info: will be replacing type %s, %d, new %d\n " , c->str .c_str (), c->children [c->children .size () - 1 ]->type ,
1766
+ type_node->type );
1767
+ continue ;
1768
+ } else {
1769
+ // assume it the same, maybe add warning for type parameter propagation through hierarchy
1770
+ return ;
1771
+ }
1696
1772
}
1697
1773
}
1698
1774
if (type_node->type == AST::AST_STRUCT) {
1699
1775
type_node->str .clear ();
1700
1776
typedef_node->children .push_back (type_node);
1701
- current_node->children .push_back (typedef_node);
1777
+ if (isReplace) {
1778
+ *replaceNode = *typedef_node;
1779
+ } else {
1780
+ current_node->children .push_back (typedef_node);
1781
+ }
1702
1782
} else if (type_node->type == AST::AST_ENUM) {
1703
1783
if (type_node->attributes .count (" \\ enum_base_type" )) {
1704
1784
auto base_type = type_node->attributes [" \\ enum_base_type" ];
@@ -1718,7 +1798,11 @@ void UhdmAst::move_type_to_new_typedef(AST::AstNode *current_node, AST::AstNode
1718
1798
wire_node->attributes [enum_item_str.c_str ()] = AST::AstNode::mkconst_str (c->str );
1719
1799
}
1720
1800
typedef_node->children .push_back (wire_node);
1721
- current_node->children .push_back (typedef_node);
1801
+ if (isReplace) {
1802
+ *replaceNode = *typedef_node;
1803
+ } else {
1804
+ current_node->children .push_back (typedef_node);
1805
+ }
1722
1806
delete type_node;
1723
1807
} else {
1724
1808
type_node->str = " $enum" + std::to_string (shared.next_enum_id ());
@@ -1738,7 +1822,11 @@ void UhdmAst::move_type_to_new_typedef(AST::AstNode *current_node, AST::AstNode
1738
1822
} else {
1739
1823
type_node->str .clear ();
1740
1824
typedef_node->children .push_back (type_node);
1741
- current_node->children .push_back (typedef_node);
1825
+ if (isReplace) {
1826
+ *replaceNode = *typedef_node;
1827
+ } else {
1828
+ current_node->children .push_back (typedef_node);
1829
+ }
1742
1830
}
1743
1831
}
1744
1832
@@ -1918,6 +2006,12 @@ void UhdmAst::process_module()
1918
2006
delete node;
1919
2007
}
1920
2008
});
2009
+ // adding type parameter name to instantiated module name
2010
+ visit_one_to_two_levels (vpiParameter, {vpiTypespec}, obj_h, [&](AST::AstNode *node) {
2011
+ if (node) {
2012
+ parameters.push_back (std::make_pair (node->str , RTLIL::Const::from_string (node->str )));
2013
+ }
2014
+ });
1921
2015
// We need to rename module to prevent name collision with the same module, but with different parameters
1922
2016
std::string module_name = !parameters.empty () ? AST::derived_module_name (type, parameters).c_str () : type;
1923
2017
auto module_node = shared.top_nodes [module_name];
@@ -1972,6 +2066,54 @@ void UhdmAst::process_module()
1972
2066
current_node->children .insert (current_node->children .begin (), typeNode);
1973
2067
auto old_top = shared.current_top_node ;
1974
2068
shared.current_top_node = module_node;
2069
+ shared.elaborated_nodes .push_back (old_top);
2070
+
2071
+ std::unordered_set<std::string> visited_identifiers;
2072
+ visitEachDescendant (module_node,
2073
+ [&](AST::AstNode *current_scope_node) { check_range_for_identifier (current_scope_node, visited_identifiers); });
2074
+
2075
+ visit_one_to_two_levels (vpiParameter, {vpiTypespec}, obj_h, [&](AST::AstNode *node) {
2076
+ if (node && node->str .size ()) {
2077
+ move_type_to_new_typedef (module_node, node);
2078
+ }
2079
+ });
2080
+
2081
+ // vpiVariables need to be checked after vpiParameter as they are processed in that order and pointers are swapped in surelog
2082
+ visit_one_to_two_levels (vpiVariables, {vpiTypespec}, obj_h, [&](AST::AstNode *node) {
2083
+ if (node && node->str .size ()) {
2084
+ move_type_to_new_typedef (module_node, node);
2085
+ }
2086
+ });
2087
+
2088
+ visitEachDescendant (module_node,
2089
+ [&](AST::AstNode *current_scope_node) { check_range_for_identifier (current_scope_node, visited_identifiers); });
2090
+
2091
+ visitEachDescendant (module_node, [&](AST::AstNode *current_scope_node) {
2092
+ if (visited_identifiers.count (current_scope_node->str ) > 0 ) {
2093
+ // identifier is already defined in this scope does not need to be copied
2094
+ visited_identifiers.erase (current_scope_node->str );
2095
+ }
2096
+ });
2097
+
2098
+ if (visited_identifiers.size () > 0 ) {
2099
+ // couldn't copy all identifiers copied
2100
+ for (int i = shared.elaborated_nodes .size () - 1 ; i >= 0 ; i--) {
2101
+ // trying to copy from elaborated nodes before hand
2102
+ auto parent_of_parent = shared.elaborated_nodes .at (i);
2103
+ visitEachDescendant (parent_of_parent, [&](AST::AstNode *current_scope_node) {
2104
+ if (visited_identifiers.count (current_scope_node->str ) > 0 ) {
2105
+ // copy identifier and replace
2106
+ visited_identifiers.erase (current_scope_node->str );
2107
+ add_or_replace_child (module_node, current_scope_node->clone ());
2108
+ }
2109
+ });
2110
+ if (visited_identifiers.size () == 0 ) {
2111
+ break ;
2112
+ }
2113
+ }
2114
+ }
2115
+ log_assert (visited_identifiers.size () == 0 );
2116
+
1975
2117
visit_one_to_many ({vpiVariables, vpiNet, vpiArrayNet, vpiInterface, vpiModule, vpiPort, vpiGenScopeArray, vpiContAssign, vpiTaskFunc}, obj_h,
1976
2118
[&](AST::AstNode *node) {
1977
2119
if (node) {
@@ -1980,6 +2122,7 @@ void UhdmAst::process_module()
1980
2122
});
1981
2123
make_cell (obj_h, current_node, module_node);
1982
2124
shared.current_top_node = old_top;
2125
+ shared.elaborated_nodes .pop_back ();
1983
2126
}
1984
2127
}
1985
2128
@@ -4415,6 +4558,16 @@ void UhdmAst::process_unsupported_stmt(const UHDM::BaseClass *object, bool is_er
4415
4558
log_func (" %sCurrently not supported object of type '%s'\n " , prefix.c_str (), UHDM::VpiTypeName (obj_h).c_str ());
4416
4559
}
4417
4560
4561
+ void UhdmAst::process_type_parameter ()
4562
+ {
4563
+ visit_one_to_one ({vpiTypespec}, obj_h, [&](AST::AstNode *node) {
4564
+ if (node) {
4565
+ current_node = make_ast_node (AST::AST_TYPEDEF);
4566
+ current_node->children .push_back (node);
4567
+ }
4568
+ });
4569
+ }
4570
+
4418
4571
AST::AstNode *UhdmAst::process_object (vpiHandle obj_handle)
4419
4572
{
4420
4573
obj_h = obj_handle;
@@ -4687,6 +4840,9 @@ AST::AstNode *UhdmAst::process_object(vpiHandle obj_handle)
4687
4840
process_unsupported_stmt (object);
4688
4841
break ;
4689
4842
case vpiTypeParameter:
4843
+ // for type parameter propagation we need to instantiate a base type (often logic)
4844
+ // that will be replaced later
4845
+ process_type_parameter ();
4690
4846
// Instances in an `uhdmTopModules` tree already have all parameter references
4691
4847
// substituted with the parameter type/value by Surelog,
4692
4848
// so the plugin doesn't need to process the parameter itself.
0 commit comments