diff --git a/kernel/fstdata.cc b/kernel/fstdata.cc index d9cc321da..6b771d4f6 100644 --- a/kernel/fstdata.cc +++ b/kernel/fstdata.cc @@ -374,3 +374,87 @@ 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); + + log("Available scopes:\n"); + std::set unique_scopes; + for (const auto& var : vars) { + unique_scopes.insert(var.scope); + } + for (const auto& scope : unique_scopes) { + log(" %s\n", scope.c_str()); + } + + // 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) { + std::string scope = var.scope.substr(0, pos + top.length()); + return scope; + } + } + } + + // Option 2 - Port based scope matching + // Matches based on exact port name matching of the top module + log("Trying port-based scope matching...\n"); + + // Map top module port name to their bit widths (RTL reference point) + dict top2widths; + for (auto wire : topmod->wires()) { + if (wire->port_input || wire->port_output) { + top2widths[RTLIL::unescape_id(wire->name)] = wire->width; + } + } + log("Extracted %d ports from top module\n", GetSize(top2widths)); + + // 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); + } + + // 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; + } + } + + // Find scopes with exact matches + // If there is a tie, return the longest scope + std::string result = ""; + for (const auto& entry : scopes2matches) { + int num_matches = entry.second; + if (num_matches == GetSize(top2widths)) { + std::string scope = entry.first; + if (result.empty() || scope.length() > result.length()) { + result = scope; + } + } + } + if (!result.empty()) { + return result; + } + + // 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 ee421f9ac..80d0c19b2 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..ed7ed71ac 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -1474,8 +1474,14 @@ 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()) { + log_error("No scope found for module '%s'. Please specify -scope explicitly.\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..5635b6869 100644 --- a/passes/silimate/reg_rename.cc +++ b/passes/silimate/reg_rename.cc @@ -188,15 +188,25 @@ 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_error("No scope found for module '%s'. Please specify -scope explicitly.\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 +233,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