@@ -109,18 +109,108 @@ static std::string remove_spaces(std::string str)
109109 return str;
110110}
111111
112+ void FstData::registerVar (const FstVar &var)
113+ {
114+ vars.push_back (var);
115+ if (!var.is_alias )
116+ handle_to_var[var.id ] = var;
117+
118+ std::string clean_name = var.name ;
119+ if (!clean_name.empty () && clean_name[0 ] == ' \\ ' )
120+ clean_name = clean_name.substr (1 );
121+
122+ // Strip trailing bit range [N:M] if present
123+ if (!clean_name.empty () && clean_name.back () == ' ]' ) {
124+ size_t open = clean_name.rfind (' [' );
125+ if (open != std::string::npos) {
126+ std::string inner = clean_name.substr (open + 1 , clean_name.size () - open - 2 );
127+ if (inner.find (' :' ) != std::string::npos)
128+ clean_name.erase (open);
129+ }
130+ }
131+
132+ // Handle memory addresses
133+ size_t pos = clean_name.find_last_of (" <" );
134+ if (pos != std::string::npos && clean_name.back () == ' >' ) {
135+ std::string mem_cell = clean_name.substr (0 , pos);
136+ normalize_brackets (mem_cell);
137+ std::string addr = clean_name.substr (pos+1 );
138+ addr.pop_back (); // remove closing bracket
139+ char *endptr;
140+ int mem_addr = strtol (addr.c_str (), &endptr, 16 );
141+ if (*endptr) {
142+ log_debug (" Error parsing memory address in : %s\n " , clean_name);
143+ } else {
144+ memory_to_handle[var.scope +" ." +mem_cell][mem_addr] = var.id ;
145+ }
146+ }
147+ pos = clean_name.find_last_of (" [" );
148+ if (pos != std::string::npos && clean_name.back () == ' ]' ) {
149+ std::string mem_cell = clean_name.substr (0 , pos);
150+ normalize_brackets (mem_cell);
151+ std::string addr = clean_name.substr (pos+1 );
152+ addr.pop_back (); // remove closing bracket
153+ char *endptr;
154+ int mem_addr = strtol (addr.c_str (), &endptr, 10 );
155+ if (*endptr) {
156+ log_debug (" Error parsing memory address in : %s\n " , clean_name);
157+ } else {
158+ memory_to_handle[var.scope +" ." +mem_cell][mem_addr] = var.id ;
159+ }
160+ }
161+ normalize_brackets (clean_name);
162+ name_to_handle[var.scope +" ." +clean_name] = var.id ;
163+ }
164+
112165void FstData::extractVarNames ()
113166{
114167 struct fstHier *h;
115168 std::string fst_scope_name;
116169
170+ /* Variables for resolving unions with $fork. */
171+ bool in_fork = false ; // if we are inside a $fork scope
172+ std::string fork_parent_scope; // parent scope of fork (used to resolve union location)
173+ std::string fork_name; // name of fork (used to resolve union name)
174+ std::vector<FstVar> fork_vars; // stores all variables in the fork scope
175+
117176 while ((h = fstReaderIterateHier (ctx))) {
118177 switch (h->htyp ) {
119178 case FST_HT_SCOPE : {
179+ // Handle tracking for potential union structs with $fork.
180+ if (!in_fork && h->u .scope .typ == FST_ST_VCD_FORK ) {
181+ in_fork = true ;
182+ fork_parent_scope = fst_scope_name;
183+ fork_name = h->u .scope .name ;
184+ fork_vars.clear ();
185+ }
186+ // Push the scope onto the stack to 'descend' into the hierarchy.
120187 fst_scope_name = fstReaderPushScope (ctx, h->u .scope .name , NULL );
121188 break ;
122189 }
123190 case FST_HT_UPSCOPE : {
191+ if (in_fork) {
192+ // A union is detected if there are at least 2 variables in the fork scope and they all have the same fstHandle.
193+ bool is_union = fork_vars.size () >= 2 &&
194+ std::all_of (fork_vars.begin () + 1 , fork_vars.end (),
195+ [&](const FstVar &v) { return v.id == fork_vars[0 ].id ; });
196+ if (is_union) {
197+ // If a union, register the fork name as the variable at the parent scope.
198+ FstVar u = fork_vars[0 ];
199+ u.name = fork_name;
200+ u.scope = fork_parent_scope;
201+ normalize_brackets (u.scope );
202+ u.is_alias = false ;
203+ registerVar (u);
204+ } else {
205+ // If not a union, register all variables in the fork scope as normal.
206+ for (auto &v : fork_vars) {
207+ registerVar (v);
208+ }
209+ }
210+ in_fork = false ;
211+ fork_vars.clear ();
212+ }
213+ // Pop the scope off the stack.
124214 fst_scope_name = fstReaderPopScope (ctx);
125215 break ;
126216 }
@@ -133,62 +223,15 @@ void FstData::extractVarNames()
133223 var.scope = fst_scope_name;
134224 normalize_brackets (var.scope );
135225 var.width = h->u .var .length ;
136- vars.push_back (var);
137- if (!var.is_alias )
138- handle_to_var[h->u .var .handle ] = var;
139-
140- std::string clean_name = var.name ;
141- if (!clean_name.empty () && clean_name[0 ] == ' \\ ' )
142- clean_name = clean_name.substr (1 );
143-
144- // Strip trailing bit range [N:M] if present
145- if (!clean_name.empty () && clean_name.back () == ' ]' ) {
146- size_t open = clean_name.rfind (' [' );
147- if (open != std::string::npos) {
148- std::string inner = clean_name.substr (open + 1 , clean_name.size () - open - 2 );
149- if (inner.find (' :' ) != std::string::npos)
150- clean_name.erase (open);
151- }
152- }
153226
154- // Handle memory addresses
155- size_t pos = clean_name.find_last_of (" <" );
156- if (pos != std::string::npos && clean_name.back () == ' >' ) {
157- std::string mem_cell = clean_name.substr (0 , pos);
158- normalize_brackets (mem_cell);
159- std::string addr = clean_name.substr (pos+1 );
160- addr.pop_back (); // remove closing bracket
161- char *endptr;
162- int mem_addr = strtol (addr.c_str (), &endptr, 16 );
163- if (*endptr) {
164- log_debug (" Error parsing memory address in : %s\n " , clean_name);
165- } else {
166- memory_to_handle[var.scope +" ." +mem_cell][mem_addr] = var.id ;
167- }
168- }
169- pos = clean_name.find_last_of (" [" );
170- if (pos != std::string::npos && clean_name.back () == ' ]' ) {
171- std::string mem_cell = clean_name.substr (0 , pos);
172- normalize_brackets (mem_cell);
173- std::string addr = clean_name.substr (pos+1 );
174- addr.pop_back (); // remove closing bracket
175- char *endptr;
176- int mem_addr = strtol (addr.c_str (), &endptr, 10 );
177- if (*endptr) {
178- log_debug (" Error parsing memory address in : %s\n " , clean_name);
179- } else {
180- memory_to_handle[var.scope +" ." +mem_cell][mem_addr] = var.id ;
181- }
182- }
183- normalize_brackets (clean_name);
184- name_to_handle[var.scope +" ." +clean_name] = h->u .var .handle ;
227+ if (in_fork) fork_vars.push_back (var); // store all variables in fork scope into a vector
228+ else registerVar (var); // otherwise, register the variable as normal
185229 break ;
186230 }
187231 }
188232 }
189233}
190234
191-
192235static void reconstruct_clb_varlen_attimes (void *user_data, uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t plen)
193236{
194237 FstData *ptr = (FstData*)user_data;
0 commit comments