From 5bdc2d34514862ab5aee31f4dd0f2a918658bc0d Mon Sep 17 00:00:00 2001 From: Stan Lee Date: Fri, 27 Feb 2026 10:12:43 -0800 Subject: [PATCH 01/11] working implementation that i will improvee further --- kernel/fstdata.cc | 106 +++++++++++++++++++++++++++++++++++++++++----- kernel/fstdata.h | 3 ++ 2 files changed, 98 insertions(+), 11 deletions(-) diff --git a/kernel/fstdata.cc b/kernel/fstdata.cc index f0f00181c..3e3e8d127 100644 --- a/kernel/fstdata.cc +++ b/kernel/fstdata.cc @@ -114,16 +114,46 @@ void FstData::extractVarNames() struct fstHier *h; std::string fst_scope_name; + // Track current fork scope + std::string current_fork_scope; + fstHandle next_virtual_handle = (fstHandle)-1; // forks get negative handle values for better identification + while ((h = fstReaderIterateHier(ctx))) { switch (h->htyp) { - case FST_HT_SCOPE: { - fst_scope_name = fstReaderPushScope(ctx, h->u.scope.name, NULL); - break; + case FST_HT_SCOPE: { + fst_scope_name = fstReaderPushScope(ctx, h->u.scope.name, NULL); + + // Fork scopes are identified by FST_ST_VCD_FORK + if (h->u.scope.typ == FST_ST_VCD_FORK) { + current_fork_scope = fst_scope_name; + // Create new vector that contains struct members + fork_scopes[current_fork_scope] = std::vector(); } - case FST_HT_UPSCOPE: { - fst_scope_name = fstReaderPopScope(ctx); - break; + break; + } + case FST_HT_UPSCOPE: { + if (!current_fork_scope.empty() && current_fork_scope == fst_scope_name) { + + // Create a virtual handle + fstHandle virtual_handle = next_virtual_handle--; + + // Map the scope to the virtual handle + name_to_handle[current_fork_scope] = virtual_handle; + virtual_to_fork[virtual_handle] = current_fork_scope; + + // Calculate total width of the struct and map it to the virtual handle + int total_width = 0; + for (fstHandle member : fork_scopes[current_fork_scope]) { + if (handle_to_var.find(member) != handle_to_var.end()) { + total_width += handle_to_var[member].width; + } + } + virtual_handle_widths[virtual_handle] = total_width; + current_fork_scope.clear(); } + fst_scope_name = fstReaderPopScope(ctx); + break; + } case FST_HT_VAR: { FstVar var; var.id = h->u.var.handle; @@ -133,10 +163,13 @@ void FstData::extractVarNames() var.scope = fst_scope_name; normalize_brackets(var.scope); var.width = h->u.var.length; - vars.push_back(var); - if (!var.is_alias) - handle_to_var[h->u.var.handle] = var; - std::string clean_name; + vars.push_back(var); + if (!var.is_alias) + handle_to_var[h->u.var.handle] = var; + if (!current_fork_scope.empty()) { + fork_scopes[current_fork_scope].push_back(h->u.var.handle); + } + std::string clean_name; bool has_space = false; for(size_t i=0;iu.var.name);i++) { @@ -275,8 +308,59 @@ void FstData::reconstructAllAtTimes(std::vector &signal, uint64_t sta std::string FstData::valueOf(fstHandle signal) { + // Condition to check if the signal comes from a fork scope + if ((int)signal < 0 && virtual_to_fork.find(signal) != virtual_to_fork.end()) { + std::string fork_scope = virtual_to_fork[signal]; + if (fork_scopes.find(fork_scope) != fork_scopes.end()) { + + // Empty string to store the full struct values + std::string result; + + // Get the members of the fork scope + const std::vector& members = fork_scopes[fork_scope]; + for (auto it = members.rbegin(); it != members.rend(); ++it) { + fstHandle member = *it; + std::string member_val; + int expected_width = 0; + + // Get the width of the member + if (handle_to_var.find(member) != handle_to_var.end()) { + expected_width = handle_to_var[member].width; + } + + // Check if the member has a value + if (past_data.find(member) != past_data.end()) { + member_val = past_data[member]; + + // If the member value is shorter than the expected width, pad with zeros + if (expected_width > 0 && (int)member_val.length() < expected_width) { + member_val = std::string(expected_width - member_val.length(), '0') + member_val; + } + } else if (expected_width > 0) { + // If the member has no value, pad with x's + member_val = std::string(expected_width, 'x'); + } else { + member_val = "x"; + } + + // Add the member value to the result + result += member_val; + } + return result; + } + + // If the fork scope is not found, pad with x's based on the width + if (virtual_handle_widths.find(signal) != virtual_handle_widths.end()) { + return std::string(virtual_handle_widths[signal], 'x'); + } + return "x"; + } + if (past_data.find(signal) == past_data.end()) { - return std::string(handle_to_var[signal].width, 'x'); + if (handle_to_var.find(signal) != handle_to_var.end()) { + return std::string(handle_to_var[signal].width, 'x'); + } + return "x"; } return past_data[signal]; } diff --git a/kernel/fstdata.h b/kernel/fstdata.h index a8ae40301..b65681b00 100644 --- a/kernel/fstdata.h +++ b/kernel/fstdata.h @@ -69,6 +69,9 @@ private: uint64_t last_time; std::map past_data; uint64_t past_time; + std::map> fork_scopes; + std::map virtual_to_fork; + std::map virtual_handle_widths; double timescale; std::string timescale_str; uint64_t start_time; From 0aaca679cea2884feeab3e04d11824322368b7e6 Mon Sep 17 00:00:00 2001 From: Stan Lee Date: Fri, 27 Feb 2026 10:22:06 -0800 Subject: [PATCH 02/11] better but not ideal --- kernel/fstdata.cc | 103 +++++++++++++++++++--------------------------- kernel/fstdata.h | 4 +- 2 files changed, 43 insertions(+), 64 deletions(-) diff --git a/kernel/fstdata.cc b/kernel/fstdata.cc index 3e3e8d127..1ecf1f7e9 100644 --- a/kernel/fstdata.cc +++ b/kernel/fstdata.cc @@ -116,7 +116,8 @@ void FstData::extractVarNames() // Track current fork scope std::string current_fork_scope; - fstHandle next_virtual_handle = (fstHandle)-1; // forks get negative handle values for better identification + fstHandle next_fork_handle = 0x80000000; + std::map> fork_scopes; while ((h = fstReaderIterateHier(ctx))) { switch (h->htyp) { @@ -133,22 +134,13 @@ void FstData::extractVarNames() } case FST_HT_UPSCOPE: { if (!current_fork_scope.empty() && current_fork_scope == fst_scope_name) { - - // Create a virtual handle - fstHandle virtual_handle = next_virtual_handle--; - - // Map the scope to the virtual handle - name_to_handle[current_fork_scope] = virtual_handle; - virtual_to_fork[virtual_handle] = current_fork_scope; - - // Calculate total width of the struct and map it to the virtual handle - int total_width = 0; - for (fstHandle member : fork_scopes[current_fork_scope]) { - if (handle_to_var.find(member) != handle_to_var.end()) { - total_width += handle_to_var[member].width; - } - } - virtual_handle_widths[virtual_handle] = total_width; + fstHandle fork_handle = next_fork_handle++; + std::string normalized_fork_scope = current_fork_scope; + normalize_brackets(normalized_fork_scope); + + name_to_handle[normalized_fork_scope] = fork_handle; + fork_scope_members[fork_handle] = fork_scopes[current_fork_scope]; + current_fork_scope.clear(); } fst_scope_name = fstReaderPopScope(ctx); @@ -308,54 +300,43 @@ void FstData::reconstructAllAtTimes(std::vector &signal, uint64_t sta std::string FstData::valueOf(fstHandle signal) { - // Condition to check if the signal comes from a fork scope - if ((int)signal < 0 && virtual_to_fork.find(signal) != virtual_to_fork.end()) { - std::string fork_scope = virtual_to_fork[signal]; - if (fork_scopes.find(fork_scope) != fork_scopes.end()) { - - // Empty string to store the full struct values - std::string result; - - // Get the members of the fork scope - const std::vector& members = fork_scopes[fork_scope]; - for (auto it = members.rbegin(); it != members.rend(); ++it) { - fstHandle member = *it; - std::string member_val; - int expected_width = 0; - - // Get the width of the member - if (handle_to_var.find(member) != handle_to_var.end()) { - expected_width = handle_to_var[member].width; - } - - // Check if the member has a value - if (past_data.find(member) != past_data.end()) { - member_val = past_data[member]; - - // If the member value is shorter than the expected width, pad with zeros - if (expected_width > 0 && (int)member_val.length() < expected_width) { - member_val = std::string(expected_width - member_val.length(), '0') + member_val; - } - } else if (expected_width > 0) { - // If the member has no value, pad with x's - member_val = std::string(expected_width, 'x'); - } else { - member_val = "x"; - } - - // Add the member value to the result - result += member_val; + // Check if this is a fork scope (struct) + auto it = fork_scope_members.find(signal); + if (it != fork_scope_members.end()) { + std::string result; + const std::vector& members = it->second; + + // Iterate in REVERSE: first declared member is MSB in SystemVerilog packed structs + for (auto m = members.rbegin(); m != members.rend(); ++m) { + fstHandle member = *m; + std::string member_val; + int expected_width = 0; + + // Get the declared width of this member + if (handle_to_var.find(member) != handle_to_var.end()) { + expected_width = handle_to_var[member].width; } - return result; + + // Get the current value + if (past_data.find(member) != past_data.end()) { + member_val = past_data[member]; + // VCD drops leading zeros - must pad to full width + if (expected_width > 0 && (int)member_val.length() < expected_width) { + member_val = std::string(expected_width - member_val.length(), '0') + member_val; + } + } else if (expected_width > 0) { + // No value yet, use x's + member_val = std::string(expected_width, 'x'); + } else { + member_val = "x"; + } + + result += member_val; } - - // If the fork scope is not found, pad with x's based on the width - if (virtual_handle_widths.find(signal) != virtual_handle_widths.end()) { - return std::string(virtual_handle_widths[signal], 'x'); - } - return "x"; + return result; } + // Normal signal handling if (past_data.find(signal) == past_data.end()) { if (handle_to_var.find(signal) != handle_to_var.end()) { return std::string(handle_to_var[signal].width, 'x'); diff --git a/kernel/fstdata.h b/kernel/fstdata.h index b65681b00..ee421f9ac 100644 --- a/kernel/fstdata.h +++ b/kernel/fstdata.h @@ -69,9 +69,7 @@ private: uint64_t last_time; std::map past_data; uint64_t past_time; - std::map> fork_scopes; - std::map virtual_to_fork; - std::map virtual_handle_widths; + std::map> fork_scope_members; double timescale; std::string timescale_str; uint64_t start_time; From 48894488f1227d2aff1a08e6a0d9cd1531a7c5da Mon Sep 17 00:00:00 2001 From: Stan Lee Date: Fri, 27 Feb 2026 11:02:46 -0800 Subject: [PATCH 03/11] better method for assigning fsthandles --- kernel/fstdata.cc | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/kernel/fstdata.cc b/kernel/fstdata.cc index 1ecf1f7e9..ec61e80d4 100644 --- a/kernel/fstdata.cc +++ b/kernel/fstdata.cc @@ -116,7 +116,9 @@ void FstData::extractVarNames() // Track current fork scope std::string current_fork_scope; - fstHandle next_fork_handle = 0x80000000; + + // Start fork handles after the maximum real handle from FST file to avoid collisions + fstHandle next_fork_handle = fstReaderGetMaxHandle(ctx) + 1; std::map> fork_scopes; while ((h = fstReaderIterateHier(ctx))) { @@ -134,13 +136,16 @@ void FstData::extractVarNames() } case FST_HT_UPSCOPE: { if (!current_fork_scope.empty() && current_fork_scope == fst_scope_name) { + // Assign a unique handle to this fork scope fstHandle fork_handle = next_fork_handle++; + + // Map normalized scope name to the handle for future lookups via getHandle() std::string normalized_fork_scope = current_fork_scope; normalize_brackets(normalized_fork_scope); - name_to_handle[normalized_fork_scope] = fork_handle; fork_scope_members[fork_handle] = fork_scopes[current_fork_scope]; - + + // Clear current fork scope for the next scope current_fork_scope.clear(); } fst_scope_name = fstReaderPopScope(ctx); @@ -158,9 +163,12 @@ void FstData::extractVarNames() vars.push_back(var); if (!var.is_alias) handle_to_var[h->u.var.handle] = var; + + // Add variable to fork scope members if we are currently in a fork scope if (!current_fork_scope.empty()) { fork_scopes[current_fork_scope].push_back(h->u.var.handle); } + std::string clean_name; bool has_space = false; for(size_t i=0;iu.var.name);i++) From ae3b9b74e2a6d6c9deb5e77e84e6f44f7fd5932f Mon Sep 17 00:00:00 2001 From: Stan Lee Date: Fri, 27 Feb 2026 11:11:05 -0800 Subject: [PATCH 04/11] ready --- kernel/fstdata.cc | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/kernel/fstdata.cc b/kernel/fstdata.cc index ec61e80d4..a4c7d7e65 100644 --- a/kernel/fstdata.cc +++ b/kernel/fstdata.cc @@ -129,7 +129,7 @@ void FstData::extractVarNames() // Fork scopes are identified by FST_ST_VCD_FORK if (h->u.scope.typ == FST_ST_VCD_FORK) { current_fork_scope = fst_scope_name; - // Create new vector that contains struct members + // Create new vector that contains struct members copied during upscope fork_scopes[current_fork_scope] = std::vector(); } break; @@ -143,6 +143,9 @@ void FstData::extractVarNames() std::string normalized_fork_scope = current_fork_scope; normalize_brackets(normalized_fork_scope); name_to_handle[normalized_fork_scope] = fork_handle; + + // Copy the extracted members of the fork scope to the fork scope members map + // for value lookups in valueOf() fork_scope_members[fork_handle] = fork_scopes[current_fork_scope]; // Clear current fork scope for the next scope @@ -313,32 +316,32 @@ std::string FstData::valueOf(fstHandle signal) if (it != fork_scope_members.end()) { std::string result; const std::vector& members = it->second; - - // Iterate in REVERSE: first declared member is MSB in SystemVerilog packed structs + + // Iterate over members of the struct to get concatenated value. + // The first declared member is MSB in SystemVerilog packed structs for (auto m = members.rbegin(); m != members.rend(); ++m) { fstHandle member = *m; std::string member_val; int expected_width = 0; - + // Get the declared width of this member if (handle_to_var.find(member) != handle_to_var.end()) { expected_width = handle_to_var[member].width; } - - // Get the current value + // Get the current value of the member if (past_data.find(member) != past_data.end()) { member_val = past_data[member]; - // VCD drops leading zeros - must pad to full width + // Pad with zeros to the expected width of the member if (expected_width > 0 && (int)member_val.length() < expected_width) { member_val = std::string(expected_width - member_val.length(), '0') + member_val; } } else if (expected_width > 0) { - // No value yet, use x's + // No value yet, use X to pad member_val = std::string(expected_width, 'x'); - } else { + } else { // fallback to X member_val = "x"; } - + // Concatenate the member value to the overall struct value result += member_val; } return result; From fa1267e0cbd8be508345cfcbea8d62532249f51a Mon Sep 17 00:00:00 2001 From: Stan Lee Date: Fri, 27 Feb 2026 11:27:37 -0800 Subject: [PATCH 05/11] fix indents --- kernel/fstdata.cc | 71 +++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/kernel/fstdata.cc b/kernel/fstdata.cc index a4c7d7e65..6d45a8750 100644 --- a/kernel/fstdata.cc +++ b/kernel/fstdata.cc @@ -123,37 +123,37 @@ void FstData::extractVarNames() while ((h = fstReaderIterateHier(ctx))) { switch (h->htyp) { - case FST_HT_SCOPE: { - fst_scope_name = fstReaderPushScope(ctx, h->u.scope.name, NULL); + case FST_HT_SCOPE: { + fst_scope_name = fstReaderPushScope(ctx, h->u.scope.name, NULL); - // Fork scopes are identified by FST_ST_VCD_FORK - if (h->u.scope.typ == FST_ST_VCD_FORK) { - current_fork_scope = fst_scope_name; - // Create new vector that contains struct members copied during upscope - fork_scopes[current_fork_scope] = std::vector(); + // Fork scopes are identified by FST_ST_VCD_FORK + if (h->u.scope.typ == FST_ST_VCD_FORK) { + current_fork_scope = fst_scope_name; + // Create new vector that contains struct members copied during upscope + fork_scopes[current_fork_scope] = std::vector(); + } + break; } - break; - } - case FST_HT_UPSCOPE: { - if (!current_fork_scope.empty() && current_fork_scope == fst_scope_name) { - // Assign a unique handle to this fork scope - fstHandle fork_handle = next_fork_handle++; + case FST_HT_UPSCOPE: { + if (!current_fork_scope.empty() && current_fork_scope == fst_scope_name) { + // Assign a unique handle to this fork scope + fstHandle fork_handle = next_fork_handle++; - // Map normalized scope name to the handle for future lookups via getHandle() - std::string normalized_fork_scope = current_fork_scope; - normalize_brackets(normalized_fork_scope); - name_to_handle[normalized_fork_scope] = fork_handle; + // Map normalized scope name to the handle for future lookups via getHandle() + std::string normalized_fork_scope = current_fork_scope; + normalize_brackets(normalized_fork_scope); + name_to_handle[normalized_fork_scope] = fork_handle; - // Copy the extracted members of the fork scope to the fork scope members map - // for value lookups in valueOf() - fork_scope_members[fork_handle] = fork_scopes[current_fork_scope]; + // Copy the extracted members of the fork scope to the fork scope members map + // for value lookups in valueOf() + fork_scope_members[fork_handle] = fork_scopes[current_fork_scope]; - // Clear current fork scope for the next scope - current_fork_scope.clear(); + // Clear current fork scope for the next scope + current_fork_scope.clear(); + } + fst_scope_name = fstReaderPopScope(ctx); + break; } - fst_scope_name = fstReaderPopScope(ctx); - break; - } case FST_HT_VAR: { FstVar var; var.id = h->u.var.handle; @@ -163,14 +163,14 @@ void FstData::extractVarNames() var.scope = fst_scope_name; normalize_brackets(var.scope); var.width = h->u.var.length; - vars.push_back(var); - if (!var.is_alias) - handle_to_var[h->u.var.handle] = var; + vars.push_back(var); + if (!var.is_alias) + handle_to_var[h->u.var.handle] = var; - // Add variable to fork scope members if we are currently in a fork scope - if (!current_fork_scope.empty()) { - fork_scopes[current_fork_scope].push_back(h->u.var.handle); - } + // Add variable to fork scope members if we are currently in a fork scope + if (!current_fork_scope.empty()) { + fork_scopes[current_fork_scope].push_back(h->u.var.handle); + } std::string clean_name; bool has_space = false; @@ -348,11 +348,8 @@ std::string FstData::valueOf(fstHandle signal) } // Normal signal handling - if (past_data.find(signal) == past_data.end()) { - if (handle_to_var.find(signal) != handle_to_var.end()) { - return std::string(handle_to_var[signal].width, 'x'); - } - return "x"; + if (handle_to_var.find(signal) != handle_to_var.end()) { + return std::string(handle_to_var[signal].width, 'x'); } return past_data[signal]; } From 03ce300b49d2b516201aff748680fdb45a4b8490 Mon Sep 17 00:00:00 2001 From: Stan Lee Date: Fri, 27 Feb 2026 11:29:31 -0800 Subject: [PATCH 06/11] another indent --- kernel/fstdata.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/fstdata.cc b/kernel/fstdata.cc index 6d45a8750..395bab66f 100644 --- a/kernel/fstdata.cc +++ b/kernel/fstdata.cc @@ -172,7 +172,7 @@ void FstData::extractVarNames() fork_scopes[current_fork_scope].push_back(h->u.var.handle); } - std::string clean_name; + std::string clean_name; bool has_space = false; for(size_t i=0;iu.var.name);i++) { From d36e2f7d17a8353afd22dd8a32840cbcf9d6d4ae Mon Sep 17 00:00:00 2001 From: Stan Lee Date: Fri, 27 Feb 2026 11:40:13 -0800 Subject: [PATCH 07/11] resolve accidental change --- kernel/fstdata.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/fstdata.cc b/kernel/fstdata.cc index 395bab66f..fbcca6b82 100644 --- a/kernel/fstdata.cc +++ b/kernel/fstdata.cc @@ -348,7 +348,7 @@ std::string FstData::valueOf(fstHandle signal) } // Normal signal handling - if (handle_to_var.find(signal) != handle_to_var.end()) { + if (past_data.find(signal) == past_data.end()) { return std::string(handle_to_var[signal].width, 'x'); } return past_data[signal]; From c42d2c2d03dd814895fd1be18fe75f8d3b05b04b Mon Sep 17 00:00:00 2001 From: Stan Lee Date: Fri, 27 Feb 2026 11:54:43 -0800 Subject: [PATCH 08/11] support for nested structs --- kernel/fstdata.cc | 80 ++++++++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 33 deletions(-) diff --git a/kernel/fstdata.cc b/kernel/fstdata.cc index fbcca6b82..0350be46b 100644 --- a/kernel/fstdata.cc +++ b/kernel/fstdata.cc @@ -114,8 +114,9 @@ void FstData::extractVarNames() struct fstHier *h; std::string fst_scope_name; - // Track current fork scope - std::string current_fork_scope; + // Track nested fork scopes using a stack to handle nested packed structs + // Begins with outmost scope and ends with innermost scope + std::vector fork_scope_stack; // Start fork handles after the maximum real handle from FST file to avoid collisions fstHandle next_fork_handle = fstReaderGetMaxHandle(ctx) + 1; @@ -126,30 +127,35 @@ void FstData::extractVarNames() case FST_HT_SCOPE: { fst_scope_name = fstReaderPushScope(ctx, h->u.scope.name, NULL); - // Fork scopes are identified by FST_ST_VCD_FORK + // Fork scopes are identified by FST_ST_VCD_FORK and are pushed onto the stack if (h->u.scope.typ == FST_ST_VCD_FORK) { - current_fork_scope = fst_scope_name; - // Create new vector that contains struct members copied during upscope - fork_scopes[current_fork_scope] = std::vector(); + fork_scope_stack.push_back(fst_scope_name); + // Create new vector that contains struct members + fork_scopes[fst_scope_name] = std::vector(); } break; } case FST_HT_UPSCOPE: { - if (!current_fork_scope.empty() && current_fork_scope == fst_scope_name) { - // Assign a unique handle to this fork scope + if (!fork_scope_stack.empty() && fork_scope_stack.back() == fst_scope_name) { + // Assign a unique handle to this fork scope and increment for future forks fstHandle fork_handle = next_fork_handle++; // Map normalized scope name to the handle for future lookups via getHandle() - std::string normalized_fork_scope = current_fork_scope; - normalize_brackets(normalized_fork_scope); - name_to_handle[normalized_fork_scope] = fork_handle; + normalize_brackets(fst_scope_name); + name_to_handle[fst_scope_name] = fork_handle; // Copy the extracted members of the fork scope to the fork scope members map // for value lookups in valueOf() - fork_scope_members[fork_handle] = fork_scopes[current_fork_scope]; + fork_scope_members[fork_handle] = fork_scopes[fst_scope_name]; - // Clear current fork scope for the next scope - current_fork_scope.clear(); + // If this is a nested fork scope, add its handle to the parent fork scope + if (fork_scope_stack.size() > 1) { + std::string parent_fork = fork_scope_stack[fork_scope_stack.size() - 2]; + fork_scopes[parent_fork].push_back(fork_handle); + } + + // Pop this fork scope from the stack + fork_scope_stack.pop_back(); } fst_scope_name = fstReaderPopScope(ctx); break; @@ -167,9 +173,9 @@ void FstData::extractVarNames() if (!var.is_alias) handle_to_var[h->u.var.handle] = var; - // Add variable to fork scope members if we are currently in a fork scope - if (!current_fork_scope.empty()) { - fork_scopes[current_fork_scope].push_back(h->u.var.handle); + // Add variable to the innermost fork scope in the fork scope stack + if (!fork_scope_stack.empty()) { + fork_scopes[fork_scope_stack.back()].push_back(h->u.var.handle); } std::string clean_name; @@ -322,24 +328,32 @@ std::string FstData::valueOf(fstHandle signal) for (auto m = members.rbegin(); m != members.rend(); ++m) { fstHandle member = *m; std::string member_val; - int expected_width = 0; + + // Check if this member is itself a nested fork scope (struct) + if (fork_scope_members.find(member) != fork_scope_members.end()) { + // Recursively get the value of the nested struct + member_val = valueOf(member); + } else { + // Regular variable - look up in past_data + int expected_width = 0; - // Get the declared width of this member - if (handle_to_var.find(member) != handle_to_var.end()) { - expected_width = handle_to_var[member].width; - } - // Get the current value of the member - if (past_data.find(member) != past_data.end()) { - member_val = past_data[member]; - // Pad with zeros to the expected width of the member - if (expected_width > 0 && (int)member_val.length() < expected_width) { - member_val = std::string(expected_width - member_val.length(), '0') + member_val; + // Get the declared width of this member + if (handle_to_var.find(member) != handle_to_var.end()) { + expected_width = handle_to_var[member].width; + } + // Get the current value of the member + if (past_data.find(member) != past_data.end()) { + member_val = past_data[member]; + // Pad with zeros to the expected width of the member + if (expected_width > 0 && (int)member_val.length() < expected_width) { + member_val = std::string(expected_width - member_val.length(), '0') + member_val; + } + } else if (expected_width > 0) { + // No value yet, use X to pad + member_val = std::string(expected_width, 'x'); + } else { // fallback to X + member_val = "x"; } - } else if (expected_width > 0) { - // No value yet, use X to pad - member_val = std::string(expected_width, 'x'); - } else { // fallback to X - member_val = "x"; } // Concatenate the member value to the overall struct value result += member_val; From 93af5a5232b8f64b3e2d8d54a046ae64e3ce48fd Mon Sep 17 00:00:00 2001 From: Stan Lee Date: Fri, 27 Feb 2026 12:17:43 -0800 Subject: [PATCH 09/11] in order --- kernel/fstdata.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/fstdata.cc b/kernel/fstdata.cc index 0350be46b..44f53e8bd 100644 --- a/kernel/fstdata.cc +++ b/kernel/fstdata.cc @@ -325,7 +325,7 @@ std::string FstData::valueOf(fstHandle signal) // Iterate over members of the struct to get concatenated value. // The first declared member is MSB in SystemVerilog packed structs - for (auto m = members.rbegin(); m != members.rend(); ++m) { + for (auto m = members.begin(); m != members.end(); m++) { fstHandle member = *m; std::string member_val; From 8ee71ddc7f98884c6de90d2432a002fa8bdb4a34 Mon Sep 17 00:00:00 2001 From: Stan Lee Date: Fri, 27 Feb 2026 12:19:14 -0800 Subject: [PATCH 10/11] bugfix --- kernel/fstdata.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/fstdata.cc b/kernel/fstdata.cc index 44f53e8bd..f417048f2 100644 --- a/kernel/fstdata.cc +++ b/kernel/fstdata.cc @@ -131,6 +131,7 @@ void FstData::extractVarNames() if (h->u.scope.typ == FST_ST_VCD_FORK) { fork_scope_stack.push_back(fst_scope_name); // Create new vector that contains struct members + normalize_brackets(fst_scope_name); fork_scopes[fst_scope_name] = std::vector(); } break; From 7e8331dd95e11765d33b26d67c043ee6a9249ae2 Mon Sep 17 00:00:00 2001 From: Stan Lee Date: Tue, 3 Mar 2026 15:15:26 -0800 Subject: [PATCH 11/11] greptile --- kernel/fstdata.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/kernel/fstdata.cc b/kernel/fstdata.cc index f417048f2..d9cc321da 100644 --- a/kernel/fstdata.cc +++ b/kernel/fstdata.cc @@ -116,10 +116,13 @@ void FstData::extractVarNames() // Track nested fork scopes using a stack to handle nested packed structs // Begins with outmost scope and ends with innermost scope + // Scopes are not normalized on the stack std::vector fork_scope_stack; // Start fork handles after the maximum real handle from FST file to avoid collisions fstHandle next_fork_handle = fstReaderGetMaxHandle(ctx) + 1; + + // Map of fork scopes to their members, which are all normalized std::map> fork_scopes; while ((h = fstReaderIterateHier(ctx))) { @@ -152,6 +155,7 @@ void FstData::extractVarNames() // If this is a nested fork scope, add its handle to the parent fork scope if (fork_scope_stack.size() > 1) { std::string parent_fork = fork_scope_stack[fork_scope_stack.size() - 2]; + normalize_brackets(parent_fork); fork_scopes[parent_fork].push_back(fork_handle); } @@ -176,7 +180,9 @@ void FstData::extractVarNames() // Add variable to the innermost fork scope in the fork scope stack if (!fork_scope_stack.empty()) { - fork_scopes[fork_scope_stack.back()].push_back(h->u.var.handle); + std::string current_fork = fork_scope_stack.back(); + normalize_brackets(current_fork); + fork_scopes[current_fork].push_back(h->u.var.handle); } std::string clean_name;