Merge pull request #133 from Silimate/sim

Better support for arrays in RTL + VCD
This commit is contained in:
Akash Levy 2026-03-30 15:12:11 -07:00 committed by GitHub
commit 5e7e172570
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 121 additions and 14 deletions

View File

@ -96,10 +96,17 @@ fstHandle FstData::getHandle(std::string name) {
return 0;
};
dict<int,fstHandle> FstData::getMemoryHandles(std::string name) {
dict<int,fstHandle> FstData::getMemoryHandles(std::string name) {
if (memory_to_handle.find(name) != memory_to_handle.end())
return memory_to_handle[name];
else
else
return dict<int,fstHandle>();
};
dict<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>();
};
@ -195,13 +202,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);
array_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);

View File

@ -55,6 +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);
double getTimescale() { return timescale; }
const char *getTimescaleString() { return timescale_str.c_str(); }
int getWidth(fstHandle signal);
@ -67,6 +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<fstHandle, std::string> last_data;
uint64_t last_time;
std::map<fstHandle, std::string> past_data;

View File

@ -224,6 +224,53 @@ struct SimInstance
dict<Wire*, fstHandle> fst_inputs;
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;
// 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)
{
std::string wire_name = scope + "." + RTLIL::unescape_id(wire->name);
dict<int, 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<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)
{
// 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>());
// 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));
}
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 +302,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<int, 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) {
// 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 +1232,10 @@ 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()) {
@ -1227,7 +1285,10 @@ 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();
@ -1523,11 +1584,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<int, 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) {
// 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;
}
}
}