2026-01-17 01:32:04 +01:00
/*
* yosys - - Yosys Open SYnthesis Suite
*
* Copyright ( C ) 2012 Claire Xenia Wolf < claire @ yosyshq . com >
* 2026 Stan Lee < stan @ silimate . com >
*
* 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"
2026-01-19 20:20:11 +01:00
# include <regex>
2026-01-17 01:32:04 +01:00
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
2026-01-19 21:58:36 +01:00
struct RegWires {
std : : vector < std : : pair < Wire * , int > > oldWires ;
int origRegWidth ;
2026-01-19 21:10:48 +01:00
} ;
2026-01-17 01:32:04 +01:00
struct RegRenamePass : public Pass {
2026-01-20 20:55:54 +01:00
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. " ) { }
2026-01-17 01:32:04 +01:00
void help ( ) override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log ( " \n " ) ;
log ( " reg_rename \n " ) ;
log ( " \n " ) ;
}
void execute ( std : : vector < std : : string > args , RTLIL : : Design * design ) override
{
log_header ( design , " Executing reg_rename pass \n " ) ;
size_t argidx ;
for ( argidx = 1 ; argidx < args . size ( ) ; argidx + + ) {
// No options currently. When adding in the future make sure to update docstring with [options]
break ;
}
extra_args ( args , argidx , design ) ;
uint32_t count = 0 ;
uint32_t moduleCount = design - > selected_modules ( ) . size ( ) ;
2026-01-19 20:20:11 +01:00
// Data structure used to keep track of multi-bit registers.
// Relevant for correct register annotation.
2026-01-19 21:22:22 +01:00
// Key is (Module*, baseName) to handle hierarchical designs where multiple modules may have same register names
2026-01-19 21:58:36 +01:00
// Value is a vector of (Wire*, index) pairs to connect the renamed registers to the corresponding index of the new wire
std : : map < std : : pair < Module * , std : : string > , RegWires > regWireMap ;
2026-01-19 20:20:11 +01:00
// Regex to match register output wires
// .*_reg[NUMBER] or .*_reg, can match NUMBER and part before _reg
std : : regex reg_regex ( " (.*)_reg(?: \\ [( \\ d+) \\ ])?$ " ) ;
2026-01-17 01:32:04 +01:00
for ( auto module : design - > selected_modules ( ) ) {
2026-01-20 20:29:56 +01:00
pool < Wire * > wiresToRemove ; // pool of wires to remove from the netlist
2026-01-17 01:32:04 +01:00
for ( auto cell : module - > selected_cells ( ) ) {
2026-01-19 20:20:11 +01:00
// 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 ( ) ;
2026-01-19 21:10:48 +01:00
2026-01-20 20:29:56 +01:00
// Check if the register is a multi-bit register (look for [NUMBER] match in regex)
2026-01-19 21:10:48 +01:00
bool isMultiBit = match . size ( ) > 2 & & match [ 2 ] . matched ;
std : : string indexStr ;
2026-01-17 01:32:04 +01:00
for ( auto conn : cell - > connections ( ) ) {
if ( conn . first = = ID : : Q & & conn . second . is_wire ( ) ) {
2026-01-20 20:29:56 +01:00
Wire * oldWire = conn . second . as_wire ( ) ;
2026-01-19 21:10:48 +01:00
2026-01-17 01:32:04 +01:00
// Skip if this wire is a module port (input/output)
2026-01-20 20:29:56 +01:00
if ( oldWire - > port_input | | oldWire - > port_output ) {
2026-01-17 01:32:04 +01:00
log ( " Skipping port wire %s in register renaming for cell %s in module %s \n " ,
2026-01-20 20:29:56 +01:00
oldWire - > name . c_str ( ) , log_id ( cell ) , log_id ( module ) ) ;
2026-01-17 01:32:04 +01:00
continue ;
}
2026-01-20 20:29:56 +01:00
// Different cases for multi-bit and single-bit registers
2026-01-19 21:10:48 +01:00
if ( isMultiBit ) {
2026-01-20 20:29:56 +01:00
2026-01-20 20:55:54 +01:00
// Index of the register
2026-01-20 20:29:56 +01:00
int index = std : : stoi ( match [ 2 ] . str ( ) ) ;
// Get or create the multi-bit wire
Wire * newWire = module - > wire ( RTLIL : : escape_id ( baseName ) ) ;
if ( newWire = = nullptr ) {
2026-01-20 20:55:54 +01:00
// Wire doesn't exist, create it with the original register width
int origRegWidth = std : : stoi ( cell - > get_string_attribute ( " $ORIG_REG_WIDTH " ) ) ;
2026-01-20 20:29:56 +01:00
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 ) ;
}
2026-01-20 20:55:54 +01:00
// Log that the new wire is being connected to the register
2026-01-20 20:29:56 +01:00
log ( " Connecting register wire %s to bit %d of %s in module %s \n " ,
2026-01-20 20:55:54 +01:00
newWire - > name . c_str ( ) , index , baseName . c_str ( ) , log_id ( module ) ) ;
2026-01-20 20:29:56 +01:00
// Replace all uses of oldWire with newWire[index]
auto rewriter = [ & ] ( SigSpec & sig ) {
sig . replace ( SigBit ( oldWire ) , SigSpec ( newWire , index , 1 ) ) ;
} ;
module - > rewrite_sigspecs ( rewriter ) ;
2026-01-19 21:10:48 +01:00
2026-01-20 20:29:56 +01:00
// Mark old wire for deletion
2026-01-20 20:55:54 +01:00
log ( " Marking old wire %s for deletion in module %s \n " ,
oldWire - > name . c_str ( ) , log_id ( module ) ) ;
2026-01-20 20:29:56 +01:00
wiresToRemove . insert ( oldWire ) ;
count + + ;
} else {
if ( oldWire - > name ! = baseName ) {
// 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 ( ) , baseName , log_id ( cell ) , log_id ( module ) ) ;
module - > rename ( oldWire , baseName ) ;
count + + ;
}
}
2026-01-17 01:32:04 +01:00
}
}
}
}
2026-01-20 20:29:56 +01:00
module - > remove ( wiresToRemove ) ;
2026-01-19 21:10:48 +01:00
}
2026-01-19 21:58:36 +01:00
// End
2026-01-17 01:32:04 +01:00
log ( " Renamed %d registers in %d modules \n " , count , moduleCount ) ;
log_flush ( ) ;
}
} RegRenamePass ;
PRIVATE_NAMESPACE_END