From c459a74c13ef4fd723bbaa45914dfaf642bb84dd Mon Sep 17 00:00:00 2001 From: Stan Lee Date: Sun, 1 Mar 2026 15:39:35 -0800 Subject: [PATCH] autoscoping --- kernel/fstdata.cc | 74 +++++++++++++++++++++++++++++++++++ kernel/fstdata.h | 1 + passes/sat/sim.cc | 18 ++++++++- passes/silimate/reg_rename.cc | 29 +++++++++++--- 4 files changed, 114 insertions(+), 8 deletions(-) diff --git a/kernel/fstdata.cc b/kernel/fstdata.cc index f0f00181c..52f690774 100644 --- a/kernel/fstdata.cc +++ b/kernel/fstdata.cc @@ -280,3 +280,77 @@ std::string FstData::valueOf(fstHandle signal) } return past_data[signal]; } + +// Auto-discover scope from FST by finding the top module +std::string FstData::autoScope(Module *topmod) { + + log("Auto-discovering scope from file...\n"); + std::string top = RTLIL::unescape_id(topmod->name); + + // Option 1 - Instance based scope matching + // Will fail if the DUT instance name != the top module name + log("Trying instance-based scope matching...\n"); + for (const auto& var : vars) { + // Check if this scope ends with our top module + log_debug("Checking scope: %s\n", var.scope.c_str()); + if (var.scope == top || + var.scope.find("." + top) != std::string::npos) { + // Extract the full path up to (and including) the top module + size_t pos = var.scope.find(top); + if (pos != std::string::npos) { + return var.scope.substr(0, pos + top.length()); + } + } + } + + // Option 2 - Post based scope matching + // Matches based on exact port name matching of the top module + log("Trying port-based scope matching...\n"); + + // Map port name to their bit widths (RTL reference point) + dict ports; + for (auto wire : topmod->wires()) { + if (wire->port_input || wire->port_output) { + ports[RTLIL::unescape_id(wire->name)] = wire->width; + } + } + + // For each scope, track which ports were found with matching width + // (VCD reference point) + dict> scope_found_ports; + 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); + } + + // Check if this variable name matches one of our port names + if (ports.count(var_name)) { + // Also check if width matches + if (ports[var_name] == var.width) { + scope_found_ports[var.scope].insert(var_name); + } + } + } + + // Compare RTl and VCD references and find an exact match + for (const auto& entry : scope_found_ports) { + const std::string& scope = entry.first; + const std::set& found = entry.second; + + // Check if all port names exist in this scope + if (found.size() == ports.size()) { + log("Auto-discovered scope: %s (matched all %d ports by name)\n", + scope.c_str(), (int)ports.size()); + return scope; + } + } + + // No match found + log_warning("Could not auto-discover scope for module '%s'...\n", + RTLIL::unescape_id(topmod->name).c_str()); + return ""; +} diff --git a/kernel/fstdata.h b/kernel/fstdata.h index a8ae40301..ba262dcf2 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(); } + std::string autoScope(Module *topmod); private: void extractVarNames(); diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index 3530bc7af..6f980ed56 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -1474,8 +1474,22 @@ struct SimWorker : SimShared log_assert(top == nullptr); fst = new FstData(sim_filename); timescale = fst->getTimescaleString(); - if (scope.empty()) - log_error("Scope must be defined for co-simulation.\n"); + if (scope.empty()) { + scope = fst->autoScope(topmod); + if (scope.empty()) { + std::set unique_scopes; + for (const auto& var : fst->getVars()) { + unique_scopes.insert(var.scope); + } + log_warning("Available scopes:\n"); + for (const auto& scope : unique_scopes) { + log_warning(" %s\n", scope.c_str()); + } + log_error("No scope found for module '%s'. Please specify -scope explicitly with above options.\n", + RTLIL::unescape_id(topmod->name).c_str()); + } + } + log("Using scope: \"%s\"\n", scope.c_str()); top = new SimInstance(this, scope, topmod); register_signals(); diff --git a/passes/silimate/reg_rename.cc b/passes/silimate/reg_rename.cc index b4a4871f2..066633780 100644 --- a/passes/silimate/reg_rename.cc +++ b/passes/silimate/reg_rename.cc @@ -188,15 +188,35 @@ struct RegRenamePass : public Pass { } extra_args(args, argidx, design); + // Extract top module + Module *topmod = design->top_module(); + if (!topmod) + log_error("No top module found!\n"); + // Extract pre-optimization register widths from VCD file dict, int> vcd_reg_widths; if (!vcd_filename.empty()) { - if (scope.empty()) { - log_error("No scope provided. Use -scope option.\n"); - } log("Reading VCD file: %s\n", vcd_filename.c_str()); try { FstData fst(vcd_filename); + if (scope.empty()) { + scope = fst.autoScope(topmod); + if (scope.empty()) { + log_warning("No scope found for module '%s'. Please specify -scope explicitly.\n", + RTLIL::unescape_id(topmod->name).c_str()); + std::set unique_scopes; + for (const auto& var : fst.getVars()) { + unique_scopes.insert(var.scope); + } + log_warning("Available scopes:\n"); + for (const auto& scope : unique_scopes) { + log_warning(" %s\n", scope.c_str()); + } + log_error("No scope found for module '%s'. Please specify -scope explicitly with above options.\n", + RTLIL::unescape_id(topmod->name).c_str()); + } + } + log("Using scope: \"%s\"\n", scope.c_str()); for (auto &var : fst.getVars()) { if (var.is_reg) { std::string reg_vcd_scope = var.scope; @@ -223,9 +243,6 @@ struct RegRenamePass : public Pass { } // STEP 2: Build hierarchy and process - Module *topmod = design->top_module(); - if (!topmod) - log_error("No top module found!\n"); log("Building hierarchy from scope: %s\n", scope.c_str()); // Build hierarchy and process register renamings