From a01d0b2935b545757d9e0da9186c7658258bbc8a Mon Sep 17 00:00:00 2001 From: Stan Lee Date: Wed, 4 Mar 2026 10:25:53 -0800 Subject: [PATCH] autoscope supports top-level fork scope ports --- kernel/fstdata.cc | 50 +++++++++++++++++++++++++++++++++++++---------- kernel/fstdata.h | 1 + 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/kernel/fstdata.cc b/kernel/fstdata.cc index 6b771d4f6..899447773 100644 --- a/kernel/fstdata.cc +++ b/kernel/fstdata.cc @@ -375,6 +375,27 @@ std::string FstData::valueOf(fstHandle signal) return past_data[signal]; } +int FstData::getWidth(fstHandle signal) +{ + // Check if signal is a fork scope (struct) + if (fork_scope_members.count(signal)) { + // Sum the widths of all members of the fork scope, which may be forks themselves + int width = 0; + for (fstHandle member : fork_scope_members[signal]) { + width += getWidth(member); + } + return width; + } + + if (handle_to_var.count(signal)) { + return handle_to_var[signal].width; + } + + // Signal not found + log_warning("Signal %d was not extracted from file...\n", signal); + return 0; +} + // Auto-discover scope from FST by finding the top module std::string FstData::autoScope(Module *topmod) { @@ -422,18 +443,27 @@ std::string FstData::autoScope(Module *topmod) { // For each scope, track the number of matching ports dict scopes2matches; - for (const auto& var : vars) { - // Strip array '[]' notation from variable name - std::string var_name = var.name; - size_t bracket = var_name.find('['); - if (bracket != std::string::npos) { - var_name = var_name.substr(0, bracket); - } + // Use name_to_handle to get all signals from the FST file + for (auto entry : name_to_handle) { + std::string name = entry.first; + fstHandle handle = entry.second; - // Check if this variable name matches one of our top module port names and width - if (top2widths.count(var_name) && top2widths[var_name] == var.width) { - scopes2matches[var.scope] += 1; + // Extract signal name and scope using '.' + // Signal names of form '{scope}.signal_name' with scope potentially + // having zero to multiple '.' + size_t last_dot = name.find_last_of('.'); + if (last_dot != std::string::npos) { // no '.' means no scope/signal extraction is possible + std::string scope = name.substr(0, last_dot); + std::string signal_name = name.substr(last_dot + 1); + + // Check that signal is in the top module and width matches + if (top2widths.count(signal_name)) { + int signal_width = getWidth(handle); + if (signal_width == top2widths[signal_name]) { + scopes2matches[scope]++; + } + } } } diff --git a/kernel/fstdata.h b/kernel/fstdata.h index 80d0c19b2..f95806cca 100644 --- a/kernel/fstdata.h +++ b/kernel/fstdata.h @@ -57,6 +57,7 @@ class FstData dict getMemoryHandles(std::string name); double getTimescale() { return timescale; } const char *getTimescaleString() { return timescale_str.c_str(); } + int getWidth(fstHandle signal); std::string autoScope(Module *topmod); private: void extractVarNames();