Merge pull request #116 from Silimate/autoscope

Autoscope
This commit is contained in:
Akash Levy 2026-03-03 20:49:13 -08:00 committed by GitHub
commit 958f1c608a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 106 additions and 8 deletions

View File

@ -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<std::string> 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<std::string, int> 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<std::string, int> 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 "";
}

View File

@ -57,6 +57,7 @@ class FstData
dict<int,fstHandle> getMemoryHandles(std::string name);
double getTimescale() { return timescale; }
const char *getTimescaleString() { return timescale_str.c_str(); }
std::string autoScope(Module *topmod);
private:
void extractVarNames();

View File

@ -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();

View File

@ -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<std::pair<std::string, std::string>, 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