From 01f0fd751fbcd303e3c25989ec1b9fc0c4765dfd Mon Sep 17 00:00:00 2001 From: Stan Lee Date: Mon, 30 Mar 2026 12:13:50 -0700 Subject: [PATCH] fixes for arrays --- kernel/fstdata.cc | 31 +++++++++++-- passes/sat/sim.cc | 111 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 131 insertions(+), 11 deletions(-) diff --git a/kernel/fstdata.cc b/kernel/fstdata.cc index 2e3c429a5..03b808412 100644 --- a/kernel/fstdata.cc +++ b/kernel/fstdata.cc @@ -195,13 +195,38 @@ void FstData::extractVarNames() } 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("["); - 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); + 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 [index][bitrange]" format + std::string full_name = h->u.var.name; + size_t space_pos = full_name.find(' '); + if (space_pos != std::string::npos) { + std::string suffix = full_name.substr(space_pos + 1); + // Parse first bracket pair for array index + if (!suffix.empty() && suffix[0] == '[') { + size_t close_bracket = suffix.find(']'); + if (close_bracket != std::string::npos) { + std::string index_str = suffix.substr(1, close_bracket - 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); + memory_to_handle[var.scope+"."+clean_name][array_index] = var.id; + } + } + } } } + + // Handle memory addresses size_t pos = clean_name.find_last_of("<"); if (pos != std::string::npos && clean_name.back() == '>') { std::string mem_cell = clean_name.substr(0, pos); diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index d470d760f..d8c63390c 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -224,6 +224,54 @@ struct SimInstance dict fst_inputs; dict> fst_memories; + // For multi-dimensional arrays + dict> fst_array_handles; + dict> 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 tryGetArrayHandles(FstData* fst, const std::string& scope, + Wire* wire, bool debug_mode) + { + std::string wire_name = scope + "." + RTLIL::unescape_id(wire->name); + fstHandle id = fst->getHandle(wire_name); + + if (id != 0) { + int fst_width = fst->getWidth(id); + if (fst_width != wire->width) { + // If there is a width mismatch, try to find array elements + if (debug_mode) { + log("Wire %s width mismatch (wire: %d, FST: %d), checking for array elements.\n", + wire_name.c_str(), wire->width, fst_width); + } + + // Array elements are stored in memory_to_handle + dict array_handles = fst->getMemoryHandles(wire_name); + if (!array_handles.empty()) { + + // Calculate total width of all array elements + int total_width = 0; + for (auto &pair : array_handles) { + total_width += fst->getWidth(pair.second); + } + + // If the total width of all array elements matches the wire, return the corresponding array handles + if (total_width == wire->width) { + if (debug_mode) { + log("Found %zu array elements for wire %s, total width: %d\n", + array_handles.size(), wire_name.c_str(), total_width); + } + return array_handles; + } else if (debug_mode) { + log_warning("Array elements total width %d doesn't match wire width %d\n", + total_width, wire->width); + } + } + } + } + return dict(); + } + SimInstance(SimShared *shared, std::string scope, Module *module, Cell *instance = nullptr, SimInstance *parent = nullptr) : shared(shared), scope(scope), module(module), instance(instance), parent(parent), sigmap(module) { @@ -255,18 +303,25 @@ struct SimInstance } } + // Populate fst_handles and fst_array_handles for signal lookups if ((shared->fst) && !(shared->hide_internal && wire->name[0] == '$')) { fstHandle id = shared->fst->getHandle(scope + "." + RTLIL::unescape_id(wire->name)); - if (id==0 && wire->name.isPublic()) { - if (shared->debug) { - log_warning("Unable to find wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(wire->name))); - } - } else { + + // Try to get array element handles if this is a multi-dimensional array + dict array_handles = tryGetArrayHandles(shared->fst, scope, wire, shared->debug); + if (!array_handles.empty()) { + // Must be an array, store in fst_array_handles + fst_array_handles[wire] = array_handles; + } else if (id != 0) { + // Case of a regular wire/reg + fst_handles[wire] = id; if (shared->debug) { log("Found wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(wire->name))); } + } else if (wire->name.isPublic() && shared->debug) { + // Not found + log_warning("Unable to find wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(wire->name))); } - fst_handles[wire] = id; } if (wire->attributes.count(ID::init)) { @@ -1178,6 +1233,20 @@ 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) { + Wire* wire = item.first; + dict& handles = item.second; + + // Concatenate values from all array elements in reverse order + std::string concatenated = ""; + for (int idx = handles.size() - 1; idx >= 0; idx--) { + if (handles.count(idx) == 0) continue; + concatenated += shared->fst->valueOf(handles[idx]); + } + + did_something |= set_state(wire, Const::from_string(concatenated)); + } for (auto cell : module->cells()) { if (cell->is_mem_cell()) { @@ -1227,6 +1296,20 @@ 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) { + Wire* wire = item.first; + dict& handles = item.second; + + // Concatenate values from all array elements in reverse order + std::string concatenated = ""; + for (int idx = handles.size() - 1; idx >= 0; idx--) { + if (handles.count(idx) == 0) continue; + concatenated += shared->fst->valueOf(handles[idx]); + } + + did_something |= set_state(wire, Const::from_string(concatenated)); + } for (auto child : children) did_something |= child.second->setInputs(); @@ -1523,11 +1606,23 @@ struct SimWorker : SimShared SigMap sigmap(topmod); for (auto wire : topmod->wires()) { + + // Populate fst_inputs and fst_array_inputs for input ports if (wire->port_input) { fstHandle id = fst->getHandle(scope + "." + RTLIL::unescape_id(wire->name)); - if (id==0) + + // Try to get array element handles if this is a multi-dimensional array + dict array_handles = top->tryGetArrayHandles(fst, scope, wire, debug); + if (!array_handles.empty()) { + // Must be an array, store in fst_array_inputs + top->fst_array_inputs[wire] = array_handles; + } else if (id != 0) { + // Case of a regular wire/reg + top->fst_inputs[wire] = id; + } else { + // Not found log_error("Unable to find required '%s' signal in file\n",(scope + "." + RTLIL::unescape_id(wire->name))); - top->fst_inputs[wire] = id; + } } }