Support for N-dimensional arrays in simulation

This commit is contained in:
Stan Lee 2026-03-31 12:50:36 -07:00
parent fe6dc21b49
commit b6f118091c
3 changed files with 44 additions and 27 deletions

View File

@ -103,11 +103,11 @@ dict<int,fstHandle> FstData::getMemoryHandles(std::string name) {
return dict<int,fstHandle>();
};
dict<int,fstHandle> FstData::getArrayHandles(std::string name) {
dict<std::vector<int>,fstHandle> FstData::getArrayHandles(std::string name) {
if (array_to_handle.find(name) != array_to_handle.end())
return array_to_handle[name];
else
return dict<int,fstHandle>();
return dict<std::vector<int>,fstHandle>();
};
static std::string remove_spaces(std::string str)
@ -213,22 +213,38 @@ void FstData::extractVarNames()
}
}
} else {
// Handle "signal [index][bitrange]" format
// 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 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);
// Parse arbitrary number of array indices
size_t open = 0;
std::vector<int> 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_to_handle[var.scope+"."+clean_name][array_index] = var.id;
array_indices.push_back(array_index);
}
}
// 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;
}
}
}

View File

@ -55,7 +55,7 @@ class FstData
std::string valueOf(fstHandle signal);
fstHandle getHandle(std::string name);
dict<int,fstHandle> getMemoryHandles(std::string name);
dict<int,fstHandle> getArrayHandles(std::string name);
dict<std::vector<int>,fstHandle> getArrayHandles(std::string name);
double getTimescale() { return timescale; }
const char *getTimescaleString() { return timescale_str.c_str(); }
int getWidth(fstHandle signal);
@ -68,7 +68,7 @@ private:
std::map<fstHandle, FstVar> handle_to_var;
std::map<std::string, fstHandle> name_to_handle;
std::map<std::string, dict<int, fstHandle>> memory_to_handle;
std::map<std::string, dict<int, fstHandle>> array_to_handle;
std::map<std::string, dict<std::vector<int>, fstHandle>> array_to_handle;
std::map<fstHandle, std::string> last_data;
uint64_t last_time;
std::map<fstHandle, std::string> past_data;

View File

@ -225,15 +225,15 @@ struct SimInstance
dict<IdString, dict<int,fstHandle>> fst_memories;
// For multi-dimensional arrays
dict<Wire*, dict<int,fstHandle>> fst_array_handles;
dict<Wire*, dict<int,fstHandle>> fst_array_inputs;
dict<Wire*, dict<std::vector<int>,fstHandle>> fst_array_handles;
dict<Wire*, dict<std::vector<int>,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<int, fstHandle> tryGetArrayHandles(FstData* fst, const std::string& scope, Wire* wire)
dict<std::vector<int>, fstHandle> tryGetArrayHandles(FstData* fst, const std::string& scope, Wire* wire)
{
std::string wire_name = scope + "." + RTLIL::unescape_id(wire->name);
dict<int, fstHandle> array_handles = fst->getArrayHandles(wire_name);
dict<std::vector<int>, fstHandle> array_handles = fst->getArrayHandles(wire_name);
if (!array_handles.empty()) {
int total_width = 0;
@ -250,25 +250,26 @@ struct SimInstance
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<int, fstHandle>();
return dict<std::vector<int>, 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<int, fstHandle>& handles)
bool setStateFromArrayHandles(Wire* wire, dict<std::vector<int>, fstHandle>& handles)
{
// Collect and sort indices in descending order (MSB = highest index)
std::vector<int> indices;
for (auto &kv : handles)
indices.push_back(kv.first);
std::sort(indices.begin(), indices.end(), std::greater<int>());
// Collect and sort indices in descending row-major orde
std::vector<std::pair<std::vector<int>, fstHandle>> sorted_elements;
for (auto &kv : handles) {
sorted_elements.push_back({kv.first, kv.second});
}
std::sort(sorted_elements.begin(), sorted_elements.end(), std::greater<>());
// Concatenate values in descending index order
std::string concatenated = "";
for (int idx : indices) {
concatenated += shared->fst->valueOf(handles[idx]);
}
return set_state(wire, Const::from_string(concatenated));
std::string concatenated = "";
for (auto &elem : sorted_elements) {
concatenated += shared->fst->valueOf(elem.second);
}
return set_state(wire, Const::from_string(concatenated));
}
SimInstance(SimShared *shared, std::string scope, Module *module, Cell *instance = nullptr, SimInstance *parent = nullptr) :