diff --git a/kernel/fstdata.cc b/kernel/fstdata.cc index 42f2f76e0..0a6f406ef 100644 --- a/kernel/fstdata.cc +++ b/kernel/fstdata.cc @@ -103,13 +103,6 @@ dict FstData::getMemoryHandles(std::string name) { return dict(); }; -dict,fstHandle> FstData::getArrayHandles(std::string name) { - if (array_to_handle.find(name) != array_to_handle.end()) - return array_to_handle[name]; - else - return dict,fstHandle>(); -}; - static std::string remove_spaces(std::string str) { str.erase(std::remove(str.begin(), str.end(), ' '), str.end()); @@ -121,54 +114,13 @@ void FstData::extractVarNames() struct fstHier *h; std::string fst_scope_name; - // 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))) { switch (h->htyp) { case FST_HT_SCOPE: { fst_scope_name = fstReaderPushScope(ctx, h->u.scope.name, NULL); - - // Fork scopes are identified by FST_ST_VCD_FORK and are pushed onto the stack - 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; } case FST_HT_UPSCOPE: { - 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() - 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[fst_scope_name]; - - // 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); - } - - // Pop this fork scope from the stack - fork_scope_stack.pop_back(); - } fst_scope_name = fstReaderPopScope(ctx); break; } @@ -185,70 +137,17 @@ void FstData::extractVarNames() if (!var.is_alias) handle_to_var[h->u.var.handle] = var; - // Add variable to the innermost fork scope in the fork scope stack - if (!fork_scope_stack.empty()) { - 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 = var.name; + if (!clean_name.empty() && clean_name[0] == '\\') + clean_name = clean_name.substr(1); - std::string clean_name; - bool has_space = false; - for(size_t i=0;iu.var.name);i++) - { - char c = h->u.var.name[i]; - if(c==' ') { has_space = true; break; } - clean_name += c; - } - if (clean_name[0]=='\\') - clean_name = clean_name.substr(1); - - // Strip bit ranges like [4:0] from the end (only if no space) - if (!has_space) { - size_t pos = clean_name.find_last_of("["); - if (pos != std::string::npos) { - std::string index_or_range = clean_name.substr(pos+1); - if (index_or_range.find(":") != std::string::npos) { - clean_name = clean_name.substr(0,pos); - } - } - } else { - - // Handle "signal [i0][i1]...[iN][bitrange]" format - std::string full_name = h->u.var.name; - size_t space_pos = full_name.find(' '); - if (space_pos != std::string::npos) { - - // Extract "[i0][i1]...[iN][bitrange]" suffix - std::string suffix = full_name.substr(space_pos + 1); - - // Parse arbitrary number of array indices - size_t open = 0; - std::vector array_indices; - while (open < suffix.length() && suffix[open] == '[') { - - size_t close = suffix.find(']', open); - if (close != std::string::npos) { - std::string index_str = suffix.substr(open + 1, close - open - 1); - - // Check it's an array index (no colon), not a bit range - if (index_str.find(':') == std::string::npos) { - int array_index = std::stoi(index_str); - array_indices.push_back(array_index); - } - } else { - log_warning("Error parsing array index in : %s\n", full_name.c_str()); - break; - } - - // Move to next opening bracket - open = close + 1; - } - - // Add array indices to array_to_handle map if there are any - if (!array_indices.empty()) { - array_to_handle[var.scope+"."+clean_name][array_indices] = var.id; - } + // Strip trailing bit range [N:M] if present + if (!clean_name.empty() && clean_name.back() == ']') { + size_t open = clean_name.rfind('['); + if (open != std::string::npos) { + std::string inner = clean_name.substr(open + 1, clean_name.size() - open - 2); + if (inner.find(':') != std::string::npos) + clean_name.erase(open); } } @@ -375,51 +274,6 @@ void FstData::reconstructAllAtTimes(std::vector &signal, uint64_t sta std::string FstData::valueOf(fstHandle signal) { - // 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 over members of the struct to get concatenated value. - // The first declared member is MSB in SystemVerilog packed structs - for (auto m = members.begin(); m != members.end(); m++) { - fstHandle member = *m; - std::string member_val; - - // 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; - } - } 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; - } - return result; - } - - // Normal signal handling if (past_data.find(signal) == past_data.end()) { return std::string(handle_to_var[signal].width, 'x'); } @@ -428,29 +282,16 @@ std::string FstData::valueOf(fstHandle 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) { - - log("Auto-discovering scopes from %d candidates...\n", GetSize(name_to_handle)); std::string top = RTLIL::unescape_id(topmod->name); std::string scope = ""; @@ -463,41 +304,44 @@ std::string FstData::autoScope(Module *topmod) { } log("Extracted %d ports from module '%s'\n", GetSize(top2widths), top.c_str()); - // For each scope, track the number of matching ports - dict scopes2matches; - // Use name_to_handle to get all signals from the FST file + // Extract list of candidate scopes from name_to_handle + pool candidate_scopes; for (auto entry : name_to_handle) { std::string name = entry.first; - fstHandle handle = entry.second; - - // 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 + if (last_dot != std::string::npos) { std::string scope = name.substr(0, last_dot); - std::string signal_name = name.substr(last_dot + 1); + candidate_scopes.insert(scope); + } + } + log("Auto-discovering scopes from %d candidates...\n", GetSize(candidate_scopes)); - // 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]++; - } + // Track number of exact matches for each scope, adding to results if all match + std::vector results; + for (const auto &scope_candidate : candidate_scopes) { + int matches = 0; + + // Loop through all top-level ports + for (auto &port : top2widths) { + const std::string &port_name = port.first; + int port_width = port.second; + std::string key = scope_candidate + "." + port_name; + auto it = name_to_handle.find(key); + + // Check the signal exists and has correct width to determine a match + if (it != name_to_handle.end() && getWidth(it->second) == port_width) { + matches++; } } - } - // Find scopes with exact matches and add to array - std::vector results; - for (const auto& entry : scopes2matches) { - int num_matches = entry.second; - if (num_matches == GetSize(top2widths)) { - std::string scope = entry.first; - results.push_back(scope); + // If all ports match, add to results + if (matches == GetSize(top2widths)) { + results.push_back(scope_candidate); } } + + // Logging results if (results.empty()) { log_warning("Could not auto-discover scope for module '%s'...\n", top.c_str()); diff --git a/kernel/fstdata.h b/kernel/fstdata.h index a7a269da6..98f5d5014 100644 --- a/kernel/fstdata.h +++ b/kernel/fstdata.h @@ -55,7 +55,6 @@ class FstData std::string valueOf(fstHandle signal); fstHandle getHandle(std::string name); dict getMemoryHandles(std::string name); - dict,fstHandle> getArrayHandles(std::string name); double getTimescale() { return timescale; } const char *getTimescaleString() { return timescale_str.c_str(); } int getWidth(fstHandle signal); @@ -68,12 +67,10 @@ private: std::map handle_to_var; std::map name_to_handle; std::map> memory_to_handle; - std::map, fstHandle>> array_to_handle; std::map last_data; uint64_t last_time; std::map past_data; uint64_t past_time; - std::map> fork_scope_members; double timescale; std::string timescale_str; uint64_t start_time; diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index 7cc53ba7a..033fb9e80 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -228,35 +228,6 @@ struct SimInstance dict fst_inputs; dict> fst_memories; - // For multi-dimensional arrays - dict,fstHandle>> fst_array_handles; - dict,fstHandle>> fst_array_inputs; - - // Helper function to detect and retrieve array element handles - // Returns non-empty dict if wire is a multi-dimensional array split in VCD - dict, fstHandle> tryGetArrayHandles(FstData* fst, const std::string& scope, Wire* wire) - { - std::string wire_name = scope + "." + RTLIL::unescape_id(wire->name); - dict, fstHandle> array_handles = fst->getArrayHandles(wire_name); - - if (!array_handles.empty()) { - int total_width = 0; - for (auto &pair : array_handles) { - total_width += fst->getWidth(pair.second); - } - if (total_width == wire->width) { - if (shared->debug) { - log("Found %zu array elements for wire %s, total width: %d\n", - array_handles.size(), wire_name.c_str(), total_width); - } - return array_handles; - } - log_warning("Array wire '%s' found in VCD (total width %d) but does not match Yosys wire width %d; skipping.\n", - wire_name.c_str(), total_width, wire->width); - } - return dict, fstHandle>(); - } - // Helper function to set wire state from array element handles // Concatenates values from array elements in descending index order bool setStateFromArrayHandles(Wire* wire, dict, fstHandle>& handles) @@ -307,16 +278,11 @@ struct SimInstance } } - // Populate fst_handles and fst_array_handles for signal lookups + // Populate fst_handles for signal lookups if ((shared->fst) && !(shared->hide_internal && wire->name[0] == '$')) { fstHandle id = shared->fst->getHandle(scope + "." + RTLIL::unescape_id(wire->name)); - // Try to get array element handles if this is a multi-dimensional array - dict, fstHandle> array_handles = tryGetArrayHandles(shared->fst, scope, wire); - if (!array_handles.empty()) { - // Must be an array, store in fst_array_handles - fst_array_handles[wire] = array_handles; - } else if (id != 0) { + if (id != 0) { // Case of a regular wire/reg fst_handles[wire] = id; if (shared->debug) { @@ -1258,10 +1224,6 @@ struct SimInstance std::string v = shared->fst->valueOf(item.second); did_something |= set_state(item.first, Const::from_string(v)); } - // Handle multi-dimensional arrays by concatenating array elements - for(auto &item : fst_array_handles) { - did_something |= setStateFromArrayHandles(item.first, item.second); - } for (auto cell : module->cells()) { if (cell->is_mem_cell()) { @@ -1301,11 +1263,6 @@ struct SimInstance // Overwrite simulation register state with the ground truth did_something |= set_state(wire, vcd_val); } - // Handles multi-dimensional registers - for (auto &item : fst_array_handles) { - if (register_wires.count(item.first) == 0) continue; - did_something |= setStateFromArrayHandles(item.first, item.second); - } // Apply to all child modules for (auto child : children) did_something |= child.second->setRegisters(time); @@ -1344,10 +1301,6 @@ struct SimInstance std::string v = shared->fst->valueOf(item.second); did_something |= set_state(item.first, Const::from_string(v)); } - // Handle multi-dimensional array inputs by concatenating array elements - for(auto &item : fst_array_inputs) { - did_something |= setStateFromArrayHandles(item.first, item.second); - } for (auto child : children) did_something |= child.second->setInputs(); @@ -1646,16 +1599,10 @@ struct SimWorker : SimShared for (auto wire : topmod->wires()) { - // Populate fst_inputs and fst_array_inputs for input ports + // Populate fst_inputs for input ports if (wire->port_input) { fstHandle id = fst->getHandle(scope + "." + RTLIL::unescape_id(wire->name)); - - // Try to get array element handles if this is a multi-dimensional array - dict, fstHandle> array_handles = top->tryGetArrayHandles(fst, scope, wire); - if (!array_handles.empty()) { - // Must be an array, store in fst_array_inputs - top->fst_array_inputs[wire] = array_handles; - } else if (id != 0) { + if (id != 0) { // Case of a regular wire/reg top->fst_inputs[wire] = id; } else {