diff --git a/passes/cmds/splitcells.cc b/passes/cmds/splitcells.cc index c5d12413b..759e9775b 100644 --- a/passes/cmds/splitcells.cc +++ b/passes/cmds/splitcells.cc @@ -169,9 +169,21 @@ struct SplitcellsWorker int slice_msb = slices[i]-1; int slice_lsb = slices[i-1]; - IdString slice_name = module->uniquify(cell->name.str() + (slice_msb == slice_lsb ? + std::string base_name = cell->name.str(); + IdString slice_name; + if (blast) { + // Strip existing brackets from cell name + size_t bracket_pos = base_name.find('['); + if (bracket_pos != std::string::npos) { + base_name = base_name.substr(0, bracket_pos); + } + slice_name = module->uniquify(base_name + stringf( + "%c%d%c", format[0], slice_lsb, format[1])); + } else { + slice_name = module->uniquify(base_name + (slice_msb == slice_lsb ? stringf("%c%d%c", format[0], slice_lsb, format[1]) : stringf("%c%d%c%d%c", format[0], slice_msb, format[2], slice_lsb, format[1]))); + } Cell *slice = module->addCell(slice_name, cell); diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index eee162319..c029cb2df 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -257,8 +257,11 @@ struct SimInstance 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 (id==0 && wire->name.isPublic()) { log_warning("Unable to find wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(wire->name))); + } else { + log("Found wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(wire->name))); + } fst_handles[wire] = id; } @@ -2331,7 +2334,7 @@ struct VCDWriter : public OutputWriter } if (!worker->timescale.empty()) - vcdfile << stringf("$timescale %s $end\n", worker->timescale); + vcdfile << stringf("$timescale 1%s $end\n", worker->timescale); worker->top->write_output_header( [this](IdString name) { vcdfile << stringf("$scope module %s $end\n", log_id(name)); }, diff --git a/passes/silimate/Makefile.inc b/passes/silimate/Makefile.inc index e167b2813..6d40f16e8 100644 --- a/passes/silimate/Makefile.inc +++ b/passes/silimate/Makefile.inc @@ -8,6 +8,7 @@ OBJS += passes/silimate/fanoutbuf.o OBJS += passes/silimate/l2j_frontend.o OBJS += passes/silimate/obs_clean.o OBJS += passes/silimate/segv.o +OBJS += passes/silimate/reg_rename.o OBJS += passes/silimate/splitfanout.o OBJS += passes/silimate/splitlarge.o OBJS += passes/silimate/splitnetlist.o diff --git a/passes/silimate/reg_rename.cc b/passes/silimate/reg_rename.cc new file mode 100644 index 000000000..d73b2dede --- /dev/null +++ b/passes/silimate/reg_rename.cc @@ -0,0 +1,190 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Claire Xenia Wolf + * 2026 Stan Lee + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/fstdata.h" +#include + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct RegRenamePass : public Pass { + RegRenamePass() : Pass("reg_rename", "renames register output wires to the correct register name and creates new wires for multi-bit registers for correct VCD register annotations.") { } + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" reg_rename [options]\n"); + log("\n"); + log(" -vcd \n"); + log(" vcd file to extract original register width from\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) override + { + log_header(design, "Executing reg_rename pass\n"); + + + std::string vcd_filename; + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-vcd" && argidx+1 < args.size()) { + vcd_filename = args[++argidx]; + continue; + } + break; + } + extra_args(args, argidx, design); + + // Populate data structure with register widths from VCD file + dict vcd_reg_widths; + if (!vcd_filename.empty()) { + log("Reading VCD file: %s\n", vcd_filename.c_str()); + try { + FstData fst(vcd_filename); + // Iterate through all variables in the VCD file + for (auto &var : fst.getVars()) { + // Only process register variables + if (var.is_reg) { + std::string reg_name = var.name; + // Remove bracket notation if present + if (auto pos = reg_name.find('['); pos != std::string::npos) + reg_name.erase(pos); + // Add RTLIL backslash prefix if not present + if (reg_name.empty() || reg_name[0] != '\\') + reg_name = "\\" + reg_name; + vcd_reg_widths[reg_name] = var.width; + log("Found register '%s' with width %d\n", reg_name.c_str(), var.width); + } + } + log("Extracted %d register widths from VCD file\n", GetSize(vcd_reg_widths)); + } catch (const std::exception &e) { + log_error("Failed to read VCD file '%s': %s\n", vcd_filename.c_str(), e.what()); + } + } else { + log_error("No VCD file provided. Please provide a VCD file with the -vcd option.\n"); + } + + // Regex to match registers to output wires + // .*_reg[NUMBER] or .*_reg, can match NUMBER and part before _reg + std::regex reg_regex("(.*)_reg(?:\\[(\\d+)\\])?$"); + uint32_t count = 0; + for (auto module : design->selected_modules()) { + pool wiresToRemove; // pool of wires to remove from the netlist + for (auto cell : module->selected_cells()) { + + // Only check register cell + if (RTLIL::builtin_ff_cell_types().count(cell->type)) { + + // Rename register output wires to corresponding testbench names + std::smatch match; + std::string name = cell->name.c_str(); + if (std::regex_match(name, match, reg_regex)) { + + // baseName is the part before _reg + std::string baseName = match[1].str(); + + // Check if the register is a multi-bit register (look for [NUMBER] match in regex) + bool isMultiBit = match.size() > 2 && match[2].matched; + std::string indexStr; + for (auto conn : cell->connections()) { + if (conn.first == ID::Q && conn.second.is_wire()) { + Wire *oldWire = conn.second.as_wire(); + + // Skip if this wire is a module port (input/output) + if (oldWire->port_input || oldWire->port_output) { + log("Skipping port wire %s in register renaming for cell %s in module %s\n", + oldWire->name.c_str(), log_id(cell), log_id(module)); + continue; + } + + // Different cases for multi-bit and single-bit registers + if (isMultiBit) { + + // Index of the register + int index = 0; + try { + index = std::stoi(match[2].str()); + } catch (const std::exception &e) { + log_warning("Failed to convert index %s to integer in register %s: %s\n", + match[2].str().c_str(), log_id(cell), e.what()); + continue; + } + + // Get or create the multi-bit wire + Wire *newWire = module->wire(RTLIL::escape_id(baseName)); + if (newWire == nullptr) { + // Wire doesn't exist, create it with the original register width + int origRegWidth = vcd_reg_widths[baseName]; + if (origRegWidth == 0) { + log_warning("Register '%s' not found in VCD file or has width 0\n", baseName.c_str()); + continue; + } + log("Creating multi-bit wire %s with width %d in module %s\n", + baseName.c_str(), origRegWidth, log_id(module)); + newWire = module->addWire(RTLIL::escape_id(baseName), origRegWidth); + } + + // Log that the new wire is being connected to the register + log("Connecting register wire %s[%d] to bit %d of %s in module %s\n", + newWire->name.c_str(), index, index, log_id(cell), log_id(module)); + + // Replace all uses of oldWire with newWire[index] + auto rewriter = [&](SigSpec &sig) { + sig.replace(SigBit(oldWire), SigSpec(newWire, index, 1)); + }; + module->rewrite_sigspecs(rewriter); + + // Mark old wire for deletion + log("Marking old wire %s for deletion in module %s\n", + oldWire->name.c_str(), log_id(module)); + wiresToRemove.insert(oldWire); + count++; + } else { + IdString target_name = RTLIL::escape_id(baseName); + if (oldWire->name != target_name) { + // Check if target name already exists + if (module->wire(target_name)) { + log("Skipping rename: wire %s already exists in module %s\n", + target_name.c_str(), log_id(module)); + } else { + // Rename single-bit register to correct name from RTL + log("Renaming register wire %s to %s for cell %s in module %s\n", + oldWire->name.c_str(), target_name.c_str(), log_id(cell), log_id(module)); + module->rename(oldWire, target_name); + count++; + } + } + } + } + } + } + } + } + module->remove(wiresToRemove); + } + + // End + log("Renamed %d registers in %d modules\n", count, design->selected_modules().size()); + log_flush(); + } +} RegRenamePass; + +PRIVATE_NAMESPACE_END