2013-01-05 04:13:26 -06:00
/*
* yosys - - Yosys Open SYnthesis Suite
*
* Copyright ( C ) 2012 Clifford Wolf < clifford @ clifford . at >
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"
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
2014-07-27 03:18:00 -05:00
for ( auto i1 : design - > modules_ )
2014-07-26 18:51:45 -05:00
for ( auto i2 : i1 . second - > cells_ )
2013-03-24 20:14:33 -05:00
{
RTLIL : : Cell * cell = i2 . second ;
2014-07-29 09:33:56 -05:00
if ( design - > has ( cell - > type ) )
continue ;
if ( cell - > type . substr ( 0 , 1 ) = = " $ " & & cell - > type . substr ( 0 , 3 ) ! = " $__ " )
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 ( ) ) ;
2014-07-27 03:18:00 -05:00
for ( auto i1 : design - > modules_ )
2014-07-26 18:51:45 -05:00
for ( auto i2 : i1 . second - > cells_ )
2013-03-26 13:11:53 -05:00
if ( i2 . second - > type = = celltype ) {
2014-07-26 07:32:50 -05:00
for ( auto & conn : i2 . second - > 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
}
2013-03-26 13:11:53 -05:00
for ( auto & para : i2 . second - > parameters )
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 ;
2013-11-22 08:01:12 -06:00
mod - > attributes [ " \\ 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 ) ) ;
}
}
2014-09-27 09:17:53 -05:00
bool expand_module ( RTLIL : : Design * design , RTLIL : : Module * module , bool flag_check , 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
2014-07-26 18:51:45 -05:00
for ( auto & cell_it : module - > cells_ )
2014-01-14 12:28:20 -06:00
{
2013-01-05 04:13:26 -06:00
RTLIL : : Cell * cell = cell_it . second ;
2014-01-14 12:28:20 -06:00
2014-06-07 04:48:50 -05:00
if ( cell - > type . substr ( 0 , 7 ) = = " $array: " ) {
2014-08-02 06:11:01 -05:00
int pos_idx = cell - > type . str ( ) . find_first_of ( ' : ' ) ;
int pos_num = cell - > type . str ( ) . find_first_of ( ' : ' , pos_idx + 1 ) ;
int pos_type = cell - > type . str ( ) . find_first_of ( ' : ' , pos_num + 1 ) ;
int idx = atoi ( cell - > type . str ( ) . substr ( pos_idx + 1 , pos_num ) . c_str ( ) ) ;
int num = atoi ( cell - > type . str ( ) . 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 ) ;
2014-08-02 06:11:01 -05:00
cell - > type = cell - > type . str ( ) . substr ( pos_type + 1 ) ;
2014-06-07 04:48:50 -05:00
}
2014-07-27 03:18:00 -05:00
if ( design - > modules_ . count ( cell - > type ) = = 0 )
2014-01-14 12:28:20 -06:00
{
2014-08-02 06:11:01 -05:00
if ( design - > modules_ . count ( " $abstract " + cell - > type . str ( ) ) )
2014-02-13 06:59:13 -06:00
{
2014-08-02 06:11:01 -05:00
cell - > type = design - > modules_ . at ( " $abstract " + cell - > type . str ( ) ) - > derive ( design , cell - > parameters ) ;
2014-02-13 06:59:13 -06:00
cell - > parameters . clear ( ) ;
did_something = true ;
continue ;
}
2014-01-14 12:28:20 -06:00
if ( cell - > type [ 0 ] = = ' $ ' )
continue ;
for ( auto & dir : libdirs )
{
filename = dir + " / " + RTLIL : : unescape_id ( cell - > type ) + " .v " ;
2014-10-17 07:01:47 -05:00
if ( check_file_exists ( filename ) ) {
2014-01-14 12:28:20 -06:00
std : : vector < std : : string > args ;
args . push_back ( filename ) ;
Frontend : : frontend_call ( design , NULL , filename , " verilog " ) ;
goto loaded_module ;
}
filename = dir + " / " + RTLIL : : unescape_id ( cell - > type ) + " .il " ;
2014-10-17 07:01:47 -05:00
if ( check_file_exists ( filename ) ) {
2014-01-14 12:28:20 -06:00
std : : vector < std : : string > args ;
args . push_back ( filename ) ;
Frontend : : frontend_call ( design , NULL , filename , " ilang " ) ;
goto loaded_module ;
}
}
2013-01-05 04:13:26 -06:00
if ( flag_check & & cell - > type [ 0 ] ! = ' $ ' )
log_error ( " Module `%s' referenced in module `%s' in cell `%s' is not part of the design. \n " ,
cell - > type . c_str ( ) , module - > name . c_str ( ) , cell - > name . c_str ( ) ) ;
continue ;
2014-01-14 12:28:20 -06:00
loaded_module :
2014-07-27 03:18:00 -05:00
if ( design - > modules_ . count ( cell - > type ) = = 0 )
2014-01-14 12:28:20 -06:00
log_error ( " File `%s' from libdir does not declare module `%s'. \n " , filename . c_str ( ) , cell - > type . c_str ( ) ) ;
did_something = true ;
2014-12-19 11:47:19 -06:00
} else
if ( flag_check )
{
RTLIL : : Module * mod = design - > module ( cell - > type ) ;
for ( auto & conn : cell - > connections ( ) )
if ( conn . first [ 0 ] = = ' $ ' & & ' 0 ' < = conn . first [ 1 ] & & conn . first [ 1 ] < = ' 9 ' ) {
int id = atoi ( conn . first . c_str ( ) + 1 ) ;
2014-12-24 09:26:18 -06:00
if ( id < = 0 | | id > GetSize ( mod - > ports ) )
2014-12-19 11:47:19 -06:00
log_error ( " Module `%s' referenced in module `%s' in cell `%s' has only %d ports, requested port %d. \n " ,
2014-12-24 09:26:18 -06:00
log_id ( cell - > type ) , log_id ( module ) , log_id ( cell ) , GetSize ( mod - > ports ) , id ) ;
2014-12-19 11:47:19 -06:00
} else if ( mod - > wire ( conn . first ) = = nullptr | | mod - > wire ( conn . first ) - > 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 ) ) ;
2013-01-05 04:13:26 -06:00
}
2014-01-14 12:28:20 -06:00
2013-01-05 04:13:26 -06:00
if ( cell - > parameters . size ( ) = = 0 )
continue ;
2014-01-14 12:28:20 -06:00
2014-07-27 03:18:00 -05:00
if ( design - > modules_ . at ( cell - > type ) - > get_bool_attribute ( " \\ blackbox " ) )
2013-03-28 03:20:10 -05:00
continue ;
2014-01-14 12:28:20 -06:00
2014-07-27 03:18:00 -05:00
RTLIL : : Module * mod = design - > modules_ [ cell - > type ] ;
2013-12-04 07:24:44 -06:00
cell - > type = mod - > derive ( design , cell - > parameters ) ;
2013-01-05 04:13:26 -06:00
cell - > parameters . clear ( ) ;
2013-04-26 06:28:15 -05:00
did_something = true ;
2013-01-05 04:13:26 -06: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 ;
2014-07-27 03:18:00 -05:00
if ( design - > modules_ . count ( cell - > type ) = = 0 )
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
2014-07-27 03:18:00 -05:00
RTLIL : : Module * mod = design - > modules_ [ 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 ;
2014-06-07 05:17:06 -05:00
if ( portname . substr ( 0 , 1 ) = = " $ " ) {
int port_id = atoi ( portname . substr ( 1 ) . c_str ( ) ) ;
2014-07-26 18:49:51 -05:00
for ( auto & wire_it : mod - > wires_ )
2014-06-07 05:17:06 -05:00
if ( wire_it . second - > port_id = = port_id ) {
portname = wire_it . first ;
break ;
}
}
2014-07-26 18:49:51 -05:00
if ( mod - > wires_ . count ( portname ) = = 0 )
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 ) ) ;
2014-07-26 18:49:51 -05:00
int port_size = mod - > wires_ . at ( portname ) - > width ;
2014-06-07 04:48:50 -05:00
if ( conn_size = = port_size )
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 ( ) ) ;
2015-02-15 05:57:41 -06:00
else if ( ! mod - > get_bool_attribute ( " \\ blackbox " ) )
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 ( ) ;
if ( celltype . substr ( 0 , 7 ) = = " $array: " ) {
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 ) ;
celltype = celltype . substr ( pos_type + 1 ) ;
}
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 ;
2014-07-27 03:18:00 -05:00
for ( auto & it : design - > modules_ )
2013-01-05 04:13:26 -06:00
if ( used . count ( it . second ) = = 0 )
del_modules . push_back ( it . second ) ;
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 ) {
2014-02-04 09:50:13 -06:00
if ( ! purge_lib & & mod - > get_bool_attribute ( " \\ blackbox " ) )
continue ;
2013-01-05 04:13:26 -06:00
log ( " Removing unused module `%s'. \n " , mod - > name . c_str ( ) ) ;
2014-07-27 03:18:00 -05:00
design - > modules_ . erase ( mod - > name ) ;
2015-02-15 05:57:41 -06:00
del_counter + + ;
2013-01-05 04:13:26 -06:00
delete mod ;
}
2015-02-15 05:57:41 -06:00
log ( " Removed %d unused modules. \n " , del_counter ) ;
2013-01-05 04:13:26 -06:00
}
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 ) ;
2015-07-25 03:31:52 -05:00
if ( ( m ! = nullptr & & set_keep_assert ( cache , m ) ) | | c - > type . in ( " $assert " , " $assume " ) )
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 ) {
db [ module ] = 0 ;
for ( auto cell : module - > cells ( ) )
if ( design - > module ( cell - > type ) )
2015-10-25 13:30:49 -05:00
db [ module ] = max ( db [ module ] , find_top_mod_score ( design , design - > module ( cell - > type ) , db ) + 1 ) ;
2015-03-18 02:33:40 -05:00
}
return db . at ( module ) ;
}
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 " ) { }
virtual void help ( )
{
// |---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 " ) ;
log ( " design an re-runs the language frontends for the parametric modules as \n " ) ;
log ( " needed. \n " ) ;
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 " ) ;
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 " ) ;
log ( " to arguments using port names. 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 " ) ;
log ( " that directly or indirectly contain one or more $assert cells. this \n " ) ;
log ( " option disables this behavior. \n " ) ;
log ( " \n " ) ;
2013-02-28 06:59:49 -06:00
log ( " -top <module> \n " ) ;
log ( " use the specified top module to built a design hierarchy. modules \n " ) ;
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 " ) ;
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 " ) ;
}
2013-01-05 04:13:26 -06:00
virtual void execute ( std : : vector < std : : string > args , RTLIL : : Design * design )
{
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 ;
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 ;
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 ;
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 ;
2013-01-05 04:13:26 -06:00
size_t argidx ;
for ( argidx = 1 ; argidx < args . size ( ) ; argidx + + )
{
2013-03-24 20:14:33 -05:00
if ( args [ argidx ] = = " -generate " & & ! flag_check & & ! top_mod ) {
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 ;
}
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 ;
}
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 " ) ;
2014-07-27 03:18:00 -05:00
top_mod = design - > modules_ . count ( RTLIL : : escape_id ( args [ argidx ] ) ) ? design - > modules_ . at ( RTLIL : : escape_id ( args [ argidx ] ) ) : NULL ;
if ( top_mod = = NULL & & design - > modules_ . count ( " $abstract " + RTLIL : : escape_id ( args [ argidx ] ) ) ) {
2014-12-26 03:53:21 -06:00
dict < RTLIL : : IdString , RTLIL : : Const > empty_parameters ;
2014-07-27 03:18:00 -05:00
design - > modules_ . at ( " $abstract " + RTLIL : : escape_id ( args [ argidx ] ) ) - > derive ( design , empty_parameters ) ;
top_mod = design - > modules_ . count ( RTLIL : : escape_id ( args [ argidx ] ) ) ? design - > modules_ . at ( RTLIL : : escape_id ( args [ argidx ] ) ) : NULL ;
2014-02-13 06:59:13 -06:00
}
2013-01-05 04:13:26 -06:00
if ( top_mod = = NULL )
log_cmd_error ( " Module `%s' not found! \n " , args [ argidx ] . c_str ( ) ) ;
continue ;
}
2015-03-18 02:33:40 -05:00
if ( args [ argidx ] = = " -auto-top " ) {
auto_top_mode = true ;
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
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 )
2014-07-27 03:18:00 -05:00
for ( auto & mod_it : design - > modules_ )
2013-11-23 22:03:43 -06:00
if ( mod_it . second - > get_bool_attribute ( " \\ top " ) )
top_mod = mod_it . second ;
2015-03-18 02:33:40 -05:00
if ( top_mod = = nullptr & & auto_top_mode ) {
2016-04-21 16:28:37 -05:00
log_header ( design , " Finding top of design hierarchy.. \n " ) ;
2015-03-18 02:33:40 -05:00
dict < Module * , int > db ;
2015-04-04 12:00:15 -05:00
for ( Module * mod : design - > selected_modules ( ) ) {
2015-03-18 02:33:40 -05:00
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 ) ) ;
}
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 ) {
if ( expand_module ( design , module , flag_check , libdirs ) )
2013-01-05 04:13:26 -06:00
did_something = true ;
}
}
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 ) {
2014-07-27 03:18:00 -05:00
for ( auto & mod_it : design - > modules_ )
2013-11-23 22:03:43 -06:00
if ( mod_it . second = = top_mod )
mod_it . second - > attributes [ " \\ top " ] = RTLIL : : Const ( 1 ) ;
else
mod_it . second - > attributes . erase ( " \\ top " ) ;
}
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 ) ) {
log ( " Module %s directly or indirectly contains $assert cells -> setting \" keep \" attribute. \n " , log_id ( mod ) ) ;
mod - > set_bool_attribute ( " \\ keep " ) ;
}
}
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 ;
2014-07-27 03:18:00 -05:00
for ( auto & mod_it : design - > modules_ )
2014-07-26 18:51:45 -05:00
for ( auto & cell_it : mod_it . second - > cells_ ) {
2013-11-03 02:42:51 -06:00
RTLIL : : Cell * cell = cell_it . second ;
2014-07-27 03:18:00 -05:00
if ( design - > modules_ . count ( cell - > type ) = = 0 )
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 ' ) {
2014-07-27 03:18:00 -05:00
pos_mods . insert ( design - > modules_ . at ( cell - > type ) ) ;
2013-11-03 02:42:51 -06:00
pos_work . push_back ( std : : pair < RTLIL : : Module * , RTLIL : : Cell * > ( mod_it . second , cell ) ) ;
break ;
}
}
for ( auto module : pos_mods )
2014-07-26 18:49:51 -05:00
for ( auto & wire_it : module - > wires_ ) {
2013-11-03 02:42:51 -06:00
RTLIL : : Wire * wire = wire_it . second ;
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 ;
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 ' ) {
int id = atoi ( conn . first . c_str ( ) + 1 ) ;
2014-07-27 03:18:00 -05:00
std : : pair < RTLIL : : Module * , int > key ( design - > modules_ . at ( 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 ;
2014-07-26 08:57:57 -05:00
cell - > connections_ = new_connections ;
2013-11-03 02:42:51 -06:00
}
}
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