@@ -188,6 +188,36 @@ 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, 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
+
191
221
static void add_multirange_wire (AST::AstNode *node, std::vector<AST::AstNode *> packed_ranges, std::vector<AST::AstNode *> unpacked_ranges,
192
222
bool reverse = true )
193
223
{
@@ -345,10 +375,14 @@ static void resolve_wiretype(AST::AstNode *wire_node)
345
375
AST::AstNode *wiretype_ast = nullptr ;
346
376
log_assert (AST_INTERNAL::current_scope.count (wiretype_node->str ));
347
377
wiretype_ast = AST_INTERNAL::current_scope[wiretype_node->str ];
378
+
379
+ auto wiretype_ast_clone = wiretype_ast->clone ();
348
380
// we need to setup current top ast as this simplify
349
381
// 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
+
352
386
if (wiretype_ast->children [0 ]->type == AST::AST_STRUCT && wire_node->type == AST::AST_WIRE) {
353
387
auto struct_width = get_max_offset_struct (wiretype_ast->children [0 ]);
354
388
wire_node->range_left = struct_width;
@@ -767,6 +801,10 @@ static void setup_current_scope(std::unordered_map<std::string, AST::AstNode *>
767
801
}
768
802
for (auto &o : current_top_node->children ) {
769
803
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
+ // }
770
808
AST_INTERNAL::current_scope[o->str ] = o;
771
809
} else if (o->type == AST::AST_ENUM) {
772
810
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
1193
1231
}
1194
1232
}
1195
1233
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
+
1196
1252
void UhdmAst::visit_range (vpiHandle obj_h, const std::function<void (AST::AstNode *)> &f)
1197
1253
{
1198
1254
std::vector<AST::AstNode *> range_nodes;
@@ -1690,15 +1746,35 @@ void UhdmAst::move_type_to_new_typedef(AST::AstNode *current_node, AST::AstNode
1690
1746
typedef_node->location = type_node->location ;
1691
1747
typedef_node->filename = type_node->filename ;
1692
1748
typedef_node->str = strip_package_name (type_node->str );
1749
+ bool isReplace = false ;
1750
+ AST::AstNode *replaceNode = nullptr ;
1693
1751
for (auto c : current_node->children ) {
1694
1752
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
+ }
1696
1768
}
1697
1769
}
1698
1770
if (type_node->type == AST::AST_STRUCT) {
1699
1771
type_node->str .clear ();
1700
1772
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
+ }
1702
1778
} else if (type_node->type == AST::AST_ENUM) {
1703
1779
if (type_node->attributes .count (" \\ enum_base_type" )) {
1704
1780
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
1718
1794
wire_node->attributes [enum_item_str.c_str ()] = AST::AstNode::mkconst_str (c->str );
1719
1795
}
1720
1796
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
+ }
1722
1802
delete type_node;
1723
1803
} else {
1724
1804
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
1738
1818
} else {
1739
1819
type_node->str .clear ();
1740
1820
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
+ }
1742
1826
}
1743
1827
}
1744
1828
@@ -1918,6 +2002,12 @@ void UhdmAst::process_module()
1918
2002
delete node;
1919
2003
}
1920
2004
});
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
+ });
1921
2011
// We need to rename module to prevent name collision with the same module, but with different parameters
1922
2012
std::string module_name = !parameters.empty () ? AST::derived_module_name (type, parameters).c_str () : type;
1923
2013
auto module_node = shared.top_nodes [module_name];
@@ -1972,6 +2062,56 @@ void UhdmAst::process_module()
1972
2062
current_node->children .insert (current_node->children .begin (), typeNode);
1973
2063
auto old_top = shared.current_top_node ;
1974
2064
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
+
1975
2115
visit_one_to_many ({vpiVariables, vpiNet, vpiArrayNet, vpiInterface, vpiModule, vpiPort, vpiGenScopeArray, vpiContAssign, vpiTaskFunc}, obj_h,
1976
2116
[&](AST::AstNode *node) {
1977
2117
if (node) {
@@ -1980,6 +2120,7 @@ void UhdmAst::process_module()
1980
2120
});
1981
2121
make_cell (obj_h, current_node, module_node);
1982
2122
shared.current_top_node = old_top;
2123
+ shared.elaborated_nodes .pop_back ();
1983
2124
}
1984
2125
}
1985
2126
@@ -4415,6 +4556,16 @@ void UhdmAst::process_unsupported_stmt(const UHDM::BaseClass *object, bool is_er
4415
4556
log_func (" %sCurrently not supported object of type '%s'\n " , prefix.c_str (), UHDM::VpiTypeName (obj_h).c_str ());
4416
4557
}
4417
4558
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
+
4418
4569
AST::AstNode *UhdmAst::process_object (vpiHandle obj_handle)
4419
4570
{
4420
4571
obj_h = obj_handle;
@@ -4687,6 +4838,9 @@ AST::AstNode *UhdmAst::process_object(vpiHandle obj_handle)
4687
4838
process_unsupported_stmt (object);
4688
4839
break ;
4689
4840
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 ();
4690
4844
// Instances in an `uhdmTopModules` tree already have all parameter references
4691
4845
// substituted with the parameter type/value by Surelog,
4692
4846
// so the plugin doesn't need to process the parameter itself.
0 commit comments