2013-01-05 04:13:26 -06:00
/*
* yosys - - Yosys Open SYnthesis Suite
*
2021-06-07 17:39:36 -05:00
* Copyright ( C ) 2012 Claire Xenia Wolf < claire @ yosyshq . com >
2018-10-13 13:34:44 -05:00
* Copyright ( C ) 2018 Ruben Undheim < ruben . undheim @ gmail . com >
2015-07-02 04:14:30 -05:00
*
2013-01-05 04:13:26 -06:00
* 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 .
2015-07-02 04:14:30 -05:00
*
2013-01-05 04:13:26 -06:00
* 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 .
*
*/
2014-10-10 11:02:17 -05:00
# include "kernel/yosys.h"
2018-06-20 16:45:01 -05:00
# include "frontends/verific/verific.h"
2013-01-05 04:13:26 -06:00
# include <stdlib.h>
# include <stdio.h>
# include <set>
2014-10-16 11:06:54 -05:00
# ifndef _WIN32
# include <unistd.h>
# endif
2013-01-05 04:13:26 -06:00
2014-09-27 09:17:53 -05:00
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct generate_port_decl_t {
bool input , output ;
2015-01-04 04:45:39 -06:00
string portname ;
2014-09-27 09:17:53 -05:00
int index ;
} ;
2013-03-24 20:14:33 -05:00
2014-09-27 09:17:53 -05:00
void generate ( RTLIL : : Design * design , const std : : vector < std : : string > & celltypes , const std : : vector < generate_port_decl_t > & portdecls )
2013-03-24 20:14:33 -05:00
{
2014-08-02 06:11:01 -05:00
std : : set < RTLIL : : IdString > found_celltypes ;
2013-03-24 20:14:33 -05:00
2020-03-19 01:49:52 -05:00
for ( auto mod : design - > modules ( ) )
for ( auto cell : mod - > cells ( ) )
2013-03-24 20:14:33 -05:00
{
2020-03-19 01:49:52 -05:00
if ( design - > module ( cell - > type ) ! = nullptr )
2014-07-29 09:33:56 -05:00
continue ;
2019-08-06 18:42:25 -05:00
if ( cell - > type . begins_with ( " $__ " ) )
2013-03-24 20:14:33 -05:00
continue ;
for ( auto & pattern : celltypes )
2014-10-10 11:02:17 -05:00
if ( patmatch ( pattern . c_str ( ) , RTLIL : : unescape_id ( cell - > type ) . c_str ( ) ) )
2013-03-24 20:14:33 -05:00
found_celltypes . insert ( cell - > type ) ;
}
for ( auto & celltype : found_celltypes )
{
2014-08-02 06:11:01 -05:00
std : : set < RTLIL : : IdString > portnames ;
std : : set < RTLIL : : IdString > parameters ;
std : : map < RTLIL : : IdString , int > portwidths ;
2013-03-24 20:14:33 -05:00
log ( " Generate module for cell type %s: \n " , celltype . c_str ( ) ) ;
2020-03-19 01:49:52 -05:00
for ( auto mod : design - > modules ( ) )
for ( auto cell : mod - > cells ( ) )
if ( cell - > type = = celltype ) {
for ( auto & conn : cell - > connections ( ) ) {
2013-03-24 20:14:33 -05:00
if ( conn . first [ 0 ] ! = ' $ ' )
portnames . insert ( conn . first ) ;
2015-10-25 13:30:49 -05:00
portwidths [ conn . first ] = max ( portwidths [ conn . first ] , conn . second . size ( ) ) ;
2013-03-24 20:14:33 -05:00
}
2020-03-19 01:49:52 -05:00
for ( auto & para : cell - > parameters )
2013-03-26 13:11:53 -05:00
parameters . insert ( para . first ) ;
}
2013-03-24 20:14:33 -05:00
for ( auto & decl : portdecls )
if ( decl . index > 0 )
portnames . insert ( decl . portname ) ;
std : : set < int > indices ;
for ( int i = 0 ; i < int ( portnames . size ( ) ) ; i + + )
indices . insert ( i + 1 ) ;
std : : vector < generate_port_decl_t > ports ( portnames . size ( ) ) ;
for ( auto & decl : portdecls )
if ( decl . index > 0 ) {
2015-10-25 13:30:49 -05:00
portwidths [ decl . portname ] = max ( portwidths [ decl . portname ] , 1 ) ;
portwidths [ decl . portname ] = max ( portwidths [ decl . portname ] , portwidths [ stringf ( " $%d " , decl . index ) ] ) ;
2013-03-24 20:14:33 -05:00
log ( " port %d: %s [%d:0] %s \n " , decl . index , decl . input ? decl . output ? " inout " : " input " : " output " , portwidths [ decl . portname ] - 1 , RTLIL : : id2cstr ( decl . portname ) ) ;
if ( indices . count ( decl . index ) > ports . size ( ) )
log_error ( " Port index (%d) exceeds number of found ports (%d). \n " , decl . index , int ( ports . size ( ) ) ) ;
if ( indices . count ( decl . index ) = = 0 )
log_error ( " Conflict on port index %d. \n " , decl . index ) ;
indices . erase ( decl . index ) ;
portnames . erase ( decl . portname ) ;
ports [ decl . index - 1 ] = decl ;
}
while ( portnames . size ( ) > 0 ) {
2014-08-02 06:11:01 -05:00
RTLIL : : IdString portname = * portnames . begin ( ) ;
2013-03-24 20:14:33 -05:00
for ( auto & decl : portdecls )
2014-10-10 11:02:17 -05:00
if ( decl . index = = 0 & & patmatch ( decl . portname . c_str ( ) , RTLIL : : unescape_id ( portname ) . c_str ( ) ) ) {
2013-03-24 20:14:33 -05:00
generate_port_decl_t d = decl ;
2015-01-04 04:45:39 -06:00
d . portname = portname . str ( ) ;
2013-03-24 20:14:33 -05:00
d . index = * indices . begin ( ) ;
2014-07-28 04:08:55 -05:00
log_assert ( ! indices . empty ( ) ) ;
2013-03-24 20:14:33 -05:00
indices . erase ( d . index ) ;
ports [ d . index - 1 ] = d ;
2015-10-25 13:30:49 -05:00
portwidths [ d . portname ] = max ( portwidths [ d . portname ] , 1 ) ;
2013-03-24 20:14:33 -05:00
log ( " port %d: %s [%d:0] %s \n " , d . index , d . input ? d . output ? " inout " : " input " : " output " , portwidths [ d . portname ] - 1 , RTLIL : : id2cstr ( d . portname ) ) ;
goto found_matching_decl ;
}
log_error ( " Can't match port %s. \n " , RTLIL : : id2cstr ( portname ) ) ;
found_matching_decl : ;
portnames . erase ( portname ) ;
}
2014-07-28 04:08:55 -05:00
log_assert ( indices . empty ( ) ) ;
2013-03-24 20:14:33 -05:00
RTLIL : : Module * mod = new RTLIL : : Module ;
mod - > name = celltype ;
2020-04-02 11:51:32 -05:00
mod - > attributes [ ID : : blackbox ] = RTLIL : : Const ( 1 ) ;
2014-07-31 07:11:39 -05:00
design - > add ( mod ) ;
2013-03-24 20:14:33 -05:00
for ( auto & decl : ports ) {
2014-07-26 13:12:50 -05:00
RTLIL : : Wire * wire = mod - > addWire ( decl . portname , portwidths . at ( decl . portname ) ) ;
2013-03-24 20:14:33 -05:00
wire - > port_id = decl . index ;
wire - > port_input = decl . input ;
wire - > port_output = decl . output ;
}
2014-08-14 09:13:42 -05:00
mod - > fixup_ports ( ) ;
2013-03-26 13:11:53 -05:00
for ( auto & para : parameters )
log ( " ignoring parameter %s. \n " , RTLIL : : id2cstr ( para ) ) ;
2013-03-24 20:14:33 -05:00
log ( " module %s created. \n " , RTLIL : : id2cstr ( mod - > name ) ) ;
}
}
2019-02-15 13:31:37 -06:00
// Return the "basic" type for an array item.
std : : string basic_cell_type ( const std : : string celltype , int pos [ 3 ] = nullptr ) {
std : : string basicType = celltype ;
2019-08-06 21:07:45 -05:00
if ( celltype . compare ( 0 , strlen ( " $array: " ) , " $array: " ) = = 0 ) {
2019-02-15 13:31:37 -06:00
int pos_idx = celltype . find_first_of ( ' : ' ) ;
int pos_num = celltype . find_first_of ( ' : ' , pos_idx + 1 ) ;
int pos_type = celltype . find_first_of ( ' : ' , pos_num + 1 ) ;
basicType = celltype . substr ( pos_type + 1 ) ;
if ( pos ! = nullptr ) {
pos [ 0 ] = pos_idx ;
pos [ 1 ] = pos_num ;
pos [ 2 ] = pos_type ;
}
}
return basicType ;
}
2020-05-26 11:46:10 -05:00
// A helper struct for expanding a module's interface connections in expand_module
struct IFExpander
{
IFExpander ( RTLIL : : Design & design , RTLIL : : Module & m )
: module ( m ) , has_interfaces_not_found ( false )
{
// Keep track of all derived interfaces available in the current
// module in 'interfaces_in_module':
for ( auto cell : module . cells ( ) ) {
if ( ! cell - > get_bool_attribute ( ID : : is_interface ) )
continue ;
interfaces_in_module [ cell - > name ] = design . module ( cell - > type ) ;
}
}
RTLIL : : Module & module ;
dict < RTLIL : : IdString , RTLIL : : Module * > interfaces_in_module ;
bool has_interfaces_not_found ;
std : : vector < RTLIL : : IdString > connections_to_remove ;
std : : vector < RTLIL : : IdString > connections_to_add_name ;
std : : vector < RTLIL : : SigSpec > connections_to_add_signal ;
dict < RTLIL : : IdString , RTLIL : : Module * > interfaces_to_add_to_submodule ;
dict < RTLIL : : IdString , RTLIL : : IdString > modports_used_in_submodule ;
// Reset the per-cell state
void start_cell ( )
{
has_interfaces_not_found = false ;
connections_to_remove . clear ( ) ;
connections_to_add_name . clear ( ) ;
connections_to_add_signal . clear ( ) ;
interfaces_to_add_to_submodule . clear ( ) ;
modports_used_in_submodule . clear ( ) ;
}
// Set has_interfaces_not_found if there are pending interfaces that
// haven't been found yet (and might be found in the future). Print a
// warning if we've already gone over all the cells in the module.
void on_missing_interface ( RTLIL : : IdString interface_name )
{
// If there are cells that haven't yet been processed, maybe
// we'll find this interface in the future.
if ( module . get_bool_attribute ( ID : : cells_not_processed ) ) {
has_interfaces_not_found = true ;
return ;
}
// Otherwise, we have already gone over all cells in this
// module and the interface has still not been found. Warn
// about it and don't set has_interfaces_not_found (to avoid a
// loop).
log_warning ( " Could not find interface instance for `%s' in `%s' \n " ,
log_id ( interface_name ) , log_id ( & module ) ) ;
}
// Handle an interface connection from the module
void on_interface ( RTLIL : : Module & submodule ,
RTLIL : : IdString conn_name ,
const RTLIL : : SigSpec & conn_signals )
{
// Check if the connected wire is a potential interface in the parent module
std : : string interface_name_str = conn_signals . bits ( ) [ 0 ] . wire - > name . str ( ) ;
// Strip the prefix '$dummywireforinterface' from the dummy wire to get the name
interface_name_str . replace ( 0 , 23 , " " ) ;
interface_name_str = " \\ " + interface_name_str ;
RTLIL : : IdString interface_name = interface_name_str ;
// If 'interfaces' in the cell have not be been handled yet, we aren't
// ready to derive the sub-module either
if ( ! module . get_bool_attribute ( ID : : interfaces_replaced_in_module ) ) {
on_missing_interface ( interface_name ) ;
return ;
}
// Check if the interface instance is present in module. Interface
// instances may either have the plain name or the name appended with
// '_inst_from_top_dummy'. Check for both of them here
int nexactmatch = interfaces_in_module . count ( interface_name ) > 0 ;
std : : string interface_name_str2 = interface_name_str + " _inst_from_top_dummy " ;
RTLIL : : IdString interface_name2 = interface_name_str2 ;
int nmatch2 = interfaces_in_module . count ( interface_name2 ) > 0 ;
// If we can't find either name, this is a missing interface.
if ( ! ( nexactmatch | | nmatch2 ) ) {
on_missing_interface ( interface_name ) ;
return ;
}
if ( nexactmatch ! = 0 ) // Choose the one with the plain name if it exists
interface_name2 = interface_name ;
RTLIL : : Module * mod_replace_ports = interfaces_in_module . at ( interface_name2 ) ;
// Go over all wires in interface, and add replacements to lists.
for ( auto mod_wire : mod_replace_ports - > wires ( ) ) {
std : : string signal_name1 = conn_name . str ( ) + " . " + log_id ( mod_wire - > name ) ;
std : : string signal_name2 = interface_name . str ( ) + " . " + log_id ( mod_wire ) ;
connections_to_add_name . push_back ( RTLIL : : IdString ( signal_name1 ) ) ;
if ( module . wire ( signal_name2 ) = = nullptr ) {
log_error ( " Could not find signal '%s' in '%s' \n " ,
signal_name2 . c_str ( ) , log_id ( module . name ) ) ;
}
else {
RTLIL : : Wire * wire_in_parent = module . wire ( signal_name2 ) ;
connections_to_add_signal . push_back ( wire_in_parent ) ;
}
}
connections_to_remove . push_back ( conn_name ) ;
interfaces_to_add_to_submodule [ conn_name ] = interfaces_in_module . at ( interface_name2 ) ;
// Find if the sub-module has set a modport for the current interface
// connection. Add any modports to a dict which will be passed to
// AstModule::derive
string modport_name = submodule . wire ( conn_name ) - > get_string_attribute ( ID : : interface_modport ) ;
if ( ! modport_name . empty ( ) ) {
modports_used_in_submodule [ conn_name ] = " \\ " + modport_name ;
}
}
// Handle a single connection from the module, making a note to expand
// it if it's an interface connection.
void on_connection ( RTLIL : : Module & submodule ,
RTLIL : : IdString conn_name ,
const RTLIL : : SigSpec & conn_signals )
{
// Check if the connection is present as an interface in the sub-module's port list
const RTLIL : : Wire * wire = submodule . wire ( conn_name ) ;
if ( ! wire | | ! wire - > get_bool_attribute ( ID : : is_interface ) )
return ;
// If the connection looks like an interface, handle it.
const auto & bits = conn_signals . bits ( ) ;
if ( bits . size ( ) = = 1 & & bits [ 0 ] . wire - > get_bool_attribute ( ID : : is_interface ) )
on_interface ( submodule , conn_name , conn_signals ) ;
}
// Iterate over the connections in a cell, tracking any interface
// connections
void visit_connections ( const RTLIL : : Cell & cell ,
RTLIL : : Module & submodule )
{
for ( const auto & conn : cell . connections ( ) ) {
on_connection ( submodule , conn . first , conn . second ) ;
}
}
// Add/remove connections to the cell as necessary, replacing any SV
// interface port connection with the individual signal connections.
void rewrite_interface_connections ( RTLIL : : Cell & cell ) const
{
for ( unsigned int i = 0 ; i < connections_to_add_name . size ( ) ; i + + ) {
cell . connections_ [ connections_to_add_name [ i ] ] = connections_to_add_signal [ i ] ;
}
// Remove the connection for the interface itself:
for ( unsigned int i = 0 ; i < connections_to_remove . size ( ) ; i + + ) {
cell . connections_ . erase ( connections_to_remove [ i ] ) ;
}
}
} ;
2020-05-27 04:42:37 -05:00
// Get a module needed by a cell, either by deriving an abstract module or by
// loading one from a directory in libdirs.
//
// If the module can't be found and check is true then exit with an error
// message. Otherwise, return a pointer to the module if we derived or loaded
// something. or null otherwise (the module should be blackbox or we couldn't
// find it and check is not set).
RTLIL : : Module * get_module ( RTLIL : : Design & design ,
RTLIL : : Cell & cell ,
RTLIL : : Module & parent ,
bool check ,
const std : : vector < std : : string > & libdirs )
{
std : : string cell_type = cell . type . str ( ) ;
RTLIL : : Module * abs_mod = design . module ( " $abstract " + cell_type ) ;
if ( abs_mod ) {
cell . type = abs_mod - > derive ( & design , cell . parameters ) ;
cell . parameters . clear ( ) ;
RTLIL : : Module * mod = design . module ( cell . type ) ;
log_assert ( mod ) ;
return mod ;
}
// If the cell type starts with '$' and isn't '$abstract', we should
// treat it as a black box and skip.
if ( cell_type [ 0 ] = = ' $ ' )
return nullptr ;
for ( auto & dir : libdirs ) {
static const vector < pair < string , string > > extensions_list =
{
{ " .v " , " verilog " } ,
{ " .sv " , " verilog -sv " } ,
{ " .il " , " rtlil " }
} ;
for ( auto & ext : extensions_list ) {
std : : string filename = dir + " / " + RTLIL : : unescape_id ( cell . type ) + ext . first ;
if ( ! check_file_exists ( filename ) )
continue ;
Frontend : : frontend_call ( & design , NULL , filename , ext . second ) ;
RTLIL : : Module * mod = design . module ( cell . type ) ;
if ( ! mod )
log_error ( " File `%s' from libdir does not declare module `%s'. \n " ,
filename . c_str ( ) , cell_type . c_str ( ) ) ;
return mod ;
}
}
// We couldn't find the module anywhere. Complain if check is set.
if ( check )
log_error ( " Module `%s' referenced in module `%s' in cell `%s' is not part of the design. \n " ,
cell_type . c_str ( ) , parent . name . c_str ( ) , cell . name . c_str ( ) ) ;
return nullptr ;
}
2020-05-27 09:54:42 -05:00
// Try to read an IdString as a numbered connection name ("$123" or similar),
// writing the result to dst. If the string isn't of the right format, ignore
// dst and return false.
bool read_id_num ( RTLIL : : IdString str , int * dst )
{
log_assert ( dst ) ;
const char * c_str = str . c_str ( ) ;
if ( c_str [ 0 ] ! = ' $ ' | | ! ( ' 0 ' < = c_str [ 1 ] & & c_str [ 1 ] < = ' 9 ' ) )
return false ;
* dst = atoi ( c_str + 1 ) ;
return true ;
}
// Check that the connections on the cell match those that are defined
// on the type: each named connection should match the name of a port
// and each positional connection should have an index smaller than
// the number of ports.
//
// Also do the same checks on the specified parameters.
void check_cell_connections ( const RTLIL : : Module & module , RTLIL : : Cell & cell , RTLIL : : Module & mod )
{
int id ;
for ( auto & conn : cell . connections ( ) ) {
if ( read_id_num ( conn . first , & id ) ) {
if ( id < = 0 | | id > GetSize ( mod . ports ) )
log_error ( " Module `%s' referenced in module `%s' in cell `%s' "
" has only %d ports, requested port %d. \n " ,
log_id ( cell . type ) , log_id ( & module ) , log_id ( & cell ) ,
GetSize ( mod . ports ) , id ) ;
continue ;
}
const RTLIL : : Wire * wire = mod . wire ( conn . first ) ;
if ( ! wire | | wire - > port_id = = 0 ) {
log_error ( " Module `%s' referenced in module `%s' in cell `%s' "
" does not have a port named '%s'. \n " ,
log_id ( cell . type ) , log_id ( & module ) , log_id ( & cell ) ,
log_id ( conn . first ) ) ;
}
}
for ( auto & param : cell . parameters ) {
if ( read_id_num ( param . first , & id ) ) {
if ( id < = 0 | | id > GetSize ( mod . avail_parameters ) )
log_error ( " Module `%s' referenced in module `%s' in cell `%s' "
" has only %d parameters, requested parameter %d. \n " ,
log_id ( cell . type ) , log_id ( & module ) , log_id ( & cell ) ,
GetSize ( mod . avail_parameters ) , id ) ;
continue ;
}
if ( mod . avail_parameters . count ( param . first ) = = 0 & &
param . first [ 0 ] ! = ' $ ' & &
strchr ( param . first . c_str ( ) , ' . ' ) = = NULL ) {
log_error ( " Module `%s' referenced in module `%s' in cell `%s' "
" does not have a parameter named '%s'. \n " ,
log_id ( cell . type ) , log_id ( & module ) , log_id ( & cell ) ,
log_id ( param . first ) ) ;
}
}
}
2022-06-22 22:53:10 -05:00
bool expand_module ( RTLIL : : Design * design , RTLIL : : Module * module , bool flag_check , bool flag_simcheck , bool flag_smtcheck ,
std : : vector < std : : string > & libdirs )
2013-01-05 04:13:26 -06:00
{
bool did_something = false ;
2014-06-07 04:48:50 -05:00
std : : map < RTLIL : : Cell * , std : : pair < int , int > > array_cells ;
2014-01-14 12:28:20 -06:00
std : : string filename ;
2013-01-05 04:13:26 -06:00
2018-10-20 04:58:25 -05:00
bool has_interface_ports = false ;
// If any of the ports are actually interface ports, we will always need to
// reprocess the module:
2020-04-02 11:51:32 -05:00
if ( ! module - > get_bool_attribute ( ID : : interfaces_replaced_in_module ) ) {
2020-03-19 01:49:52 -05:00
for ( auto wire : module - > wires ( ) ) {
2020-03-12 14:57:01 -05:00
if ( ( wire - > port_input | | wire - > port_output ) & & wire - > get_bool_attribute ( ID : : is_interface ) )
2018-10-20 04:58:25 -05:00
has_interface_ports = true ;
}
}
2020-05-26 11:46:10 -05:00
IFExpander if_expander ( * design , * module ) ;
2018-10-11 16:33:31 -05:00
2020-03-19 01:49:52 -05:00
for ( auto cell : module - > cells ( ) )
2018-10-11 16:33:31 -05:00
{
2020-05-26 11:46:10 -05:00
if_expander . start_cell ( ) ;
2014-01-14 12:28:20 -06:00
2019-08-06 18:42:25 -05:00
if ( cell - > type . begins_with ( " $array: " ) ) {
2019-02-15 13:31:37 -06:00
int pos [ 3 ] ;
basic_cell_type ( cell - > type . str ( ) , pos ) ;
int pos_idx = pos [ 0 ] ;
int pos_num = pos [ 1 ] ;
int pos_type = pos [ 2 ] ;
2019-08-07 13:09:17 -05:00
int idx = atoi ( cell - > type . substr ( pos_idx + 1 , pos_num ) . c_str ( ) ) ;
int num = atoi ( cell - > type . substr ( pos_num + 1 , pos_type ) . c_str ( ) ) ;
2014-06-07 04:48:50 -05:00
array_cells [ cell ] = std : : pair < int , int > ( idx , num ) ;
2019-08-06 21:08:33 -05:00
cell - > type = cell - > type . substr ( pos_type + 1 ) ;
2014-06-07 04:48:50 -05:00
}
2020-05-26 11:46:10 -05:00
RTLIL : : Module * mod = design - > module ( cell - > type ) ;
2020-05-27 04:42:37 -05:00
if ( ! mod )
2014-01-14 12:28:20 -06:00
{
2022-06-22 22:53:10 -05:00
mod = get_module ( * design , * cell , * module , flag_check | | flag_simcheck | | flag_smtcheck , libdirs ) ;
2014-01-14 12:28:20 -06:00
2020-05-27 04:42:37 -05:00
// If we still don't have a module, treat the cell as a black box and skip
// it. Otherwise, we either loaded or derived something so should set the
// did_something flag before returning (to ensure we come back and expand
// the thing we just loaded).
if ( mod )
did_something = true ;
2014-01-14 12:28:20 -06:00
2013-01-05 04:13:26 -06:00
continue ;
2020-05-27 04:42:37 -05:00
}
2014-01-14 12:28:20 -06:00
2020-05-27 04:42:37 -05:00
log_assert ( mod ) ;
2018-10-11 16:33:31 -05:00
2020-05-26 11:46:10 -05:00
// Go over all connections and check if any of them are SV
// interfaces.
if_expander . visit_connections ( * cell , * mod ) ;
2018-10-11 16:33:31 -05:00
2022-06-22 22:53:10 -05:00
if ( flag_check | | flag_simcheck | | flag_smtcheck )
2020-05-27 09:54:42 -05:00
check_cell_connections ( * module , * cell , * mod ) ;
2020-05-26 11:46:10 -05:00
if ( mod - > get_blackbox_attribute ( ) ) {
2022-06-22 22:53:10 -05:00
if ( flag_simcheck | | ( flag_smtcheck & & ! mod - > get_bool_attribute ( ID : : smtlib2_module ) ) )
2019-04-18 10:42:12 -05:00
log_error ( " Module `%s' referenced in module `%s' in cell `%s' is a blackbox/whitebox module. \n " ,
2018-05-12 06:59:13 -05:00
cell - > type . c_str ( ) , module - > name . c_str ( ) , cell - > name . c_str ( ) ) ;
2013-01-05 04:13:26 -06:00
continue ;
2018-05-12 06:59:13 -05:00
}
2014-01-14 12:28:20 -06:00
2018-10-11 16:33:31 -05:00
// If interface instances not yet found, skip cell for now, and say we did something, so that we will return back here:
2020-05-26 11:46:10 -05:00
if ( if_expander . has_interfaces_not_found ) {
2018-10-11 16:33:31 -05:00
did_something = true ; // waiting for interfaces to be handled
2013-03-28 03:20:10 -05:00
continue ;
2018-10-11 16:33:31 -05:00
}
2014-01-14 12:28:20 -06:00
2020-05-26 11:46:10 -05:00
if_expander . rewrite_interface_connections ( * cell ) ;
2018-10-11 16:33:31 -05:00
// If there are no overridden parameters AND not interfaces, then we can use the existing module instance as the type
// for the cell:
2020-05-26 11:46:10 -05:00
if ( cell - > parameters . size ( ) = = 0 & &
( if_expander . interfaces_to_add_to_submodule . size ( ) = = 0 | |
! ( cell - > get_bool_attribute ( ID : : module_not_derived ) ) ) ) {
2018-10-11 16:33:31 -05:00
// If the cell being processed is an the interface instance itself, go down to "handle_interface_instance:",
// so that the signals of the interface are added to the parent module.
2020-03-12 14:57:01 -05:00
if ( mod - > get_bool_attribute ( ID : : is_interface ) ) {
2018-10-11 16:33:31 -05:00
goto handle_interface_instance ;
}
continue ;
}
2020-05-26 11:46:10 -05:00
cell - > type = mod - > derive ( design ,
cell - > parameters ,
if_expander . interfaces_to_add_to_submodule ,
if_expander . modports_used_in_submodule ) ;
2013-01-05 04:13:26 -06:00
cell - > parameters . clear ( ) ;
2013-04-26 06:28:15 -05:00
did_something = true ;
2018-10-11 16:33:31 -05:00
handle_interface_instance :
// We add all the signals of the interface explicitly to the parent module. This is always needed when we encounter
// an interface instance:
2020-04-02 11:51:32 -05:00
if ( mod - > get_bool_attribute ( ID : : is_interface ) & & cell - > get_bool_attribute ( ID : : module_not_derived ) ) {
2020-03-12 14:57:01 -05:00
cell - > set_bool_attribute ( ID : : is_interface ) ;
2020-03-19 01:49:52 -05:00
RTLIL : : Module * derived_module = design - > module ( cell - > type ) ;
2020-05-26 11:46:10 -05:00
if_expander . interfaces_in_module [ cell - > name ] = derived_module ;
2018-10-11 16:33:31 -05:00
did_something = true ;
}
2018-10-13 13:34:44 -05:00
// We clear 'module_not_derived' such that we will not rederive the cell again (needed when there are interfaces connected to the cell)
2020-04-02 11:51:32 -05:00
cell - > attributes . erase ( ID : : module_not_derived ) ;
2018-10-11 16:33:31 -05:00
}
2018-10-13 13:34:44 -05:00
// Clear the attribute 'cells_not_processed' such that it can be known that we
// have been through all cells at least once, and that we can know whether
// to flag an error because of interface instances not found:
2020-04-02 11:51:32 -05:00
module - > attributes . erase ( ID : : cells_not_processed ) ;
2018-10-11 16:33:31 -05:00
2018-10-13 13:34:44 -05:00
2018-10-20 04:58:25 -05:00
// If any interface instances or interface ports were found in the module, we need to rederive it completely:
2020-05-26 11:46:10 -05:00
if ( ( if_expander . interfaces_in_module . size ( ) > 0 | | has_interface_ports ) & & ! module - > get_bool_attribute ( ID : : interfaces_replaced_in_module ) ) {
2021-10-19 19:43:30 -05:00
module - > expand_interfaces ( design , if_expander . interfaces_in_module ) ;
2018-10-11 16:33:31 -05:00
return did_something ;
2013-01-05 04:13:26 -06:00
}
2021-10-19 19:46:26 -05:00
// Now that modules have been derived, we may want to reprocess this
// module given the additional available context.
if ( module - > reprocess_if_necessary ( design ) )
return true ;
2018-10-11 16:33:31 -05:00
2014-06-07 04:48:50 -05:00
for ( auto & it : array_cells )
{
RTLIL : : Cell * cell = it . first ;
int idx = it . second . first , num = it . second . second ;
2020-03-19 01:49:52 -05:00
if ( design - > module ( cell - > type ) = = nullptr )
2014-09-06 01:47:06 -05:00
log_error ( " Array cell `%s.%s' of unknown type `%s'. \n " , RTLIL : : id2cstr ( module - > name ) , RTLIL : : id2cstr ( cell - > name ) , RTLIL : : id2cstr ( cell - > type ) ) ;
2014-06-07 04:48:50 -05:00
2020-03-19 01:49:52 -05:00
RTLIL : : Module * mod = design - > module ( cell - > type ) ;
2014-06-07 04:48:50 -05:00
2014-07-26 08:57:57 -05:00
for ( auto & conn : cell - > connections_ ) {
2014-07-22 13:15:14 -05:00
int conn_size = conn . second . size ( ) ;
2014-08-02 06:11:01 -05:00
RTLIL : : IdString portname = conn . first ;
2019-08-06 18:42:25 -05:00
if ( portname . begins_with ( " $ " ) ) {
2019-08-07 13:09:17 -05:00
int port_id = atoi ( portname . substr ( 1 ) . c_str ( ) ) ;
2020-03-19 01:49:52 -05:00
for ( auto wire : mod - > wires ( ) )
if ( wire - > port_id = = port_id ) {
portname = wire - > name ;
2014-06-07 05:17:06 -05:00
break ;
}
}
2020-03-19 01:49:52 -05:00
if ( mod - > wire ( portname ) = = nullptr )
2014-09-06 01:47:06 -05:00
log_error ( " Array cell `%s.%s' connects to unknown port `%s'. \n " , RTLIL : : id2cstr ( module - > name ) , RTLIL : : id2cstr ( cell - > name ) , RTLIL : : id2cstr ( conn . first ) ) ;
2020-03-19 01:49:52 -05:00
int port_size = mod - > wire ( portname ) - > width ;
2018-05-31 11:09:31 -05:00
if ( conn_size = = port_size | | conn_size = = 0 )
2014-06-07 04:48:50 -05:00
continue ;
if ( conn_size ! = port_size * num )
log_error ( " Array cell `%s.%s' has invalid port vs. signal size for port `%s'. \n " , RTLIL : : id2cstr ( module - > name ) , RTLIL : : id2cstr ( cell - > name ) , RTLIL : : id2cstr ( conn . first ) ) ;
conn . second = conn . second . extract ( port_size * idx , port_size ) ;
}
}
2013-01-05 04:13:26 -06:00
return did_something ;
}
2016-05-22 09:37:47 -05:00
void hierarchy_worker ( RTLIL : : Design * design , std : : set < RTLIL : : Module * , IdString : : compare_ptr_by_name < Module > > & used , RTLIL : : Module * mod , int indent )
2013-01-05 04:13:26 -06:00
{
if ( used . count ( mod ) > 0 )
return ;
2013-05-26 05:20:51 -05:00
if ( indent = = 0 )
log ( " Top module: %s \n " , mod - > name . c_str ( ) ) ;
2019-04-18 10:42:12 -05:00
else if ( ! mod - > get_blackbox_attribute ( ) )
2013-05-26 05:20:51 -05:00
log ( " Used module: %*s%s \n " , indent , " " , mod - > name . c_str ( ) ) ;
2013-01-05 04:13:26 -06:00
used . insert ( mod ) ;
2014-11-27 05:47:33 -06:00
for ( auto cell : mod - > cells ( ) ) {
std : : string celltype = cell - > type . str ( ) ;
2019-08-06 21:07:45 -05:00
if ( celltype . compare ( 0 , strlen ( " $array: " ) , " $array: " ) = = 0 )
2019-02-15 13:31:37 -06:00
celltype = basic_cell_type ( celltype ) ;
2014-11-27 05:47:33 -06:00
if ( design - > module ( celltype ) )
hierarchy_worker ( design , used , design - > module ( celltype ) , indent + 4 ) ;
2013-01-05 04:13:26 -06:00
}
}
2015-03-04 08:52:34 -06:00
void hierarchy_clean ( RTLIL : : Design * design , RTLIL : : Module * top , bool purge_lib )
2013-01-05 04:13:26 -06:00
{
2016-05-22 09:37:47 -05:00
std : : set < RTLIL : : Module * , IdString : : compare_ptr_by_name < Module > > used ;
2013-05-26 05:20:51 -05:00
hierarchy_worker ( design , used , top , 0 ) ;
2013-01-05 04:13:26 -06:00
std : : vector < RTLIL : : Module * > del_modules ;
2020-03-19 01:49:52 -05:00
for ( auto mod : design - > modules ( ) )
if ( used . count ( mod ) = = 0 )
del_modules . push_back ( mod ) ;
2018-10-20 04:58:25 -05:00
else {
// Now all interface ports must have been exploded, and it is hence
// safe to delete all of the remaining dummy interface ports:
pool < RTLIL : : Wire * > del_wires ;
2020-03-19 01:49:52 -05:00
for ( auto wire : mod - > wires ( ) ) {
2020-03-12 14:57:01 -05:00
if ( ( wire - > port_input | | wire - > port_output ) & & wire - > get_bool_attribute ( ID : : is_interface ) ) {
2020-03-19 01:49:52 -05:00
del_wires . insert ( wire ) ;
2018-10-20 04:58:25 -05:00
}
}
if ( del_wires . size ( ) > 0 ) {
2020-03-19 01:49:52 -05:00
mod - > remove ( del_wires ) ;
mod - > fixup_ports ( ) ;
2018-10-20 04:58:25 -05:00
}
}
2013-01-05 04:13:26 -06:00
2015-02-15 05:57:41 -06:00
int del_counter = 0 ;
2013-01-05 04:13:26 -06:00
for ( auto mod : del_modules ) {
2019-04-18 10:42:12 -05:00
if ( ! purge_lib & & mod - > get_blackbox_attribute ( ) )
2014-02-04 09:50:13 -06:00
continue ;
2013-01-05 04:13:26 -06:00
log ( " Removing unused module `%s'. \n " , mod - > name . c_str ( ) ) ;
2020-03-19 01:49:52 -05:00
design - > remove ( mod ) ;
2015-02-15 05:57:41 -06:00
del_counter + + ;
2013-01-05 04:13:26 -06:00
}
2015-02-15 05:57:41 -06:00
log ( " Removed %d unused modules. \n " , del_counter ) ;
2013-01-05 04:13:26 -06:00
}
2024-01-19 08:23:08 -06:00
bool set_keep_print ( std : : map < RTLIL : : Module * , bool > & cache , RTLIL : : Module * mod )
{
if ( cache . count ( mod ) = = 0 )
for ( auto c : mod - > cells ( ) ) {
RTLIL : : Module * m = mod - > design - > module ( c - > type ) ;
if ( ( m ! = nullptr & & set_keep_print ( cache , m ) ) | | c - > type = = ID ( $ print ) )
return cache [ mod ] = true ;
}
return cache [ mod ] ;
}
2014-09-30 12:16:40 -05:00
bool set_keep_assert ( std : : map < RTLIL : : Module * , bool > & cache , RTLIL : : Module * mod )
{
if ( cache . count ( mod ) = = 0 )
for ( auto c : mod - > cells ( ) ) {
RTLIL : : Module * m = mod - > design - > module ( c - > type ) ;
2024-01-11 03:39:28 -06:00
if ( ( m ! = nullptr & & set_keep_assert ( cache , m ) ) | | c - > type . in ( ID ( $ check ) , ID ( $ assert ) , ID ( $ assume ) , ID ( $ live ) , ID ( $ fair ) , ID ( $ cover ) ) )
2014-09-30 12:16:40 -05:00
return cache [ mod ] = true ;
}
return cache [ mod ] ;
}
2015-03-18 02:33:40 -05:00
int find_top_mod_score ( Design * design , Module * module , dict < Module * , int > & db )
{
if ( db . count ( module ) = = 0 ) {
2016-08-16 02:07:13 -05:00
int score = 0 ;
2015-03-18 02:33:40 -05:00
db [ module ] = 0 ;
2019-02-15 13:31:37 -06:00
for ( auto cell : module - > cells ( ) ) {
std : : string celltype = cell - > type . str ( ) ;
// Is this an array instance
2019-08-06 21:07:45 -05:00
if ( celltype . compare ( 0 , strlen ( " $array: " ) , " $array: " ) = = 0 )
2019-02-15 13:31:37 -06:00
celltype = basic_cell_type ( celltype ) ;
2019-02-19 16:35:15 -06:00
// Is this cell a module instance?
2019-02-22 18:06:10 -06:00
auto instModule = design - > module ( celltype ) ;
// If there is no instance for this, issue a warning.
2019-02-24 13:41:36 -06:00
if ( instModule ! = nullptr ) {
2019-02-22 18:06:10 -06:00
score = max ( score , find_top_mod_score ( design , instModule , db ) + 1 ) ;
2019-02-15 13:31:37 -06:00
}
}
2016-08-16 02:07:13 -05:00
db [ module ] = score ;
2015-03-18 02:33:40 -05:00
}
return db . at ( module ) ;
}
2018-10-11 16:33:31 -05:00
RTLIL : : Module * check_if_top_has_changed ( Design * design , Module * top_mod )
{
2020-03-12 14:57:01 -05:00
if ( top_mod ! = NULL & & top_mod - > get_bool_attribute ( ID : : initial_top ) )
2018-10-11 16:33:31 -05:00
return top_mod ;
else {
for ( auto mod : design - > modules ( ) ) {
2020-03-12 14:57:01 -05:00
if ( mod - > get_bool_attribute ( ID : : top ) ) {
2018-10-11 16:33:31 -05:00
return mod ;
}
}
}
return NULL ;
}
2019-11-22 03:04:54 -06:00
// Find a matching wire for an implicit port connection; traversing generate block scope
RTLIL : : Wire * find_implicit_port_wire ( Module * module , Cell * cell , const std : : string & port )
{
const std : : string & cellname = cell - > name . str ( ) ;
size_t idx = cellname . size ( ) ;
while ( ( idx = cellname . find_last_of ( ' . ' , idx - 1 ) ) ! = std : : string : : npos ) {
Wire * found = module - > wire ( cellname . substr ( 0 , idx + 1 ) + port . substr ( 1 ) ) ;
if ( found ! = nullptr )
return found ;
}
return module - > wire ( port ) ;
}
2013-01-05 04:13:26 -06:00
struct HierarchyPass : public Pass {
2013-02-28 06:59:49 -06:00
HierarchyPass ( ) : Pass ( " hierarchy " , " check, expand and clean up design hierarchy " ) { }
2020-06-18 18:34:52 -05:00
void help ( ) override
2013-02-28 06:59:49 -06:00
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log ( " \n " ) ;
log ( " hierarchy [-check] [-top <module>] \n " ) ;
2013-03-24 20:14:33 -05:00
log ( " hierarchy -generate <cell-types> <port-decls> \n " ) ;
2013-02-28 06:59:49 -06:00
log ( " \n " ) ;
2014-09-06 01:47:06 -05:00
log ( " In parametric designs, a module might exists in several variations with \n " ) ;
2013-02-28 06:59:49 -06:00
log ( " different parameter values. This pass looks at all modules in the current \n " ) ;
2020-05-28 05:39:44 -05:00
log ( " design and re-runs the language frontends for the parametric modules as \n " ) ;
2019-05-28 09:43:25 -05:00
log ( " needed. It also resolves assignments to wired logic data types (wand/wor), \n " ) ;
2020-05-28 05:39:44 -05:00
log ( " resolves positional module parameters, unrolls array instances, and more. \n " ) ;
2013-02-28 06:59:49 -06:00
log ( " \n " ) ;
log ( " -check \n " ) ;
log ( " also check the design hierarchy. this generates an error when \n " ) ;
log ( " an unknown module is used as cell type. \n " ) ;
log ( " \n " ) ;
2018-05-12 06:59:13 -05:00
log ( " -simcheck \n " ) ;
2018-12-07 13:14:07 -06:00
log ( " like -check, but also throw an error if blackbox modules are \n " ) ;
2019-03-13 14:42:18 -05:00
log ( " instantiated, and throw an error if the design has no top module. \n " ) ;
2018-05-12 06:59:13 -05:00
log ( " \n " ) ;
2022-06-22 22:53:10 -05:00
log ( " -smtcheck \n " ) ;
log ( " like -simcheck, but allow smtlib2_module modules. \n " ) ;
log ( " \n " ) ;
2014-02-04 09:50:13 -06:00
log ( " -purge_lib \n " ) ;
log ( " by default the hierarchy command will not remove library (blackbox) \n " ) ;
2015-03-29 13:22:08 -05:00
log ( " modules. use this option to also remove unused blackbox modules. \n " ) ;
2014-02-04 09:50:13 -06:00
log ( " \n " ) ;
2014-01-14 12:28:20 -06:00
log ( " -libdir <directory> \n " ) ;
log ( " search for files named <module_name>.v in the specified directory \n " ) ;
2014-09-06 01:47:06 -05:00
log ( " for unknown modules and automatically run read_verilog for each \n " ) ;
2014-01-14 12:28:20 -06:00
log ( " unknown module. \n " ) ;
log ( " \n " ) ;
2013-11-03 02:42:51 -06:00
log ( " -keep_positionals \n " ) ;
log ( " per default this pass also converts positional arguments in cells \n " ) ;
2019-03-13 14:42:18 -05:00
log ( " to arguments using port names. This option disables this behavior. \n " ) ;
2013-11-03 02:42:51 -06:00
log ( " \n " ) ;
2017-01-01 15:52:52 -06:00
log ( " -keep_portwidths \n " ) ;
log ( " per default this pass adjusts the port width on cells that are \n " ) ;
2019-03-13 14:42:18 -05:00
log ( " module instances when the width does not match the module port. This \n " ) ;
2017-01-01 15:52:52 -06:00
log ( " option disables this behavior. \n " ) ;
log ( " \n " ) ;
2019-06-19 04:49:20 -05:00
log ( " -nodefaults \n " ) ;
log ( " do not resolve input port default values \n " ) ;
log ( " \n " ) ;
2024-01-19 08:23:08 -06:00
log ( " -nokeep_prints \n " ) ;
log ( " per default this pass sets the \" keep \" attribute on all modules \n " ) ;
log ( " that directly or indirectly display text on the terminal. \n " ) ;
log ( " This option disables this behavior. \n " ) ;
log ( " \n " ) ;
2014-09-30 12:16:40 -05:00
log ( " -nokeep_asserts \n " ) ;
log ( " per default this pass sets the \" keep \" attribute on all modules \n " ) ;
2019-05-03 15:03:43 -05:00
log ( " that directly or indirectly contain one or more formal properties. \n " ) ;
log ( " This option disables this behavior. \n " ) ;
2014-09-30 12:16:40 -05:00
log ( " \n " ) ;
2013-02-28 06:59:49 -06:00
log ( " -top <module> \n " ) ;
2019-03-13 14:42:18 -05:00
log ( " use the specified top module to build the design hierarchy. Modules \n " ) ;
2013-02-28 06:59:49 -06:00
log ( " outside this tree (unused modules) are removed. \n " ) ;
log ( " \n " ) ;
2013-11-23 22:03:43 -06:00
log ( " when the -top option is used, the 'top' attribute will be set on the \n " ) ;
log ( " specified top module. otherwise a module with the 'top' attribute set \n " ) ;
log ( " will implicitly be used as top module, if such a module exists. \n " ) ;
log ( " \n " ) ;
2015-03-18 02:33:40 -05:00
log ( " -auto-top \n " ) ;
log ( " automatically determine the top of the design hierarchy and mark it. \n " ) ;
log ( " \n " ) ;
2019-03-13 14:42:18 -05:00
log ( " -chparam name value \n " ) ;
log ( " elaborate the top module using this parameter value. Modules on which \n " ) ;
log ( " this parameter does not exist may cause a warning message to be output. \n " ) ;
log ( " This option can be specified multiple times to override multiple \n " ) ;
log ( " parameters. String values must be passed in double quotes ( \" ). \n " ) ;
log ( " \n " ) ;
2013-11-22 08:01:12 -06:00
log ( " In -generate mode this pass generates blackbox modules for the given cell \n " ) ;
2013-03-24 20:14:33 -05:00
log ( " types (wildcards supported). For this the design is searched for cells that \n " ) ;
log ( " match the given types and then the given port declarations are used to \n " ) ;
log ( " determine the direction of the ports. The syntax for a port declaration is: \n " ) ;
log ( " \n " ) ;
log ( " {i|o|io}[@<num>]:<portname> \n " ) ;
log ( " \n " ) ;
log ( " Input ports are specified with the 'i' prefix, output ports with the 'o' \n " ) ;
log ( " prefix and inout ports with the 'io' prefix. The optional <num> specifies \n " ) ;
2015-08-14 03:56:05 -05:00
log ( " the position of the port in the parameter list (needed when instantiated \n " ) ;
2013-03-24 20:14:33 -05:00
log ( " using positional arguments). When <num> is not specified, the <portname> can \n " ) ;
log ( " also contain wildcard characters. \n " ) ;
log ( " \n " ) ;
2013-02-28 06:59:49 -06:00
log ( " This pass ignores the current selection and always operates on all modules \n " ) ;
log ( " in the current design. \n " ) ;
log ( " \n " ) ;
}
2020-06-18 18:34:52 -05:00
void execute ( std : : vector < std : : string > args , RTLIL : : Design * design ) override
2013-01-05 04:13:26 -06:00
{
2016-04-21 16:28:37 -05:00
log_header ( design , " Executing HIERARCHY pass (managing design hierarchy). \n " ) ;
2013-01-05 04:13:26 -06:00
bool flag_check = false ;
2018-05-12 06:59:13 -05:00
bool flag_simcheck = false ;
2022-06-22 22:53:10 -05:00
bool flag_smtcheck = false ;
2014-02-04 09:50:13 -06:00
bool purge_lib = false ;
2013-01-05 04:13:26 -06:00
RTLIL : : Module * top_mod = NULL ;
2018-06-20 16:45:01 -05:00
std : : string load_top_mod ;
2014-01-14 12:28:20 -06:00
std : : vector < std : : string > libdirs ;
2013-01-05 04:13:26 -06:00
2015-03-18 02:33:40 -05:00
bool auto_top_mode = false ;
2013-03-24 20:14:33 -05:00
bool generate_mode = false ;
2013-11-03 02:42:51 -06:00
bool keep_positionals = false ;
2017-01-01 15:52:52 -06:00
bool keep_portwidths = false ;
2019-06-19 04:49:20 -05:00
bool nodefaults = false ;
2024-01-19 08:23:08 -06:00
bool nokeep_prints = false ;
2014-09-30 12:16:40 -05:00
bool nokeep_asserts = false ;
2013-03-24 20:14:33 -05:00
std : : vector < std : : string > generate_cells ;
std : : vector < generate_port_decl_t > generate_ports ;
2019-03-13 14:42:18 -05:00
std : : map < std : : string , std : : string > parameters ;
2013-03-24 20:14:33 -05:00
2013-01-05 04:13:26 -06:00
size_t argidx ;
for ( argidx = 1 ; argidx < args . size ( ) ; argidx + + )
{
2022-06-22 22:53:10 -05:00
if ( args [ argidx ] = = " -generate " & & ! flag_check & & ! flag_simcheck & & ! flag_smtcheck & & ! top_mod ) {
2013-03-24 20:14:33 -05:00
generate_mode = true ;
log ( " Entering generate mode. \n " ) ;
while ( + + argidx < args . size ( ) ) {
const char * p = args [ argidx ] . c_str ( ) ;
generate_port_decl_t decl ;
if ( p [ 0 ] = = ' i ' & & p [ 1 ] = = ' o ' )
decl . input = true , decl . output = true , p + = 2 ;
else if ( * p = = ' i ' )
decl . input = true , decl . output = false , p + + ;
else if ( * p = = ' o ' )
decl . input = false , decl . output = true , p + + ;
else
goto is_celltype ;
if ( * p = = ' @ ' ) {
char * endptr ;
decl . index = strtol ( + + p , & endptr , 10 ) ;
if ( decl . index < 1 )
goto is_celltype ;
p = endptr ;
} else
decl . index = 0 ;
if ( * ( p + + ) ! = ' : ' )
goto is_celltype ;
if ( * p = = 0 )
goto is_celltype ;
decl . portname = p ;
log ( " Port declaration: %s " , decl . input ? decl . output ? " inout " : " input " : " output " ) ;
if ( decl . index > = 1 )
log ( " [at position %d] " , decl . index ) ;
log ( " %s \n " , decl . portname . c_str ( ) ) ;
generate_ports . push_back ( decl ) ;
continue ;
is_celltype :
log ( " Celltype: %s \n " , args [ argidx ] . c_str ( ) ) ;
generate_cells . push_back ( RTLIL : : unescape_id ( args [ argidx ] ) ) ;
}
continue ;
}
2013-01-05 04:13:26 -06:00
if ( args [ argidx ] = = " -check " ) {
flag_check = true ;
continue ;
}
2018-05-12 06:59:13 -05:00
if ( args [ argidx ] = = " -simcheck " ) {
flag_simcheck = true ;
continue ;
}
2022-06-22 22:53:10 -05:00
if ( args [ argidx ] = = " -smtcheck " ) {
flag_smtcheck = true ;
continue ;
}
2014-02-04 09:50:13 -06:00
if ( args [ argidx ] = = " -purge_lib " ) {
purge_lib = true ;
continue ;
}
2013-11-03 02:42:51 -06:00
if ( args [ argidx ] = = " -keep_positionals " ) {
keep_positionals = true ;
continue ;
}
2017-01-01 15:52:52 -06:00
if ( args [ argidx ] = = " -keep_portwidths " ) {
keep_portwidths = true ;
continue ;
}
2019-06-19 04:49:20 -05:00
if ( args [ argidx ] = = " -nodefaults " ) {
nodefaults = true ;
continue ;
}
2024-01-19 08:23:08 -06:00
if ( args [ argidx ] = = " -nokeep_prints " ) {
nokeep_prints = true ;
continue ;
}
2014-09-30 12:16:40 -05:00
if ( args [ argidx ] = = " -nokeep_asserts " ) {
nokeep_asserts = true ;
continue ;
}
2014-01-14 12:28:20 -06:00
if ( args [ argidx ] = = " -libdir " & & argidx + 1 < args . size ( ) ) {
libdirs . push_back ( args [ + + argidx ] ) ;
continue ;
}
2013-01-05 04:13:26 -06:00
if ( args [ argidx ] = = " -top " ) {
if ( + + argidx > = args . size ( ) )
log_cmd_error ( " Option -top requires an additional argument! \n " ) ;
2019-05-03 15:03:43 -05:00
load_top_mod = args [ argidx ] ;
2013-01-05 04:13:26 -06:00
continue ;
}
2015-03-18 02:33:40 -05:00
if ( args [ argidx ] = = " -auto-top " ) {
auto_top_mode = true ;
continue ;
}
2019-03-13 14:42:18 -05:00
if ( args [ argidx ] = = " -chparam " & & argidx + 2 < args . size ( ) ) {
const std : : string & key = args [ + + argidx ] ;
const std : : string & value = args [ + + argidx ] ;
auto r = parameters . emplace ( key , value ) ;
if ( ! r . second ) {
2019-03-14 10:29:43 -05:00
log_warning ( " -chparam %s already specified: overwriting. \n " , key . c_str ( ) ) ;
2019-03-13 14:42:18 -05:00
r . first - > second = value ;
}
continue ;
}
2013-03-03 03:05:37 -06:00
break ;
2013-01-05 04:13:26 -06:00
}
2013-03-03 03:05:37 -06:00
extra_args ( args , argidx , design , false ) ;
2013-01-05 04:13:26 -06:00
2019-05-03 15:03:43 -05:00
if ( ! load_top_mod . empty ( ) )
{
IdString top_name = RTLIL : : escape_id ( load_top_mod ) ;
IdString abstract_id = " $abstract " + RTLIL : : escape_id ( load_top_mod ) ;
top_mod = design - > module ( top_name ) ;
dict < RTLIL : : IdString , RTLIL : : Const > top_parameters ;
2020-09-25 04:40:37 -05:00
if ( ( top_mod = = nullptr & & design - > module ( abstract_id ) ) | | top_mod ! = nullptr ) {
for ( auto & para : parameters ) {
SigSpec sig_value ;
if ( ! RTLIL : : SigSpec : : parse ( sig_value , NULL , para . second ) )
log_cmd_error ( " Can't decode value '%s'! \n " , para . second . c_str ( ) ) ;
top_parameters [ RTLIL : : escape_id ( para . first ) ] = sig_value . as_const ( ) ;
}
2019-05-03 15:03:43 -05:00
}
if ( top_mod = = nullptr & & design - > module ( abstract_id ) )
top_mod = design - > module ( design - > module ( abstract_id ) - > derive ( design , top_parameters ) ) ;
else if ( top_mod ! = nullptr & & ! top_parameters . empty ( ) )
top_mod = design - > module ( top_mod - > derive ( design , top_parameters ) ) ;
if ( top_mod ! = nullptr & & top_mod - > name ! = top_name ) {
Module * m = top_mod - > clone ( ) ;
m - > name = top_name ;
Module * old_mod = design - > module ( top_name ) ;
if ( old_mod )
design - > remove ( old_mod ) ;
design - > add ( m ) ;
top_mod = m ;
}
}
if ( top_mod = = nullptr & & ! load_top_mod . empty ( ) ) {
2018-06-20 16:45:01 -05:00
# ifdef YOSYS_ENABLE_VERIFIC
if ( verific_import_pending ) {
2022-11-25 06:02:11 -06:00
load_top_mod = verific_import ( design , parameters , load_top_mod ) ;
2018-06-20 16:45:01 -05:00
top_mod = design - > module ( RTLIL : : escape_id ( load_top_mod ) ) ;
}
# endif
if ( top_mod = = NULL )
log_cmd_error ( " Module `%s' not found! \n " , load_top_mod . c_str ( ) ) ;
} else {
# ifdef YOSYS_ENABLE_VERIFIC
if ( verific_import_pending )
2019-03-13 14:42:18 -05:00
verific_import ( design , parameters ) ;
2018-06-20 16:45:01 -05:00
# endif
}
2013-03-24 20:14:33 -05:00
if ( generate_mode ) {
generate ( design , generate_cells , generate_ports ) ;
return ;
}
2013-05-26 05:20:51 -05:00
log_push ( ) ;
2015-03-18 02:33:40 -05:00
if ( top_mod = = nullptr )
2020-03-19 01:49:52 -05:00
for ( auto mod : design - > modules ( ) )
2020-03-12 14:57:01 -05:00
if ( mod - > get_bool_attribute ( ID : : top ) )
2020-03-19 01:49:52 -05:00
top_mod = mod ;
2013-11-23 22:03:43 -06:00
2022-04-05 07:02:37 -05:00
if ( top_mod = = nullptr & & auto_top_mode ) {
log_header ( design , " Finding top of design hierarchy.. \n " ) ;
dict < Module * , int > db ;
for ( Module * mod : design - > selected_modules ( ) ) {
int score = find_top_mod_score ( design , mod , db ) ;
log ( " root of %3d design levels: %-20s \n " , score , log_id ( mod ) ) ;
if ( ! top_mod | | score > db [ top_mod ] )
top_mod = mod ;
}
if ( top_mod ! = nullptr )
log ( " Automatically selected %s as design top module. \n " , log_id ( top_mod ) ) ;
}
2019-09-03 14:18:50 -05:00
if ( top_mod ! = nullptr & & top_mod - > name . begins_with ( " $abstract " ) ) {
IdString top_name = top_mod - > name . substr ( strlen ( " $abstract " ) ) ;
2019-08-28 21:59:25 -05:00
dict < RTLIL : : IdString , RTLIL : : Const > top_parameters ;
for ( auto & para : parameters ) {
SigSpec sig_value ;
if ( ! RTLIL : : SigSpec : : parse ( sig_value , NULL , para . second ) )
log_cmd_error ( " Can't decode value '%s'! \n " , para . second . c_str ( ) ) ;
top_parameters [ RTLIL : : escape_id ( para . first ) ] = sig_value . as_const ( ) ;
}
2019-09-03 14:18:50 -05:00
top_mod = design - > module ( top_mod - > derive ( design , top_parameters ) ) ;
2019-08-28 21:59:25 -05:00
if ( top_mod ! = nullptr & & top_mod - > name ! = top_name ) {
Module * m = top_mod - > clone ( ) ;
m - > name = top_name ;
Module * old_mod = design - > module ( top_name ) ;
if ( old_mod )
design - > remove ( old_mod ) ;
design - > add ( m ) ;
top_mod = m ;
}
}
2022-06-22 22:53:10 -05:00
if ( ( flag_simcheck | | flag_smtcheck ) & & top_mod = = nullptr )
2018-05-12 06:59:13 -05:00
log_error ( " Design has no top module. \n " ) ;
2018-10-11 16:33:31 -05:00
if ( top_mod ! = NULL ) {
2020-03-19 01:49:52 -05:00
for ( auto mod : design - > modules ( ) )
if ( mod = = top_mod )
2020-03-12 14:57:01 -05:00
mod - > attributes [ ID : : initial_top ] = RTLIL : : Const ( 1 ) ;
2018-10-11 16:33:31 -05:00
else
2020-03-12 14:57:01 -05:00
mod - > attributes . erase ( ID : : initial_top ) ;
2018-10-11 16:33:31 -05:00
}
2013-01-05 04:13:26 -06:00
bool did_something = true ;
2015-03-04 08:52:34 -06:00
while ( did_something )
{
2013-01-05 04:13:26 -06:00
did_something = false ;
2015-03-04 08:52:34 -06:00
2016-05-22 09:37:47 -05:00
std : : set < RTLIL : : Module * , IdString : : compare_ptr_by_name < Module > > used_modules ;
2015-03-04 08:52:34 -06:00
if ( top_mod ! = NULL ) {
2016-04-21 16:28:37 -05:00
log_header ( design , " Analyzing design hierarchy.. \n " ) ;
2015-03-04 08:52:34 -06:00
hierarchy_worker ( design , used_modules , top_mod , 0 ) ;
} else {
for ( auto mod : design - > modules ( ) )
used_modules . insert ( mod ) ;
}
for ( auto module : used_modules ) {
2022-06-22 22:53:10 -05:00
if ( expand_module ( design , module , flag_check , flag_simcheck , flag_smtcheck , libdirs ) )
2013-01-05 04:13:26 -06:00
did_something = true ;
}
2018-10-11 16:33:31 -05:00
2018-10-13 13:34:44 -05:00
// The top module might have changed if interface instances have been detected in it:
2018-10-11 16:33:31 -05:00
RTLIL : : Module * tmp_top_mod = check_if_top_has_changed ( design , top_mod ) ;
if ( tmp_top_mod ! = NULL ) {
if ( tmp_top_mod ! = top_mod ) {
top_mod = tmp_top_mod ;
2022-08-26 10:12:56 -05:00
top_mod - > attributes [ ID : : initial_top ] = RTLIL : : Const ( 1 ) ;
2018-10-11 16:33:31 -05:00
did_something = true ;
}
}
2018-10-13 13:34:44 -05:00
// Delete modules marked as 'to_delete':
2018-10-11 16:33:31 -05:00
std : : vector < RTLIL : : Module * > modules_to_delete ;
2020-03-19 01:49:52 -05:00
for ( auto mod : design - > modules ( ) ) {
2020-04-02 11:51:32 -05:00
if ( mod - > get_bool_attribute ( ID : : to_delete ) ) {
2020-03-19 01:49:52 -05:00
modules_to_delete . push_back ( mod ) ;
2018-10-11 16:33:31 -05:00
}
}
for ( size_t i = 0 ; i < modules_to_delete . size ( ) ; i + + ) {
design - > remove ( modules_to_delete [ i ] ) ;
}
2013-01-05 04:13:26 -06:00
}
2018-10-11 16:33:31 -05:00
2015-03-04 08:52:34 -06:00
if ( top_mod ! = NULL ) {
2016-04-21 16:28:37 -05:00
log_header ( design , " Analyzing design hierarchy.. \n " ) ;
2015-03-04 08:52:34 -06:00
hierarchy_clean ( design , top_mod , purge_lib ) ;
2013-05-26 05:20:51 -05:00
}
2013-11-23 22:03:43 -06:00
if ( top_mod ! = NULL ) {
2020-03-19 01:49:52 -05:00
for ( auto mod : design - > modules ( ) ) {
if ( mod = = top_mod )
2020-03-12 14:57:01 -05:00
mod - > attributes [ ID : : top ] = RTLIL : : Const ( 1 ) ;
2013-11-23 22:03:43 -06:00
else
2020-03-12 14:57:01 -05:00
mod - > attributes . erase ( ID : : top ) ;
mod - > attributes . erase ( ID : : initial_top ) ;
2018-10-11 16:33:31 -05:00
}
2013-11-23 22:03:43 -06:00
}
2024-01-19 08:23:08 -06:00
if ( ! nokeep_prints ) {
std : : map < RTLIL : : Module * , bool > cache ;
for ( auto mod : design - > modules ( ) )
if ( set_keep_print ( cache , mod ) ) {
log ( " Module %s directly or indirectly displays text -> setting \" keep \" attribute. \n " , log_id ( mod ) ) ;
mod - > set_bool_attribute ( ID : : keep ) ;
}
}
2014-09-30 12:16:40 -05:00
if ( ! nokeep_asserts ) {
std : : map < RTLIL : : Module * , bool > cache ;
for ( auto mod : design - > modules ( ) )
if ( set_keep_assert ( cache , mod ) ) {
2019-05-03 15:03:43 -05:00
log ( " Module %s directly or indirectly contains formal properties -> setting \" keep \" attribute. \n " , log_id ( mod ) ) ;
2020-04-02 11:51:32 -05:00
mod - > set_bool_attribute ( ID : : keep ) ;
2014-09-30 12:16:40 -05:00
}
}
2013-11-03 02:42:51 -06:00
if ( ! keep_positionals )
{
std : : set < RTLIL : : Module * > pos_mods ;
std : : map < std : : pair < RTLIL : : Module * , int > , RTLIL : : IdString > pos_map ;
std : : vector < std : : pair < RTLIL : : Module * , RTLIL : : Cell * > > pos_work ;
2020-03-19 01:49:52 -05:00
for ( auto mod : design - > modules ( ) )
for ( auto cell : mod - > cells ( ) ) {
2020-04-16 10:38:55 -05:00
RTLIL : : Module * cell_mod = design - > module ( cell - > type ) ;
if ( cell_mod = = nullptr )
2013-11-03 02:42:51 -06:00
continue ;
2014-07-26 07:32:50 -05:00
for ( auto & conn : cell - > connections ( ) )
2013-11-03 02:42:51 -06:00
if ( conn . first [ 0 ] = = ' $ ' & & ' 0 ' < = conn . first [ 1 ] & & conn . first [ 1 ] < = ' 9 ' ) {
2020-03-19 01:49:52 -05:00
pos_mods . insert ( design - > module ( cell - > type ) ) ;
pos_work . push_back ( std : : pair < RTLIL : : Module * , RTLIL : : Cell * > ( mod , cell ) ) ;
2013-11-03 02:42:51 -06:00
break ;
}
2020-04-16 10:38:55 -05:00
pool < std : : pair < IdString , IdString > > params_rename ;
for ( const auto & p : cell - > parameters ) {
2021-07-19 03:23:41 -05:00
int id ;
if ( read_id_num ( p . first , & id ) ) {
2020-04-16 10:38:55 -05:00
if ( id < = 0 | | id > GetSize ( cell_mod - > avail_parameters ) ) {
log ( " Failed to map positional parameter %d of cell %s.%s (%s). \n " ,
id , RTLIL : : id2cstr ( mod - > name ) , RTLIL : : id2cstr ( cell - > name ) , RTLIL : : id2cstr ( cell - > type ) ) ;
} else {
params_rename . insert ( std : : make_pair ( p . first , cell_mod - > avail_parameters [ id - 1 ] ) ) ;
}
}
}
for ( const auto & p : params_rename ) {
cell - > setParam ( p . second , cell - > getParam ( p . first ) ) ;
cell - > unsetParam ( p . first ) ;
}
2013-11-03 02:42:51 -06:00
}
for ( auto module : pos_mods )
2020-03-19 01:49:52 -05:00
for ( auto wire : module - > wires ( ) ) {
2013-11-03 02:42:51 -06:00
if ( wire - > port_id > 0 )
pos_map [ std : : pair < RTLIL : : Module * , int > ( module , wire - > port_id ) ] = wire - > name ;
}
for ( auto & work : pos_work ) {
RTLIL : : Module * module = work . first ;
RTLIL : : Cell * cell = work . second ;
log ( " Mapping positional arguments of cell %s.%s (%s). \n " ,
RTLIL : : id2cstr ( module - > name ) , RTLIL : : id2cstr ( cell - > name ) , RTLIL : : id2cstr ( cell - > type ) ) ;
2014-12-26 03:53:21 -06:00
dict < RTLIL : : IdString , RTLIL : : SigSpec > new_connections ;
2021-07-19 03:23:41 -05:00
for ( auto & conn : cell - > connections ( ) ) {
int id ;
if ( read_id_num ( conn . first , & id ) ) {
2020-03-19 01:49:52 -05:00
std : : pair < RTLIL : : Module * , int > key ( design - > module ( cell - > type ) , id ) ;
2013-11-03 02:42:51 -06:00
if ( pos_map . count ( key ) = = 0 ) {
log ( " Failed to map positional argument %d of cell %s.%s (%s). \n " ,
id , RTLIL : : id2cstr ( module - > name ) , RTLIL : : id2cstr ( cell - > name ) , RTLIL : : id2cstr ( cell - > type ) ) ;
new_connections [ conn . first ] = conn . second ;
} else
new_connections [ pos_map . at ( key ) ] = conn . second ;
} else
new_connections [ conn . first ] = conn . second ;
2021-07-19 03:23:41 -05:00
}
2014-07-26 08:57:57 -05:00
cell - > connections_ = new_connections ;
2013-11-03 02:42:51 -06:00
}
}
2019-11-22 03:21:35 -06:00
// Determine default values
dict < IdString , dict < IdString , Const > > defaults_db ;
if ( ! nodefaults )
{
for ( auto module : design - > modules ( ) )
for ( auto wire : module - > wires ( ) )
2020-03-12 14:57:01 -05:00
if ( wire - > port_input & & wire - > attributes . count ( ID : : defaultvalue ) )
defaults_db [ module - > name ] [ wire - > name ] = wire - > attributes . at ( ID : : defaultvalue ) ;
2019-11-22 03:21:35 -06:00
}
2019-11-22 09:07:55 -06:00
// Process SV implicit wildcard port connections
2019-11-22 03:04:54 -06:00
std : : set < Module * > blackbox_derivatives ;
std : : vector < Module * > design_modules = design - > modules ( ) ;
for ( auto module : design_modules )
{
for ( auto cell : module - > cells ( ) )
{
2020-04-02 11:51:32 -05:00
if ( ! cell - > get_bool_attribute ( ID : : wildcard_port_conns ) )
2019-11-22 03:04:54 -06:00
continue ;
Module * m = design - > module ( cell - > type ) ;
if ( m = = nullptr )
log_error ( " Cell %s.%s (%s) has implicit port connections but the module it instantiates is unknown. \n " ,
RTLIL : : id2cstr ( module - > name ) , RTLIL : : id2cstr ( cell - > name ) , RTLIL : : id2cstr ( cell - > type ) ) ;
// Need accurate port widths for error checking; so must derive blackboxes with dynamic port widths
2020-04-02 11:51:32 -05:00
if ( m - > get_blackbox_attribute ( ) & & ! cell - > parameters . empty ( ) & & m - > get_bool_attribute ( ID : : dynports ) ) {
2019-11-22 03:04:54 -06:00
IdString new_m_name = m - > derive ( design , cell - > parameters , true ) ;
if ( new_m_name . empty ( ) )
continue ;
if ( new_m_name ! = m - > name ) {
m = design - > module ( new_m_name ) ;
blackbox_derivatives . insert ( m ) ;
}
}
auto old_connections = cell - > connections ( ) ;
for ( auto wire : m - > wires ( ) ) {
// Find ports of the module that aren't explicitly connected
if ( ! wire - > port_input & & ! wire - > port_output )
continue ;
if ( old_connections . count ( wire - > name ) )
continue ;
// Make sure a wire of correct name exists in the parent
Wire * parent_wire = find_implicit_port_wire ( module , cell , wire - > name . str ( ) ) ;
2019-11-22 03:21:35 -06:00
// Missing wires are OK when a default value is set
if ( ! nodefaults & & parent_wire = = nullptr & & defaults_db . count ( cell - > type ) & & defaults_db . at ( cell - > type ) . count ( wire - > name ) )
continue ;
2019-11-22 03:04:54 -06:00
if ( parent_wire = = nullptr )
log_error ( " No matching wire for implicit port connection `%s' of cell %s.%s (%s). \n " ,
RTLIL : : id2cstr ( wire - > name ) , RTLIL : : id2cstr ( module - > name ) , RTLIL : : id2cstr ( cell - > name ) , RTLIL : : id2cstr ( cell - > type ) ) ;
if ( parent_wire - > width ! = wire - > width )
log_error ( " Width mismatch between wire (%d bits) and port (%d bits) for implicit port connection `%s' of cell %s.%s (%s). \n " ,
parent_wire - > width , wire - > width ,
RTLIL : : id2cstr ( wire - > name ) , RTLIL : : id2cstr ( module - > name ) , RTLIL : : id2cstr ( cell - > name ) , RTLIL : : id2cstr ( cell - > type ) ) ;
cell - > setPort ( wire - > name , parent_wire ) ;
}
2020-04-02 11:51:32 -05:00
cell - > attributes . erase ( ID : : wildcard_port_conns ) ;
2019-11-22 03:04:54 -06:00
}
}
2019-06-19 04:49:20 -05:00
if ( ! nodefaults )
{
for ( auto module : design - > modules ( ) )
for ( auto cell : module - > cells ( ) )
{
if ( defaults_db . count ( cell - > type ) = = 0 )
continue ;
if ( keep_positionals ) {
bool found_positionals = false ;
for ( auto & conn : cell - > connections ( ) )
if ( conn . first [ 0 ] = = ' $ ' & & ' 0 ' < = conn . first [ 1 ] & & conn . first [ 1 ] < = ' 9 ' )
found_positionals = true ;
if ( found_positionals )
continue ;
}
for ( auto & it : defaults_db . at ( cell - > type ) )
if ( ! cell - > hasPort ( it . first ) )
cell - > setPort ( it . first , it . second ) ;
}
}
2019-05-27 11:00:22 -05:00
for ( auto module : design_modules )
{
2019-05-28 09:43:25 -05:00
pool < Wire * > wand_wor_index ;
dict < Wire * , SigSpec > wand_map , wor_map ;
vector < SigSig > new_connections ;
for ( auto wire : module - > wires ( ) )
{
2020-03-12 14:57:01 -05:00
if ( wire - > get_bool_attribute ( ID : : wand ) ) {
2019-05-28 09:43:25 -05:00
wand_map [ wire ] = SigSpec ( ) ;
wand_wor_index . insert ( wire ) ;
}
2020-03-12 14:57:01 -05:00
if ( wire - > get_bool_attribute ( ID : : wor ) ) {
2019-05-28 09:43:25 -05:00
wor_map [ wire ] = SigSpec ( ) ;
wand_wor_index . insert ( wire ) ;
}
2019-05-27 11:00:22 -05:00
}
for ( auto & conn : module - > connections ( ) )
{
2019-05-28 09:43:25 -05:00
SigSig new_conn ;
int cursor = 0 ;
2019-05-27 11:00:22 -05:00
2019-05-28 09:43:25 -05:00
for ( auto c : conn . first . chunks ( ) )
{
Wire * w = c . wire ;
SigSpec rhs = conn . second . extract ( cursor , GetSize ( c ) ) ;
if ( wand_wor_index . count ( w ) = = 0 ) {
new_conn . first . append ( c ) ;
new_conn . second . append ( rhs ) ;
} else {
if ( wand_map . count ( w ) ) {
SigSpec sig = SigSpec ( State : : S1 , GetSize ( w ) ) ;
sig . replace ( c . offset , rhs ) ;
wand_map . at ( w ) . append ( sig ) ;
} else {
SigSpec sig = SigSpec ( State : : S0 , GetSize ( w ) ) ;
sig . replace ( c . offset , rhs ) ;
wor_map . at ( w ) . append ( sig ) ;
}
2019-05-27 11:00:22 -05:00
}
2019-05-28 09:43:25 -05:00
cursor + = GetSize ( c ) ;
2019-05-27 11:00:22 -05:00
}
2019-05-28 09:43:25 -05:00
new_connections . push_back ( new_conn ) ;
2019-05-27 11:00:22 -05:00
}
module - > new_connections ( new_connections ) ;
2018-01-04 06:23:29 -06:00
2019-05-28 09:43:25 -05:00
for ( auto cell : module - > cells ( ) )
{
if ( ! cell - > known ( ) )
continue ;
2017-01-01 15:52:52 -06:00
2019-05-28 09:43:25 -05:00
for ( auto & conn : cell - > connections ( ) )
{
if ( ! cell - > output ( conn . first ) )
continue ;
2017-01-01 15:52:52 -06:00
2019-05-28 09:43:25 -05:00
SigSpec new_sig ;
bool update_port = false ;
for ( auto c : conn . second . chunks ( ) )
{
Wire * w = c . wire ;
if ( wand_wor_index . count ( w ) = = 0 ) {
new_sig . append ( c ) ;
continue ;
}
Wire * t = module - > addWire ( NEW_ID , GetSize ( c ) ) ;
new_sig . append ( t ) ;
update_port = true ;
if ( wand_map . count ( w ) ) {
SigSpec sig = SigSpec ( State : : S1 , GetSize ( w ) ) ;
sig . replace ( c . offset , t ) ;
wand_map . at ( w ) . append ( sig ) ;
} else {
SigSpec sig = SigSpec ( State : : S0 , GetSize ( w ) ) ;
sig . replace ( c . offset , t ) ;
wor_map . at ( w ) . append ( sig ) ;
}
}
if ( update_port )
cell - > setPort ( conn . first , new_sig ) ;
2018-01-04 06:23:29 -06:00
}
}
2019-05-28 09:43:25 -05:00
for ( auto w : wand_wor_index )
2017-07-22 08:08:30 -05:00
{
2019-05-28 09:43:25 -05:00
bool wand = wand_map . count ( w ) ;
SigSpec sigs = wand ? wand_map . at ( w ) : wor_map . at ( w ) ;
2017-01-01 15:52:52 -06:00
2019-05-28 09:43:25 -05:00
if ( GetSize ( sigs ) = = 0 )
2017-07-22 08:08:30 -05:00
continue ;
2017-07-21 12:32:31 -05:00
2019-05-28 09:43:25 -05:00
if ( GetSize ( w ) = = 1 ) {
if ( wand )
module - > addReduceAnd ( NEW_ID , sigs , w ) ;
else
module - > addReduceOr ( NEW_ID , sigs , w ) ;
2017-07-22 08:08:30 -05:00
continue ;
2019-05-28 09:43:25 -05:00
}
2017-01-01 15:52:52 -06:00
2019-05-28 09:43:25 -05:00
SigSpec s = sigs . extract ( 0 , GetSize ( w ) ) ;
for ( int i = GetSize ( w ) ; i < GetSize ( sigs ) ; i + = GetSize ( w ) ) {
if ( wand )
s = module - > And ( NEW_ID , s , sigs . extract ( i , GetSize ( w ) ) ) ;
2017-01-01 15:52:52 -06:00
else
2019-05-28 09:43:25 -05:00
s = module - > Or ( NEW_ID , s , sigs . extract ( i , GetSize ( w ) ) ) ;
}
module - > connect ( w , s ) ;
}
for ( auto cell : module - > cells ( ) )
{
Module * m = design - > module ( cell - > type ) ;
if ( m = = nullptr )
continue ;
2017-01-01 15:52:52 -06:00
2020-04-02 11:51:32 -05:00
if ( m - > get_blackbox_attribute ( ) & & ! cell - > parameters . empty ( ) & & m - > get_bool_attribute ( ID : : dynports ) ) {
2019-05-28 09:43:25 -05:00
IdString new_m_name = m - > derive ( design , cell - > parameters , true ) ;
if ( new_m_name . empty ( ) )
continue ;
if ( new_m_name ! = m - > name ) {
m = design - > module ( new_m_name ) ;
blackbox_derivatives . insert ( m ) ;
}
2017-01-01 15:52:52 -06:00
}
2017-07-22 08:08:30 -05:00
2019-05-28 09:43:25 -05:00
for ( auto & conn : cell - > connections ( ) )
{
Wire * w = m - > wire ( conn . first ) ;
if ( w = = nullptr | | w - > port_id = = 0 )
continue ;
if ( GetSize ( conn . second ) = = 0 )
2019-05-27 11:00:22 -05:00
continue ;
2019-05-28 09:43:25 -05:00
SigSpec sig = conn . second ;
if ( ! keep_portwidths & & GetSize ( w ) ! = GetSize ( conn . second ) )
{
if ( GetSize ( w ) < GetSize ( conn . second ) )
{
int n = GetSize ( conn . second ) - GetSize ( w ) ;
if ( ! w - > port_input & & w - > port_output )
2020-12-18 13:59:08 -06:00
{
RTLIL : : SigSpec out = sig . extract ( 0 , GetSize ( w ) ) ;
out . extend_u0 ( GetSize ( sig ) , w - > is_signed ) ;
module - > connect ( sig . extract ( GetSize ( w ) , n ) , out . extract ( GetSize ( w ) , n ) ) ;
}
2019-05-28 09:43:25 -05:00
sig . remove ( GetSize ( w ) , n ) ;
}
else
{
int n = GetSize ( w ) - GetSize ( conn . second ) ;
if ( w - > port_input & & ! w - > port_output )
2020-12-18 13:59:08 -06:00
sig . extend_u0 ( GetSize ( w ) , sig . is_wire ( ) & & sig . as_wire ( ) - > is_signed ) ;
2019-05-28 09:43:25 -05:00
else
sig . append ( module - > addWire ( NEW_ID , n ) ) ;
2019-05-27 11:00:22 -05:00
}
2019-05-28 09:43:25 -05:00
if ( ! conn . second . is_fully_const ( ) | | ! w - > port_input | | w - > port_output )
log_warning ( " Resizing cell port %s.%s.%s from %d bits to %d bits. \n " , log_id ( module ) , log_id ( cell ) ,
log_id ( conn . first ) , GetSize ( conn . second ) , GetSize ( sig ) ) ;
cell - > setPort ( conn . first , sig ) ;
2019-05-27 11:00:22 -05:00
}
2019-05-28 09:43:25 -05:00
if ( w - > port_output & & ! w - > port_input & & sig . has_const ( ) )
log_error ( " Output port %s.%s.%s (%s) is connected to constants: %s \n " ,
log_id ( module ) , log_id ( cell ) , log_id ( conn . first ) , log_id ( cell - > type ) , log_signal ( sig ) ) ;
}
2017-01-01 15:52:52 -06:00
}
}
2018-01-04 06:23:29 -06:00
for ( auto module : blackbox_derivatives )
design - > remove ( module ) ;
2013-05-26 05:20:51 -05:00
log_pop ( ) ;
2013-01-05 04:13:26 -06:00
}
} HierarchyPass ;
2015-04-04 12:00:15 -05:00
2014-09-27 09:17:53 -05:00
PRIVATE_NAMESPACE_END