2013-01-05 11:13:26 +01:00
/*
* yosys - - Yosys Open SYnthesis Suite
*
2021-06-08 00:39:36 +02:00
* Copyright ( C ) 2012 Claire Xenia Wolf < claire @ yosyshq . com >
2015-07-02 11:14:30 +02:00
*
2013-01-05 11:13:26 +01: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 11:14:30 +02:00
*
2013-01-05 11:13:26 +01: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 .
*
*/
# include "kernel/register.h"
# include "kernel/sigtools.h"
2014-02-06 15:49:03 +01:00
# include "kernel/celltypes.h"
2014-08-17 00:55:35 +02:00
# include "kernel/utils.h"
2013-01-05 11:13:26 +01:00
# include "kernel/log.h"
# include <stdlib.h>
# include <stdio.h>
2014-07-21 16:34:16 +02:00
# include <algorithm>
2013-01-05 11:13:26 +01:00
2014-09-27 16:17:53 +02:00
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
2013-01-05 11:13:26 +01:00
2014-09-27 16:17:53 +02:00
bool did_something ;
2020-03-30 17:22:12 +02:00
void replace_undriven ( RTLIL : : Module * module , const CellTypes & ct )
2014-02-06 15:49:03 +01:00
{
SigMap sigmap ( module ) ;
SigPool driven_signals ;
SigPool used_signals ;
SigPool all_signals ;
2019-04-30 14:46:12 +02:00
dict < SigBit , pair < Wire * , State > > initbits ;
pool < Wire * > revisit_initwires ;
2014-07-27 13:19:05 +02:00
for ( auto cell : module - > cells ( ) )
for ( auto & conn : cell - > connections ( ) ) {
if ( ! ct . cell_known ( cell - > type ) | | ct . cell_output ( cell - > type , conn . first ) )
2014-02-06 15:49:03 +01:00
driven_signals . add ( sigmap ( conn . second ) ) ;
2014-07-27 13:19:05 +02:00
if ( ! ct . cell_known ( cell - > type ) | | ct . cell_input ( cell - > type , conn . first ) )
2014-02-06 15:49:03 +01:00
used_signals . add ( sigmap ( conn . second ) ) ;
}
2014-07-27 13:19:05 +02:00
for ( auto wire : module - > wires ( ) ) {
2020-04-02 18:51:32 +02:00
if ( wire - > attributes . count ( ID : : init ) ) {
2019-04-30 14:46:12 +02:00
SigSpec sig = sigmap ( wire ) ;
2020-04-02 18:51:32 +02:00
Const initval = wire - > attributes . at ( ID : : init ) ;
2019-04-30 14:46:12 +02:00
for ( int i = 0 ; i < GetSize ( initval ) & & i < GetSize ( wire ) ; i + + ) {
if ( initval [ i ] = = State : : S0 | | initval [ i ] = = State : : S1 )
initbits [ sig [ i ] ] = make_pair ( wire , initval [ i ] ) ;
}
}
2014-07-27 13:19:05 +02:00
if ( wire - > port_input )
driven_signals . add ( sigmap ( wire ) ) ;
2019-08-15 23:51:12 +02:00
if ( wire - > port_output | | wire - > get_bool_attribute ( ID : : keep ) )
2014-07-27 13:19:05 +02:00
used_signals . add ( sigmap ( wire ) ) ;
all_signals . add ( sigmap ( wire ) ) ;
2014-02-06 15:49:03 +01:00
}
all_signals . del ( driven_signals ) ;
RTLIL : : SigSpec undriven_signals = all_signals . export_all ( ) ;
2014-07-22 20:15:14 +02:00
for ( auto & c : undriven_signals . chunks ( ) )
2014-02-06 15:49:03 +01:00
{
RTLIL : : SigSpec sig = c ;
if ( c . wire - > name [ 0 ] = = ' $ ' )
sig = used_signals . extract ( sig ) ;
2014-07-22 20:15:14 +02:00
if ( sig . size ( ) = = 0 )
2014-02-06 15:49:03 +01:00
continue ;
2019-04-30 14:46:12 +02:00
Const val ( RTLIL : : State : : Sx , GetSize ( sig ) ) ;
for ( int i = 0 ; i < GetSize ( sig ) ; i + + ) {
SigBit bit = sigmap ( sig [ i ] ) ;
auto cursor = initbits . find ( bit ) ;
if ( cursor ! = initbits . end ( ) ) {
revisit_initwires . insert ( cursor - > second . first ) ;
2024-10-09 19:39:45 +02:00
val . bits ( ) [ i ] = cursor - > second . second ;
2019-04-30 14:46:12 +02:00
}
}
2019-05-03 14:24:53 +02:00
log_debug ( " Setting undriven signal in %s to constant: %s = %s \n " , log_id ( module ) , log_signal ( sig ) , log_signal ( val ) ) ;
2019-04-30 14:46:12 +02:00
module - > connect ( sig , val ) ;
2014-08-30 19:37:12 +02:00
did_something = true ;
2014-02-06 15:49:03 +01:00
}
2019-04-30 14:46:12 +02:00
if ( ! revisit_initwires . empty ( ) )
{
SigMap sm2 ( module ) ;
for ( auto wire : revisit_initwires ) {
SigSpec sig = sm2 ( wire ) ;
2020-04-02 18:51:32 +02:00
Const initval = wire - > attributes . at ( ID : : init ) ;
2019-04-30 14:46:12 +02:00
for ( int i = 0 ; i < GetSize ( initval ) & & i < GetSize ( wire ) ; i + + ) {
if ( SigBit ( initval [ i ] ) = = sig [ i ] )
2024-10-09 19:39:45 +02:00
initval . bits ( ) [ i ] = State : : Sx ;
2019-04-30 14:46:12 +02:00
}
2019-05-03 14:24:53 +02:00
if ( initval . is_fully_undef ( ) ) {
log_debug ( " Removing init attribute from %s/%s. \n " , log_id ( module ) , log_id ( wire ) ) ;
2020-04-02 18:51:32 +02:00
wire - > attributes . erase ( ID : : init ) ;
2019-05-03 14:24:53 +02:00
did_something = true ;
2020-04-02 18:51:32 +02:00
} else if ( initval ! = wire - > attributes . at ( ID : : init ) ) {
2019-05-03 14:24:53 +02:00
log_debug ( " Updating init attribute on %s/%s: %s \n " , log_id ( module ) , log_id ( wire ) , log_signal ( initval ) ) ;
2020-04-02 18:51:32 +02:00
wire - > attributes [ ID : : init ] = initval ;
2019-05-03 14:24:53 +02:00
did_something = true ;
}
2019-04-30 14:46:12 +02:00
}
}
2014-02-06 15:49:03 +01:00
}
2019-08-11 23:25:46 +02:00
void replace_cell ( SigMap & assign_map , RTLIL : : Module * module , RTLIL : : Cell * cell ,
2020-06-19 03:32:48 +02:00
const std : : string & info , IdString out_port , RTLIL : : SigSpec out_val )
2013-01-05 11:13:26 +01:00
{
2014-07-31 16:38:54 +02:00
RTLIL : : SigSpec Y = cell - > getPort ( out_port ) ;
2014-07-22 20:15:14 +02:00
out_val . extend_u0 ( Y . size ( ) , false ) ;
2014-07-21 21:38:55 +02:00
2019-04-22 17:25:52 +02:00
log_debug ( " Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'. \n " ,
2013-01-05 11:13:26 +01:00
cell - > type . c_str ( ) , cell - > name . c_str ( ) , info . c_str ( ) ,
module - > name . c_str ( ) , log_signal ( Y ) , log_signal ( out_val ) ) ;
2014-08-24 15:14:45 +02:00
// log_cell(cell);
2014-07-27 14:50:25 +02:00
assign_map . add ( Y , out_val ) ;
module - > connect ( Y , out_val ) ;
2014-07-25 15:05:18 +02:00
module - > remove ( cell ) ;
2013-01-05 11:13:26 +01:00
did_something = true ;
}
2020-04-24 03:15:07 +02:00
bool group_cell_inputs ( RTLIL : : Module * module , RTLIL : : Cell * cell , bool commutative , SigMap & sigmap , bool keepdc )
2014-07-21 16:34:16 +02:00
{
2019-08-15 23:50:10 +02:00
IdString b_name = cell - > hasPort ( ID : : B ) ? ID : : B : ID : : A ;
2014-07-21 16:34:16 +02:00
2020-04-02 18:51:32 +02:00
bool a_signed = cell - > parameters . at ( ID : : A_SIGNED ) . as_bool ( ) ;
2019-08-09 18:58:14 +02:00
bool b_signed = cell - > parameters . at ( b_name . str ( ) + " _SIGNED " ) . as_bool ( ) ;
2014-07-21 16:34:16 +02:00
2019-08-15 23:50:10 +02:00
RTLIL : : SigSpec sig_a = sigmap ( cell - > getPort ( ID : : A ) ) ;
2014-07-31 16:38:54 +02:00
RTLIL : : SigSpec sig_b = sigmap ( cell - > getPort ( b_name ) ) ;
2019-08-15 23:50:10 +02:00
RTLIL : : SigSpec sig_y = sigmap ( cell - > getPort ( ID : : Y ) ) ;
2014-07-21 16:34:16 +02:00
2014-09-04 08:55:58 +02:00
sig_a . extend_u0 ( sig_y . size ( ) , a_signed ) ;
sig_b . extend_u0 ( sig_y . size ( ) , b_signed ) ;
2014-07-21 16:34:16 +02:00
std : : vector < RTLIL : : SigBit > bits_a = sig_a , bits_b = sig_b , bits_y = sig_y ;
enum { GRP_DYN , GRP_CONST_A , GRP_CONST_B , GRP_CONST_AB , GRP_N } ;
std : : map < std : : pair < RTLIL : : SigBit , RTLIL : : SigBit > , std : : set < RTLIL : : SigBit > > grouped_bits [ GRP_N ] ;
2014-10-10 16:59:44 +02:00
for ( int i = 0 ; i < GetSize ( bits_y ) ; i + + )
2014-07-21 16:34:16 +02:00
{
int group_idx = GRP_DYN ;
RTLIL : : SigBit bit_a = bits_a [ i ] , bit_b = bits_b [ i ] ;
2020-04-24 20:15:29 +02:00
if ( cell - > type = = ID ( $ or ) ) {
if ( bit_a = = RTLIL : : State : : S1 | | bit_b = = RTLIL : : State : : S1 )
bit_a = bit_b = RTLIL : : State : : S1 ;
}
else if ( cell - > type = = ID ( $ and ) ) {
if ( bit_a = = RTLIL : : State : : S0 | | bit_b = = RTLIL : : State : : S0 )
bit_a = bit_b = RTLIL : : State : : S0 ;
}
else if ( ! keepdc ) {
if ( cell - > type = = ID ( $ xor ) ) {
if ( bit_a = = bit_b )
bit_a = bit_b = RTLIL : : State : : S0 ;
}
else if ( cell - > type = = ID ( $ xnor ) ) {
if ( bit_a = = bit_b )
bit_a = bit_b = RTLIL : : State : : S1 ; // For consistency with gate-level which does $xnor -> $_XOR_ + $_NOT_
}
}
2014-07-21 21:38:55 +02:00
2020-05-14 21:14:23 +02:00
bool def = ( bit_a ! = State : : Sx & & bit_a ! = State : : Sz & & bit_b ! = State : : Sx & & bit_b ! = State : : Sz ) ;
2020-04-24 20:15:29 +02:00
if ( def | | ! keepdc ) {
2020-04-24 03:15:07 +02:00
if ( bit_a . wire = = NULL & & bit_b . wire = = NULL )
group_idx = GRP_CONST_AB ;
else if ( bit_a . wire = = NULL )
group_idx = GRP_CONST_A ;
else if ( bit_b . wire = = NULL & & commutative )
group_idx = GRP_CONST_A , std : : swap ( bit_a , bit_b ) ;
else if ( bit_b . wire = = NULL )
group_idx = GRP_CONST_B ;
}
2014-07-21 16:34:16 +02:00
grouped_bits [ group_idx ] [ std : : pair < RTLIL : : SigBit , RTLIL : : SigBit > ( bit_a , bit_b ) ] . insert ( bits_y [ i ] ) ;
}
for ( int i = 0 ; i < GRP_N ; i + + )
2014-10-10 16:59:44 +02:00
if ( GetSize ( grouped_bits [ i ] ) = = GetSize ( bits_y ) )
2014-07-21 16:34:16 +02:00
return false ;
2019-04-22 17:25:52 +02:00
log_debug ( " Replacing %s cell `%s' in module `%s' with cells using grouped bits: \n " ,
2014-07-21 16:34:16 +02:00
log_id ( cell - > type ) , log_id ( cell ) , log_id ( module ) ) ;
for ( int i = 0 ; i < GRP_N ; i + + )
{
if ( grouped_bits [ i ] . empty ( ) )
continue ;
2024-11-12 02:06:11 +01:00
RTLIL : : SigSpec new_y = module - > addWire ( NEW_ID2_SUFFIX ( " grp_y " ) , GetSize ( grouped_bits [ i ] ) ) ; // SILIMATE: Improve the naming
2014-07-21 16:34:16 +02:00
RTLIL : : SigSpec new_a , new_b ;
RTLIL : : SigSig new_conn ;
for ( auto & it : grouped_bits [ i ] ) {
for ( auto & bit : it . second ) {
2020-03-13 16:17:39 +01:00
new_conn . first . append ( bit ) ;
2020-04-24 03:15:07 +02:00
new_conn . second . append ( new_y [ new_a . size ( ) ] ) ;
2014-07-21 16:34:16 +02:00
}
2020-03-13 16:17:39 +01:00
new_a . append ( it . first . first ) ;
new_b . append ( it . first . second ) ;
2014-07-21 16:34:16 +02:00
}
2019-08-09 18:58:14 +02:00
if ( cell - > type . in ( ID ( $ and ) , ID ( $ or ) ) & & i = = GRP_CONST_A ) {
2020-04-24 20:15:29 +02:00
if ( ! keepdc ) {
if ( cell - > type = = ID ( $ and ) )
new_a . replace ( dict < SigBit , SigBit > { { State : : Sx , State : : S0 } , { State : : Sz , State : : S0 } } , & new_b ) ;
else if ( cell - > type = = ID ( $ or ) )
new_a . replace ( dict < SigBit , SigBit > { { State : : Sx , State : : S1 } , { State : : Sz , State : : S1 } } , & new_b ) ;
else log_abort ( ) ;
}
2019-04-22 17:25:52 +02:00
log_debug ( " Direct Connection: %s (%s with %s) \n " , log_signal ( new_b ) , log_id ( cell - > type ) , log_signal ( new_a ) ) ;
2019-03-14 20:35:15 +01:00
module - > connect ( new_y , new_b ) ;
module - > connect ( new_conn ) ;
continue ;
}
2020-04-24 20:15:29 +02:00
if ( cell - > type . in ( ID ( $ xor ) , ID ( $ xnor ) ) & & i = = GRP_CONST_A ) {
2020-04-24 03:15:07 +02:00
SigSpec undef_a , undef_y , undef_b ;
SigSpec def_y , def_a , def_b ;
2020-04-24 20:15:29 +02:00
for ( int i = 0 ; i < GetSize ( new_y ) ; i + + ) {
bool undef = new_a [ i ] = = State : : Sx | | new_a [ i ] = = State : : Sz ;
if ( ! keepdc & & ( undef | | new_a [ i ] = = new_b [ i ] ) ) {
2020-04-24 03:15:07 +02:00
undef_a . append ( new_a [ i ] ) ;
if ( cell - > type = = ID ( $ xor ) )
undef_b . append ( State : : S0 ) ;
2020-04-24 20:15:29 +02:00
// For consistency since simplemap does $xnor -> $_XOR_ + $_NOT_
2020-04-24 03:15:07 +02:00
else if ( cell - > type = = ID ( $ xnor ) )
undef_b . append ( State : : S1 ) ;
else log_abort ( ) ;
undef_y . append ( new_y [ i ] ) ;
}
2020-04-24 20:15:29 +02:00
else if ( new_a [ i ] = = State : : S0 | | new_a [ i ] = = State : : S1 ) {
undef_a . append ( new_a [ i ] ) ;
if ( cell - > type = = ID ( $ xor ) )
2024-11-12 02:06:11 +01:00
undef_b . append ( new_a [ i ] = = State : : S1 ? module - > Not ( NEW_ID2_SUFFIX ( " grp_undef_b " ) , new_b [ i ] , false , cell - > get_src_attribute ( ) ) . as_bit ( ) : new_b [ i ] ) ; // SILIMATE: Improve the naming
2020-04-24 20:15:29 +02:00
else if ( cell - > type = = ID ( $ xnor ) )
2024-11-12 02:06:11 +01:00
undef_b . append ( new_a [ i ] = = State : : S1 ? new_b [ i ] : module - > Not ( NEW_ID2_SUFFIX ( " grp_undef_b " ) , new_b [ i ] , false , cell - > get_src_attribute ( ) ) . as_bit ( ) ) ; // SILIMATE: Improve the naming
2020-04-24 20:15:29 +02:00
else log_abort ( ) ;
undef_y . append ( new_y [ i ] ) ;
}
2020-04-24 03:15:07 +02:00
else {
def_a . append ( new_a [ i ] ) ;
def_b . append ( new_b [ i ] ) ;
def_y . append ( new_y [ i ] ) ;
}
2020-04-24 20:15:29 +02:00
}
2020-04-24 03:15:07 +02:00
if ( ! undef_y . empty ( ) ) {
log_debug ( " Direct Connection: %s (%s with %s) \n " , log_signal ( undef_b ) , log_id ( cell - > type ) , log_signal ( undef_a ) ) ;
module - > connect ( undef_y , undef_b ) ;
2020-04-24 20:15:29 +02:00
if ( def_y . empty ( ) ) {
module - > connect ( new_conn ) ;
continue ;
}
2020-04-24 03:15:07 +02:00
}
new_a = std : : move ( def_a ) ;
new_b = std : : move ( def_b ) ;
new_y = std : : move ( def_y ) ;
}
2024-11-12 02:06:11 +01:00
// SILIMATE: New cell takes on old cell's name
RTLIL : : IdString cell_name = cell - > name ;
module - > rename ( cell - > name , NEW_ID ) ;
2024-11-12 12:44:22 +01:00
RTLIL : : Cell * c = module - > addCell ( NEW_ID3 , cell - > type ) ;
2024-11-12 02:06:11 +01:00
c - > set_src_attribute ( cell - > get_src_attribute ( ) ) ;
2014-07-21 16:34:16 +02:00
2019-08-15 23:50:10 +02:00
c - > setPort ( ID : : A , new_a ) ;
2020-04-02 18:51:32 +02:00
c - > parameters [ ID : : A_WIDTH ] = new_a . size ( ) ;
c - > parameters [ ID : : A_SIGNED ] = false ;
2014-07-21 16:34:16 +02:00
2019-08-15 23:50:10 +02:00
if ( b_name = = ID : : B ) {
c - > setPort ( ID : : B , new_b ) ;
2020-04-02 18:51:32 +02:00
c - > parameters [ ID : : B_WIDTH ] = new_b . size ( ) ;
c - > parameters [ ID : : B_SIGNED ] = false ;
2014-07-21 16:34:16 +02:00
}
2019-08-15 23:50:10 +02:00
c - > setPort ( ID : : Y , new_y ) ;
2020-04-24 03:15:07 +02:00
c - > parameters [ ID : : Y_WIDTH ] = GetSize ( new_y ) ;
2014-07-21 16:34:16 +02:00
c - > check ( ) ;
2014-07-26 14:32:50 +02:00
module - > connect ( new_conn ) ;
2014-07-21 16:34:16 +02:00
2019-04-22 17:25:52 +02:00
log_debug ( " New cell `%s': A=%s " , log_id ( c ) , log_signal ( new_a ) ) ;
2019-08-15 23:50:10 +02:00
if ( b_name = = ID : : B )
2019-04-22 17:25:52 +02:00
log_debug ( " , B=%s " , log_signal ( new_b ) ) ;
log_debug ( " \n " ) ;
2014-07-21 16:34:16 +02:00
}
2016-03-31 08:43:28 +02:00
cover_list ( " opt.opt_expr.fine.group " , " $not " , " $pos " , " $and " , " $or " , " $xor " , " $xnor " , cell - > type . str ( ) ) ;
2014-07-24 19:36:43 +02:00
2014-07-21 16:34:16 +02:00
module - > remove ( cell ) ;
did_something = true ;
return true ;
}
2015-07-01 10:49:21 +02:00
void handle_polarity_inv ( Cell * cell , IdString port , IdString param , const SigMap & assign_map , const dict < RTLIL : : SigSpec , RTLIL : : SigSpec > & invert_map )
{
SigSpec sig = assign_map ( cell - > getPort ( port ) ) ;
if ( invert_map . count ( sig ) ) {
2019-04-22 17:25:52 +02:00
log_debug ( " Inverting %s of %s cell `%s' in module `%s': %s -> %s \n " ,
2015-07-01 10:49:21 +02:00
log_id ( port ) , log_id ( cell - > type ) , log_id ( cell ) , log_id ( cell - > module ) ,
log_signal ( sig ) , log_signal ( invert_map . at ( sig ) ) ) ;
cell - > setPort ( port , ( invert_map . at ( sig ) ) ) ;
cell - > setParam ( param , ! cell - > getParam ( param ) . as_bool ( ) ) ;
}
}
void handle_clkpol_celltype_swap ( Cell * cell , string type1 , string type2 , IdString port , const SigMap & assign_map , const dict < RTLIL : : SigSpec , RTLIL : : SigSpec > & invert_map )
{
log_assert ( GetSize ( type1 ) = = GetSize ( type2 ) ) ;
string cell_type = cell - > type . str ( ) ;
if ( GetSize ( type1 ) ! = GetSize ( cell_type ) )
return ;
for ( int i = 0 ; i < GetSize ( type1 ) ; i + + ) {
log_assert ( ( type1 [ i ] = = ' ? ' ) = = ( type2 [ i ] = = ' ? ' ) ) ;
if ( type1 [ i ] = = ' ? ' ) {
if ( cell_type [ i ] ! = ' 0 ' & & cell_type [ i ] ! = ' 1 ' & & cell_type [ i ] ! = ' N ' & & cell_type [ i ] ! = ' P ' )
return ;
type1 [ i ] = cell_type [ i ] ;
type2 [ i ] = cell_type [ i ] ;
}
}
if ( cell - > type . in ( type1 , type2 ) ) {
SigSpec sig = assign_map ( cell - > getPort ( port ) ) ;
if ( invert_map . count ( sig ) ) {
2019-04-22 17:25:52 +02:00
log_debug ( " Inverting %s of %s cell `%s' in module `%s': %s -> %s \n " ,
2015-07-01 10:49:21 +02:00
log_id ( port ) , log_id ( cell - > type ) , log_id ( cell ) , log_id ( cell - > module ) ,
log_signal ( sig ) , log_signal ( invert_map . at ( sig ) ) ) ;
cell - > setPort ( port , ( invert_map . at ( sig ) ) ) ;
cell - > type = cell - > type = = type1 ? type2 : type1 ;
}
}
}
2015-09-25 17:27:06 +02:00
bool is_one_or_minus_one ( const Const & value , bool is_signed , bool & is_negative )
{
bool all_bits_one = true ;
bool last_bit_one = true ;
2024-10-09 19:39:45 +02:00
if ( GetSize ( value ) < 1 )
2015-09-25 17:27:06 +02:00
return false ;
2024-10-09 19:39:45 +02:00
if ( GetSize ( value ) = = 1 ) {
if ( value [ 0 ] ! = State : : S1 )
2015-09-25 17:27:06 +02:00
return false ;
if ( is_signed )
is_negative = true ;
return true ;
}
2024-10-09 19:39:45 +02:00
for ( int i = 0 ; i < GetSize ( value ) ; i + + ) {
if ( value [ i ] ! = State : : S1 )
2015-09-25 17:27:06 +02:00
all_bits_one = false ;
2024-10-09 19:39:45 +02:00
if ( value [ i ] ! = ( i ? State : : S0 : State : : S1 ) )
2015-09-25 17:27:06 +02:00
last_bit_one = false ;
}
if ( all_bits_one & & is_signed ) {
is_negative = true ;
return true ;
}
return last_bit_one ;
}
2017-01-31 16:20:56 +01:00
2019-01-02 06:04:28 +01:00
int get_highest_hot_index ( RTLIL : : SigSpec signal )
{
for ( int i = GetSize ( signal ) - 1 ; i > = 0 ; i - - )
{
if ( signal [ i ] = = RTLIL : : State : : S0 )
continue ;
if ( signal [ i ] = = RTLIL : : State : : S1 )
return i ;
break ;
}
return - 1 ;
}
2020-07-24 13:08:54 +02:00
void replace_const_cells ( RTLIL : : Design * design , RTLIL : : Module * module , bool consume_x , bool mux_undef , bool mux_bool , bool do_fine , bool keepdc , bool noclkinv )
2013-01-05 11:13:26 +01:00
{
SigMap assign_map ( module ) ;
2014-12-26 10:53:21 +01:00
dict < RTLIL : : SigSpec , RTLIL : : SigSpec > invert_map ;
2013-01-05 11:13:26 +01:00
2024-01-31 13:21:43 +01:00
for ( auto cell : module - > cells ( ) ) {
2014-07-27 14:50:25 +02:00
if ( design - > selected ( module , cell ) & & cell - > type [ 0 ] = = ' $ ' ) {
2019-08-09 18:58:14 +02:00
if ( cell - > type . in ( ID ( $ _NOT_ ) , ID ( $ not ) , ID ( $ logic_not ) ) & &
2019-08-22 17:05:01 +02:00
GetSize ( cell - > getPort ( ID : : A ) ) = = 1 & & GetSize ( cell - > getPort ( ID : : Y ) ) = = 1 )
2019-08-15 23:50:10 +02:00
invert_map [ assign_map ( cell - > getPort ( ID : : Y ) ) ] = assign_map ( cell - > getPort ( ID : : A ) ) ;
2019-08-09 18:58:14 +02:00
if ( cell - > type . in ( ID ( $ mux ) , ID ( $ _MUX_ ) ) & &
2019-08-15 23:50:10 +02:00
cell - > getPort ( ID : : A ) = = SigSpec ( State : : S1 ) & & cell - > getPort ( ID : : B ) = = SigSpec ( State : : S0 ) )
2020-04-02 18:51:32 +02:00
invert_map [ assign_map ( cell - > getPort ( ID : : Y ) ) ] = assign_map ( cell - > getPort ( ID : : S ) ) ;
2014-02-02 21:46:42 +01:00
}
2024-01-31 13:21:43 +01:00
}
2013-01-05 11:13:26 +01:00
2024-01-31 13:24:12 +01:00
CellTypes ct_memcells ;
ct_memcells . setup_stdcells_mem ( ) ;
2024-01-31 13:21:43 +01:00
if ( ! noclkinv )
for ( auto cell : module - > cells ( ) )
if ( design - > selected ( module , cell ) ) {
if ( cell - > type . in ( ID ( $ dff ) , ID ( $ dffe ) , ID ( $ dffsr ) , ID ( $ dffsre ) , ID ( $ adff ) , ID ( $ adffe ) , ID ( $ aldff ) , ID ( $ aldffe ) , ID ( $ sdff ) , ID ( $ sdffe ) , ID ( $ sdffce ) , ID ( $ fsm ) , ID ( $ memrd ) , ID ( $ memrd_v2 ) , ID ( $ memwr ) , ID ( $ memwr_v2 ) ) )
handle_polarity_inv ( cell , ID : : CLK , ID : : CLK_POLARITY , assign_map , invert_map ) ;
2014-07-27 14:50:25 +02:00
2024-01-31 13:21:43 +01:00
if ( cell - > type . in ( ID ( $ sr ) , ID ( $ dffsr ) , ID ( $ dffsre ) , ID ( $ dlatchsr ) ) ) {
handle_polarity_inv ( cell , ID : : SET , ID : : SET_POLARITY , assign_map , invert_map ) ;
handle_polarity_inv ( cell , ID : : CLR , ID : : CLR_POLARITY , assign_map , invert_map ) ;
}
2014-07-27 14:50:25 +02:00
2024-01-31 13:21:43 +01:00
if ( cell - > type . in ( ID ( $ adff ) , ID ( $ adffe ) , ID ( $ adlatch ) ) )
handle_polarity_inv ( cell , ID : : ARST , ID : : ARST_POLARITY , assign_map , invert_map ) ;
2013-01-05 11:13:26 +01:00
2024-01-31 13:21:43 +01:00
if ( cell - > type . in ( ID ( $ aldff ) , ID ( $ aldffe ) ) )
handle_polarity_inv ( cell , ID : : ALOAD , ID : : ALOAD_POLARITY , assign_map , invert_map ) ;
2015-07-01 10:49:21 +02:00
2024-01-31 13:21:43 +01:00
if ( cell - > type . in ( ID ( $ sdff ) , ID ( $ sdffe ) , ID ( $ sdffce ) ) )
handle_polarity_inv ( cell , ID : : SRST , ID : : SRST_POLARITY , assign_map , invert_map ) ;
2015-07-01 10:49:21 +02:00
2024-01-31 13:21:43 +01:00
if ( cell - > type . in ( ID ( $ dffe ) , ID ( $ adffe ) , ID ( $ aldffe ) , ID ( $ sdffe ) , ID ( $ sdffce ) , ID ( $ dffsre ) , ID ( $ dlatch ) , ID ( $ adlatch ) , ID ( $ dlatchsr ) ) )
handle_polarity_inv ( cell , ID : : EN , ID : : EN_POLARITY , assign_map , invert_map ) ;
2020-04-09 00:26:17 +02:00
2024-01-31 13:24:12 +01:00
if ( ! ct_memcells . cell_known ( cell - > type ) )
continue ;
2024-01-31 13:21:43 +01:00
handle_clkpol_celltype_swap ( cell , " $_SR_N?_ " , " $_SR_P?_ " , ID : : S , assign_map , invert_map ) ;
handle_clkpol_celltype_swap ( cell , " $_SR_?N_ " , " $_SR_?P_ " , ID : : R , assign_map , invert_map ) ;
2021-10-02 01:23:43 +02:00
2024-01-31 13:21:43 +01:00
handle_clkpol_celltype_swap ( cell , " $_DFF_N_ " , " $_DFF_P_ " , ID : : C , assign_map , invert_map ) ;
2020-04-09 00:26:17 +02:00
2024-01-31 13:21:43 +01:00
handle_clkpol_celltype_swap ( cell , " $_DFFE_N?_ " , " $_DFFE_P?_ " , ID : : C , assign_map , invert_map ) ;
handle_clkpol_celltype_swap ( cell , " $_DFFE_?N_ " , " $_DFFE_?P_ " , ID : : E , assign_map , invert_map ) ;
2015-07-01 10:49:21 +02:00
2024-01-31 13:21:43 +01:00
handle_clkpol_celltype_swap ( cell , " $_DFF_N??_ " , " $_DFF_P??_ " , ID : : C , assign_map , invert_map ) ;
handle_clkpol_celltype_swap ( cell , " $_DFF_?N?_ " , " $_DFF_?P?_ " , ID : : R , assign_map , invert_map ) ;
2015-07-01 10:49:21 +02:00
2024-01-31 13:21:43 +01:00
handle_clkpol_celltype_swap ( cell , " $_DFFE_N???_ " , " $_DFFE_P???_ " , ID : : C , assign_map , invert_map ) ;
handle_clkpol_celltype_swap ( cell , " $_DFFE_?N??_ " , " $_DFFE_?P??_ " , ID : : R , assign_map , invert_map ) ;
handle_clkpol_celltype_swap ( cell , " $_DFFE_???N_ " , " $_DFFE_???P_ " , ID : : E , assign_map , invert_map ) ;
2015-07-01 10:49:21 +02:00
2024-01-31 13:21:43 +01:00
handle_clkpol_celltype_swap ( cell , " $_SDFF_N??_ " , " $_SDFF_P??_ " , ID : : C , assign_map , invert_map ) ;
handle_clkpol_celltype_swap ( cell , " $_SDFF_?N?_ " , " $_SDFF_?P?_ " , ID : : R , assign_map , invert_map ) ;
2015-07-01 10:49:21 +02:00
2024-01-31 13:21:43 +01:00
handle_clkpol_celltype_swap ( cell , " $_SDFFE_N???_ " , " $_SDFFE_P???_ " , ID : : C , assign_map , invert_map ) ;
handle_clkpol_celltype_swap ( cell , " $_SDFFE_?N??_ " , " $_SDFFE_?P??_ " , ID : : R , assign_map , invert_map ) ;
handle_clkpol_celltype_swap ( cell , " $_SDFFE_???N_ " , " $_SDFFE_???P_ " , ID : : E , assign_map , invert_map ) ;
2015-07-01 10:49:21 +02:00
2024-01-31 13:21:43 +01:00
handle_clkpol_celltype_swap ( cell , " $_SDFFCE_N???_ " , " $_SDFFCE_P???_ " , ID : : C , assign_map , invert_map ) ;
handle_clkpol_celltype_swap ( cell , " $_SDFFCE_?N??_ " , " $_SDFFCE_?P??_ " , ID : : R , assign_map , invert_map ) ;
handle_clkpol_celltype_swap ( cell , " $_SDFFCE_???N_ " , " $_SDFFCE_???P_ " , ID : : E , assign_map , invert_map ) ;
2020-04-09 00:26:17 +02:00
2024-01-31 13:21:43 +01:00
handle_clkpol_celltype_swap ( cell , " $_ALDFF_N?_ " , " $_ALDFF_P?_ " , ID : : C , assign_map , invert_map ) ;
handle_clkpol_celltype_swap ( cell , " $_ALDFF_?N_ " , " $_ALDFF_?P_ " , ID : : L , assign_map , invert_map ) ;
2020-04-09 00:26:17 +02:00
2024-01-31 13:21:43 +01:00
handle_clkpol_celltype_swap ( cell , " $_ALDFFE_N??_ " , " $_ALDFFE_P??_ " , ID : : C , assign_map , invert_map ) ;
handle_clkpol_celltype_swap ( cell , " $_ALDFFE_?N?_ " , " $_ALDFFE_?P?_ " , ID : : L , assign_map , invert_map ) ;
handle_clkpol_celltype_swap ( cell , " $_ALDFFE_??N_ " , " $_ALDFFE_??P_ " , ID : : E , assign_map , invert_map ) ;
2020-04-09 00:26:17 +02:00
2024-01-31 13:21:43 +01:00
handle_clkpol_celltype_swap ( cell , " $_DFFSR_N??_ " , " $_DFFSR_P??_ " , ID : : C , assign_map , invert_map ) ;
handle_clkpol_celltype_swap ( cell , " $_DFFSR_?N?_ " , " $_DFFSR_?P?_ " , ID : : S , assign_map , invert_map ) ;
handle_clkpol_celltype_swap ( cell , " $_DFFSR_??N_ " , " $_DFFSR_??P_ " , ID : : R , assign_map , invert_map ) ;
2020-04-09 00:26:17 +02:00
2024-01-31 13:21:43 +01:00
handle_clkpol_celltype_swap ( cell , " $_DFFSRE_N???_ " , " $_DFFSRE_P???_ " , ID : : C , assign_map , invert_map ) ;
handle_clkpol_celltype_swap ( cell , " $_DFFSRE_?N??_ " , " $_DFFSRE_?P??_ " , ID : : S , assign_map , invert_map ) ;
handle_clkpol_celltype_swap ( cell , " $_DFFSRE_??N?_ " , " $_DFFSRE_??P?_ " , ID : : R , assign_map , invert_map ) ;
handle_clkpol_celltype_swap ( cell , " $_DFFSRE_???N_ " , " $_DFFSRE_???P_ " , ID : : E , assign_map , invert_map ) ;
2021-10-02 01:23:43 +02:00
2024-01-31 13:21:43 +01:00
handle_clkpol_celltype_swap ( cell , " $_DLATCH_N_ " , " $_DLATCH_P_ " , ID : : E , assign_map , invert_map ) ;
2021-10-02 01:23:43 +02:00
2024-01-31 13:21:43 +01:00
handle_clkpol_celltype_swap ( cell , " $_DLATCH_N??_ " , " $_DLATCH_P??_ " , ID : : E , assign_map , invert_map ) ;
handle_clkpol_celltype_swap ( cell , " $_DLATCH_?N?_ " , " $_DLATCH_?P?_ " , ID : : R , assign_map , invert_map ) ;
2015-07-01 10:49:21 +02:00
2024-01-31 13:21:43 +01:00
handle_clkpol_celltype_swap ( cell , " $_DLATCHSR_N??_ " , " $_DLATCHSR_P??_ " , ID : : E , assign_map , invert_map ) ;
handle_clkpol_celltype_swap ( cell , " $_DLATCHSR_?N?_ " , " $_DLATCHSR_?P?_ " , ID : : S , assign_map , invert_map ) ;
handle_clkpol_celltype_swap ( cell , " $_DLATCHSR_??N_ " , " $_DLATCHSR_??P_ " , ID : : R , assign_map , invert_map ) ;
}
2020-04-09 00:26:17 +02:00
2024-01-31 13:21:43 +01:00
TopoSort < RTLIL : : Cell * , RTLIL : : IdString : : compare_ptr_by_name < RTLIL : : Cell > > cells ;
dict < RTLIL : : SigBit , Cell * > outbit_to_cell ;
2015-07-01 10:49:21 +02:00
2024-01-31 13:21:43 +01:00
for ( auto cell : module - > cells ( ) )
if ( design - > selected ( module , cell ) & & yosys_celltypes . cell_evaluable ( cell - > type ) ) {
for ( auto & conn : cell - > connections ( ) )
if ( yosys_celltypes . cell_output ( cell - > type , conn . first ) )
for ( auto bit : assign_map ( conn . second ) )
outbit_to_cell [ bit ] = cell ;
cells . node ( cell ) ;
}
2020-04-09 00:26:17 +02:00
2024-01-31 13:21:43 +01:00
for ( auto cell : module - > cells ( ) )
if ( design - > selected ( module , cell ) & & yosys_celltypes . cell_evaluable ( cell - > type ) ) {
const int r_index = cells . node ( cell ) ;
for ( auto & conn : cell - > connections ( ) )
if ( yosys_celltypes . cell_input ( cell - > type , conn . first ) )
for ( auto bit : assign_map ( conn . second ) )
if ( outbit_to_cell . count ( bit ) )
cells . edge ( cells . node ( outbit_to_cell . at ( bit ) ) , r_index ) ;
}
if ( ! cells . sort ( ) ) {
2024-06-25 20:18:49 +02:00
// There might be a combinational loop, or there might be constants on the output of cells. 'check' may find out more.
// ...unless this is a coarse-grained cell loop, but not a bit loop, in which case it won't, and all is good.
2024-07-15 11:14:47 +02:00
log ( " Couldn't topologically sort cells, optimizing module %s may take a longer time. \n " , log_id ( module ) ) ;
2024-01-31 13:21:43 +01:00
}
for ( auto cell : cells . sorted )
{
# define ACTION_DO(_p_, _s_) do { cover("opt.opt_expr.action_" S__LINE__); replace_cell(assign_map, module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0)
# define ACTION_DO_Y(_v_) ACTION_DO(ID::Y, RTLIL::SigSpec(RTLIL::State::S ## _v_))
2015-07-01 10:49:21 +02:00
2016-04-21 13:02:56 +02:00
bool detect_const_and = false ;
bool detect_const_or = false ;
2019-08-09 18:58:14 +02:00
if ( cell - > type . in ( ID ( $ reduce_and ) , ID ( $ _AND_ ) ) )
2016-04-21 13:02:56 +02:00
detect_const_and = true ;
2020-04-02 18:51:32 +02:00
if ( cell - > type . in ( ID ( $ and ) , ID ( $ logic_and ) ) & & GetSize ( cell - > getPort ( ID : : A ) ) = = 1 & & GetSize ( cell - > getPort ( ID : : B ) ) = = 1 & & ! cell - > getParam ( ID : : A_SIGNED ) . as_bool ( ) )
2016-04-21 13:02:56 +02:00
detect_const_and = true ;
2019-08-09 18:58:14 +02:00
if ( cell - > type . in ( ID ( $ reduce_or ) , ID ( $ reduce_bool ) , ID ( $ _OR_ ) ) )
2016-04-21 13:02:56 +02:00
detect_const_or = true ;
2020-04-02 18:51:32 +02:00
if ( cell - > type . in ( ID ( $ or ) , ID ( $ logic_or ) ) & & GetSize ( cell - > getPort ( ID : : A ) ) = = 1 & & GetSize ( cell - > getPort ( ID : : B ) ) = = 1 & & ! cell - > getParam ( ID : : A_SIGNED ) . as_bool ( ) )
2016-04-21 13:02:56 +02:00
detect_const_or = true ;
if ( detect_const_and | | detect_const_or )
{
2019-08-15 23:50:10 +02:00
pool < SigBit > input_bits = assign_map ( cell - > getPort ( ID : : A ) ) . to_sigbit_pool ( ) ;
2017-02-11 10:01:17 +01:00
bool found_zero = false , found_one = false , found_undef = false , found_inv = false , many_conconst = false ;
SigBit non_const_input = State : : Sm ;
2016-04-21 13:02:56 +02:00
2019-08-15 23:50:10 +02:00
if ( cell - > hasPort ( ID : : B ) ) {
vector < SigBit > more_bits = assign_map ( cell - > getPort ( ID : : B ) ) . to_sigbit_vector ( ) ;
2016-04-21 13:02:56 +02:00
input_bits . insert ( more_bits . begin ( ) , more_bits . end ( ) ) ;
}
for ( auto bit : input_bits ) {
2017-02-11 10:01:17 +01:00
if ( bit . wire ) {
if ( invert_map . count ( bit ) & & input_bits . count ( invert_map . at ( bit ) ) )
found_inv = true ;
if ( non_const_input ! = State : : Sm )
many_conconst = true ;
non_const_input = many_conconst ? State : : Sm : bit ;
} else {
if ( bit = = State : : S0 )
found_zero = true ;
else if ( bit = = State : : S1 )
found_one = true ;
else
found_undef = true ;
}
2016-04-21 13:02:56 +02:00
}
2020-05-08 20:12:43 +02:00
if ( detect_const_and & & ( found_zero | | found_inv | | ( found_undef & & consume_x ) ) ) {
2016-04-21 13:02:56 +02:00
cover ( " opt.opt_expr.const_and " ) ;
2019-08-15 23:50:10 +02:00
replace_cell ( assign_map , module , cell , " const_and " , ID : : Y , RTLIL : : State : : S0 ) ;
2016-04-21 13:02:56 +02:00
goto next_cell ;
}
2020-05-08 20:12:43 +02:00
if ( detect_const_or & & ( found_one | | found_inv | | ( found_undef & & consume_x ) ) ) {
2016-04-21 13:02:56 +02:00
cover ( " opt.opt_expr.const_or " ) ;
2019-08-15 23:50:10 +02:00
replace_cell ( assign_map , module , cell , " const_or " , ID : : Y , RTLIL : : State : : S1 ) ;
2016-04-21 13:02:56 +02:00
goto next_cell ;
}
2017-02-11 10:01:17 +01:00
if ( non_const_input ! = State : : Sm & & ! found_undef ) {
cover ( " opt.opt_expr.and_or_buffer " ) ;
2019-08-15 23:50:10 +02:00
replace_cell ( assign_map , module , cell , " and_or_buffer " , ID : : Y , non_const_input ) ;
2017-02-11 10:01:17 +01:00
goto next_cell ;
}
2016-04-21 13:02:56 +02:00
}
2020-04-02 18:51:32 +02:00
if ( cell - > type . in ( ID ( $ _XOR_ ) , ID ( $ _XNOR_ ) ) | | ( cell - > type . in ( ID ( $ xor ) , ID ( $ xnor ) ) & & GetSize ( cell - > getPort ( ID : : A ) ) = = 1 & & GetSize ( cell - > getPort ( ID : : B ) ) = = 1 & & ! cell - > getParam ( ID : : A_SIGNED ) . as_bool ( ) ) )
2020-03-20 00:33:54 +01:00
{
SigBit sig_a = assign_map ( cell - > getPort ( ID : : A ) ) ;
SigBit sig_b = assign_map ( cell - > getPort ( ID : : B ) ) ;
2020-04-24 03:15:07 +02:00
if ( ! keepdc & & ( sig_a = = sig_b | | sig_a = = State : : Sx | | sig_a = = State : : Sz | | sig_b = = State : : Sx | | sig_b = = State : : Sz ) ) {
2020-04-24 00:57:48 +02:00
if ( cell - > type . in ( ID ( $ xor ) , ID ( $ _XOR_ ) ) ) {
cover ( " opt.opt_expr.const_xor " ) ;
replace_cell ( assign_map , module , cell , " const_xor " , ID : : Y , RTLIL : : State : : S0 ) ;
goto next_cell ;
}
if ( cell - > type . in ( ID ( $ xnor ) , ID ( $ _XNOR_ ) ) ) {
cover ( " opt.opt_expr.const_xnor " ) ;
2020-04-24 20:15:29 +02:00
// For consistency since simplemap does $xnor -> $_XOR_ + $_NOT_
2020-07-29 10:00:01 +02:00
int width = GetSize ( cell - > getPort ( ID : : Y ) ) ;
2020-04-24 23:13:45 +02:00
replace_cell ( assign_map , module , cell , " const_xnor " , ID : : Y , SigSpec ( RTLIL : : State : : S1 , width ) ) ;
2020-04-24 00:57:48 +02:00
goto next_cell ;
}
log_abort ( ) ;
}
2020-03-20 00:33:54 +01:00
if ( ! sig_a . wire )
std : : swap ( sig_a , sig_b ) ;
2020-03-20 17:17:53 +01:00
if ( sig_b = = State : : S0 | | sig_b = = State : : S1 ) {
2020-03-20 00:56:39 +01:00
if ( cell - > type . in ( ID ( $ xor ) , ID ( $ _XOR_ ) ) ) {
cover ( " opt.opt_expr.xor_buffer " ) ;
2020-03-20 22:39:08 +01:00
SigSpec sig_y ;
if ( cell - > type = = ID ( $ xor ) )
2024-11-12 02:06:11 +01:00
sig_y = ( sig_b = = State : : S1 ? module - > Not ( NEW_ID2_SUFFIX ( " xor_inv " ) , sig_a , false , cell - > get_src_attribute ( ) ) . as_bit ( ) : sig_a ) ; // SILIMATE: Improve the naming
2020-03-20 22:39:08 +01:00
else if ( cell - > type = = ID ( $ _XOR_ ) )
2024-11-12 02:06:11 +01:00
sig_y = ( sig_b = = State : : S1 ? module - > NotGate ( NEW_ID2_SUFFIX ( " xor_inv " ) , sig_a , cell - > get_src_attribute ( ) ) : sig_a ) ; // SILIMATE: Improve the naming
2020-03-20 22:39:08 +01:00
else log_abort ( ) ;
replace_cell ( assign_map , module , cell , " xor_buffer " , ID : : Y , sig_y ) ;
2020-03-20 00:56:39 +01:00
goto next_cell ;
}
if ( cell - > type . in ( ID ( $ xnor ) , ID ( $ _XNOR_ ) ) ) {
cover ( " opt.opt_expr.xnor_buffer " ) ;
2020-03-20 22:39:08 +01:00
SigSpec sig_y ;
if ( cell - > type = = ID ( $ xnor ) ) {
2024-11-12 02:06:11 +01:00
sig_y = ( sig_b = = State : : S1 ? sig_a : module - > Not ( NEW_ID2_SUFFIX ( " xnor_inv " ) , sig_a , false , cell - > get_src_attribute ( ) ) . as_bit ( ) ) ; // SILIMATE: Improve the naming
2020-04-02 18:51:32 +02:00
int width = cell - > getParam ( ID : : Y_WIDTH ) . as_int ( ) ;
2020-03-20 22:39:08 +01:00
sig_y . append ( RTLIL : : Const ( State : : S1 , width - 1 ) ) ;
}
else if ( cell - > type = = ID ( $ _XNOR_ ) )
2024-11-12 02:06:11 +01:00
sig_y = ( sig_b = = State : : S1 ? sig_a : module - > NotGate ( NEW_ID2_SUFFIX ( " xnor_inv " ) , sig_a , cell - > get_src_attribute ( ) ) ) ; // SILIMATE: Improve the naming
2020-03-20 22:39:08 +01:00
else log_abort ( ) ;
replace_cell ( assign_map , module , cell , " xnor_buffer " , ID : : Y , sig_y ) ;
2020-03-20 00:56:39 +01:00
goto next_cell ;
}
2020-03-20 17:17:53 +01:00
log_abort ( ) ;
}
2020-03-20 00:33:54 +01:00
}
2019-08-09 18:58:14 +02:00
if ( cell - > type . in ( ID ( $ reduce_and ) , ID ( $ reduce_or ) , ID ( $ reduce_bool ) , ID ( $ reduce_xor ) , ID ( $ reduce_xnor ) , ID ( $ neg ) ) & &
2019-08-15 23:50:10 +02:00
GetSize ( cell - > getPort ( ID : : A ) ) = = 1 & & GetSize ( cell - > getPort ( ID : : Y ) ) = = 1 )
2016-04-21 13:02:56 +02:00
{
2019-08-09 18:58:14 +02:00
if ( cell - > type = = ID ( $ reduce_xnor ) ) {
2016-04-21 13:02:56 +02:00
cover ( " opt.opt_expr.reduce_xnor_not " ) ;
2019-04-22 17:25:52 +02:00
log_debug ( " Replacing %s cell `%s' in module `%s' with $not cell. \n " ,
2016-04-21 13:02:56 +02:00
log_id ( cell - > type ) , log_id ( cell - > name ) , log_id ( module ) ) ;
2019-08-09 18:58:14 +02:00
cell - > type = ID ( $ not ) ;
2019-04-22 17:25:52 +02:00
did_something = true ;
2016-04-21 13:02:56 +02:00
} else {
cover ( " opt.opt_expr.unary_buffer " ) ;
2019-08-15 23:50:10 +02:00
replace_cell ( assign_map , module , cell , " unary_buffer " , ID : : Y , cell - > getPort ( ID : : A ) ) ;
2016-04-21 13:02:56 +02:00
}
goto next_cell ;
}
2022-11-02 17:57:14 +01:00
if ( cell - > type . in ( ID ( $ and ) , ID ( $ or ) , ID ( $ xor ) , ID ( $ xnor ) ) )
{
RTLIL : : SigSpec sig_a = assign_map ( cell - > getPort ( ID : : A ) ) ;
RTLIL : : SigSpec sig_b = assign_map ( cell - > getPort ( ID : : B ) ) ;
bool a_fully_const = ( sig_a . is_fully_const ( ) & & ( ! keepdc | | ! sig_a . is_fully_undef ( ) ) ) ;
bool b_fully_const = ( sig_b . is_fully_const ( ) & & ( ! keepdc | | ! sig_b . is_fully_undef ( ) ) ) ;
if ( a_fully_const ! = b_fully_const )
{
cover ( " opt.opt_expr.bitwise_logic_one_const " ) ;
log_debug ( " Replacing %s cell `%s' in module `%s' having one fully constant input \n " ,
log_id ( cell - > type ) , log_id ( cell - > name ) , log_id ( module ) ) ;
RTLIL : : SigSpec sig_y = assign_map ( cell - > getPort ( ID : : Y ) ) ;
int width = GetSize ( cell - > getPort ( ID : : Y ) ) ;
sig_a . extend_u0 ( width , cell - > getParam ( ID : : A_SIGNED ) . as_bool ( ) ) ;
sig_b . extend_u0 ( width , cell - > getParam ( ID : : B_SIGNED ) . as_bool ( ) ) ;
if ( ! a_fully_const )
std : : swap ( sig_a , sig_b ) ;
RTLIL : : SigSpec b_group_0 , b_group_1 , b_group_x ;
RTLIL : : SigSpec y_group_0 , y_group_1 , y_group_x ;
for ( int i = 0 ; i < width ; i + + ) {
auto bit_a = sig_a [ i ] . data ;
if ( bit_a = = State : : S0 ) b_group_0 . append ( sig_b [ i ] ) , y_group_0 . append ( sig_y [ i ] ) ;
if ( bit_a = = State : : S1 ) b_group_1 . append ( sig_b [ i ] ) , y_group_1 . append ( sig_y [ i ] ) ;
if ( bit_a = = State : : Sx ) b_group_x . append ( sig_b [ i ] ) , y_group_x . append ( sig_y [ i ] ) ;
}
if ( cell - > type = = ID ( $ xnor ) ) {
std : : swap ( b_group_0 , b_group_1 ) ;
std : : swap ( y_group_0 , y_group_1 ) ;
}
RTLIL : : SigSpec y_new_0 , y_new_1 , y_new_x ;
2024-11-12 02:06:11 +01:00
// SILIMATE: New cell takes on old cell's name
RTLIL : : IdString cell_name = cell - > name ;
module - > rename ( cell - > name , NEW_ID ) ;
2022-11-02 17:57:14 +01:00
if ( cell - > type = = ID ( $ and ) ) {
if ( ! y_group_0 . empty ( ) ) y_new_0 = Const ( State : : S0 , GetSize ( y_group_0 ) ) ;
if ( ! y_group_1 . empty ( ) ) y_new_1 = b_group_1 ;
if ( ! y_group_x . empty ( ) ) {
if ( keepdc )
2024-11-12 12:44:22 +01:00
y_new_x = module - > And ( NEW_ID3 , Const ( State : : Sx , GetSize ( y_group_x ) ) , b_group_x , false , cell - > get_src_attribute ( ) ) ; // SILIMATE: Improve the naming
2022-11-02 17:57:14 +01:00
else
y_new_x = Const ( State : : S0 , GetSize ( y_group_x ) ) ;
}
} else if ( cell - > type = = ID ( $ or ) ) {
if ( ! y_group_0 . empty ( ) ) y_new_0 = b_group_0 ;
if ( ! y_group_1 . empty ( ) ) y_new_1 = Const ( State : : S1 , GetSize ( y_group_1 ) ) ;
if ( ! y_group_x . empty ( ) ) {
if ( keepdc )
2024-11-12 12:44:22 +01:00
y_new_x = module - > Or ( NEW_ID3 , Const ( State : : Sx , GetSize ( y_group_x ) ) , b_group_x , false , cell - > get_src_attribute ( ) ) ; // SILIMATE: Improve the naming
2022-11-02 17:57:14 +01:00
else
y_new_x = Const ( State : : S1 , GetSize ( y_group_x ) ) ;
}
} else if ( cell - > type . in ( ID ( $ xor ) , ID ( $ xnor ) ) ) {
if ( ! y_group_0 . empty ( ) ) y_new_0 = b_group_0 ;
2024-11-12 12:44:22 +01:00
if ( ! y_group_1 . empty ( ) ) y_new_1 = module - > Not ( NEW_ID3_SUFFIX ( " inv " ) , b_group_1 , false , cell - > get_src_attribute ( ) ) ; // SILIMATE: Improve the naming
2022-11-02 17:57:14 +01:00
if ( ! y_group_x . empty ( ) ) {
if ( keepdc )
2024-11-12 12:44:22 +01:00
y_new_x = module - > Xor ( NEW_ID3 , Const ( State : : Sx , GetSize ( y_group_x ) ) , b_group_x , false , cell - > get_src_attribute ( ) ) ; // SILIMATE: Improve the naming
2022-11-02 17:57:14 +01:00
else // This should be fine even with keepdc, but opt_expr_xor.ys wants to keep the xor
y_new_x = Const ( State : : Sx , GetSize ( y_group_x ) ) ;
}
} else {
log_abort ( ) ;
}
assign_map . add ( y_group_0 , y_new_0 ) ; module - > connect ( y_group_0 , y_new_0 ) ;
assign_map . add ( y_group_1 , y_new_1 ) ; module - > connect ( y_group_1 , y_new_1 ) ;
assign_map . add ( y_group_x , y_new_x ) ; module - > connect ( y_group_x , y_new_x ) ;
module - > remove ( cell ) ;
did_something = true ;
goto next_cell ;
}
}
2022-11-02 17:54:45 +01:00
if ( cell - > type = = ID ( $ bwmux ) )
{
2024-12-13 22:32:44 +01:00
RTLIL : : SigSpec inv_sig ;
2022-11-02 17:54:45 +01:00
RTLIL : : SigSpec sig_a = assign_map ( cell - > getPort ( ID : : A ) ) ;
RTLIL : : SigSpec sig_b = assign_map ( cell - > getPort ( ID : : B ) ) ;
RTLIL : : SigSpec sig_s = assign_map ( cell - > getPort ( ID : : S ) ) ;
RTLIL : : SigSpec sig_y = assign_map ( cell - > getPort ( ID : : Y ) ) ;
int width = GetSize ( cell - > getPort ( ID : : Y ) ) ;
if ( sig_s . is_fully_def ( ) )
{
RTLIL : : SigSpec a_group_0 , b_group_1 ;
RTLIL : : SigSpec y_group_0 , y_group_1 ;
for ( int i = 0 ; i < width ; i + + ) {
if ( sig_s [ i ] . data = = State : : S1 )
y_group_1 . append ( sig_y [ i ] ) , b_group_1 . append ( sig_b [ i ] ) ;
else
y_group_0 . append ( sig_y [ i ] ) , a_group_0 . append ( sig_a [ i ] ) ;
}
assign_map . add ( y_group_0 , a_group_0 ) ; module - > connect ( y_group_0 , a_group_0 ) ;
assign_map . add ( y_group_1 , b_group_1 ) ; module - > connect ( y_group_1 , b_group_1 ) ;
module - > remove ( cell ) ;
did_something = true ;
goto next_cell ;
}
else if ( sig_a . is_fully_def ( ) | | sig_b . is_fully_def ( ) )
{
2024-11-12 02:06:11 +01:00
// SILIMATE: New cell takes on old cell's name
RTLIL : : IdString cell_name = cell - > name ;
module - > rename ( cell - > name , NEW_ID ) ;
2022-11-02 17:54:45 +01:00
bool flip = ! sig_a . is_fully_def ( ) ;
if ( flip )
std : : swap ( sig_a , sig_b ) ;
RTLIL : : SigSpec b_group_0 , b_group_1 ;
RTLIL : : SigSpec s_group_0 , s_group_1 ;
RTLIL : : SigSpec y_group_0 , y_group_1 ;
for ( int i = 0 ; i < width ; i + + ) {
if ( sig_a [ i ] . data = = State : : S1 )
y_group_1 . append ( sig_y [ i ] ) , b_group_1 . append ( sig_b [ i ] ) , s_group_1 . append ( sig_s [ i ] ) ;
else
y_group_0 . append ( sig_y [ i ] ) , b_group_0 . append ( sig_b [ i ] ) , s_group_0 . append ( sig_s [ i ] ) ;
}
RTLIL : : SigSpec y_new_0 , y_new_1 ;
if ( flip ) {
2024-12-13 22:32:44 +01:00
if ( ! y_group_0 . empty ( ) ) {
inv_sig = module - > Not ( NEW_ID3_SUFFIX ( " inv " ) , s_group_0 , false , cell - > get_src_attribute ( ) ) ; // SILIMATE: Improve the naming
y_new_0 = module - > And ( NEW_ID3 , b_group_0 , inv_sig , false , cell - > get_src_attribute ( ) ) ; // SILIMATE: Improve the naming
}
2024-11-12 12:44:22 +01:00
if ( ! y_group_1 . empty ( ) ) y_new_1 = module - > Or ( NEW_ID3 , b_group_1 , s_group_1 , false , cell - > get_src_attribute ( ) ) ; // SILIMATE: Improve the naming
2022-11-02 17:54:45 +01:00
} else {
2024-11-12 12:44:22 +01:00
if ( ! y_group_0 . empty ( ) ) y_new_0 = module - > And ( NEW_ID3 , b_group_0 , s_group_0 , false , cell - > get_src_attribute ( ) ) ; // SILIMATE: Improve the naming
2024-12-13 22:32:44 +01:00
if ( ! y_group_1 . empty ( ) ) {
inv_sig = module - > Not ( NEW_ID3_SUFFIX ( " inv " ) , s_group_1 , false , cell - > get_src_attribute ( ) ) ; // SILIMATE: Improve the naming
y_new_1 = module - > Or ( NEW_ID3 , b_group_1 , inv_sig , false , cell - > get_src_attribute ( ) ) ; // SILIMATE: Improve the naming
}
2022-11-02 17:54:45 +01:00
}
module - > connect ( y_group_0 , y_new_0 ) ;
module - > connect ( y_group_1 , y_new_1 ) ;
module - > remove ( cell ) ;
did_something = true ;
goto next_cell ;
}
}
2014-07-21 21:38:55 +02:00
if ( do_fine )
{
2019-08-09 18:58:14 +02:00
if ( cell - > type . in ( ID ( $ not ) , ID ( $ pos ) , ID ( $ and ) , ID ( $ or ) , ID ( $ xor ) , ID ( $ xnor ) ) )
2020-04-24 03:15:07 +02:00
if ( group_cell_inputs ( module , cell , true , assign_map , keepdc ) )
2014-07-21 21:38:55 +02:00
goto next_cell ;
2019-08-09 18:58:14 +02:00
if ( cell - > type . in ( ID ( $ logic_not ) , ID ( $ logic_and ) , ID ( $ logic_or ) , ID ( $ reduce_or ) , ID ( $ reduce_and ) , ID ( $ reduce_bool ) ) )
2017-07-26 18:28:55 +02:00
{
2019-08-09 18:58:14 +02:00
SigBit neutral_bit = cell - > type = = ID ( $ reduce_and ) ? State : : S1 : State : : S0 ;
2017-07-26 18:28:55 +02:00
2019-08-15 23:50:10 +02:00
RTLIL : : SigSpec sig_a = assign_map ( cell - > getPort ( ID : : A ) ) ;
2017-07-26 18:28:55 +02:00
RTLIL : : SigSpec new_sig_a ;
for ( auto bit : sig_a )
if ( bit ! = neutral_bit ) new_sig_a . append ( bit ) ;
if ( GetSize ( new_sig_a ) = = 0 )
new_sig_a . append ( neutral_bit ) ;
if ( GetSize ( new_sig_a ) < GetSize ( sig_a ) ) {
cover_list ( " opt.opt_expr.fine.neutral_A " , " $logic_not " , " $logic_and " , " $logic_or " , " $reduce_or " , " $reduce_and " , " $reduce_bool " , cell - > type . str ( ) ) ;
2019-04-22 17:25:52 +02:00
log_debug ( " Replacing port A of %s cell `%s' in module `%s' with shorter expression: %s -> %s \n " ,
2017-07-26 18:28:55 +02:00
cell - > type . c_str ( ) , cell - > name . c_str ( ) , module - > name . c_str ( ) , log_signal ( sig_a ) , log_signal ( new_sig_a ) ) ;
2019-08-15 23:50:10 +02:00
cell - > setPort ( ID : : A , new_sig_a ) ;
2020-04-02 18:51:32 +02:00
cell - > parameters . at ( ID : : A_WIDTH ) = GetSize ( new_sig_a ) ;
2017-07-26 18:28:55 +02:00
did_something = true ;
}
}
2019-08-09 18:58:14 +02:00
if ( cell - > type . in ( ID ( $ logic_and ) , ID ( $ logic_or ) ) )
2017-07-26 18:28:55 +02:00
{
SigBit neutral_bit = State : : S0 ;
2019-08-15 23:50:10 +02:00
RTLIL : : SigSpec sig_b = assign_map ( cell - > getPort ( ID : : B ) ) ;
2017-07-26 18:28:55 +02:00
RTLIL : : SigSpec new_sig_b ;
for ( auto bit : sig_b )
if ( bit ! = neutral_bit ) new_sig_b . append ( bit ) ;
if ( GetSize ( new_sig_b ) = = 0 )
new_sig_b . append ( neutral_bit ) ;
if ( GetSize ( new_sig_b ) < GetSize ( sig_b ) ) {
cover_list ( " opt.opt_expr.fine.neutral_B " , " $logic_and " , " $logic_or " , cell - > type . str ( ) ) ;
2019-04-22 17:25:52 +02:00
log_debug ( " Replacing port B of %s cell `%s' in module `%s' with shorter expression: %s -> %s \n " ,
2017-07-26 18:28:55 +02:00
cell - > type . c_str ( ) , cell - > name . c_str ( ) , module - > name . c_str ( ) , log_signal ( sig_b ) , log_signal ( new_sig_b ) ) ;
2019-08-15 23:50:10 +02:00
cell - > setPort ( ID : : B , new_sig_b ) ;
2020-04-02 18:51:32 +02:00
cell - > parameters . at ( ID : : B_WIDTH ) = GetSize ( new_sig_b ) ;
2017-07-26 18:28:55 +02:00
did_something = true ;
}
}
2019-08-09 18:58:14 +02:00
if ( cell - > type = = ID ( $ reduce_and ) )
2014-07-21 21:38:55 +02:00
{
2019-08-15 23:50:10 +02:00
RTLIL : : SigSpec sig_a = assign_map ( cell - > getPort ( ID : : A ) ) ;
2014-07-21 21:38:55 +02:00
RTLIL : : State new_a = RTLIL : : State : : S1 ;
for ( auto & bit : sig_a . to_sigbit_vector ( ) )
if ( bit = = RTLIL : : State : : Sx ) {
if ( new_a = = RTLIL : : State : : S1 )
new_a = RTLIL : : State : : Sx ;
} else if ( bit = = RTLIL : : State : : S0 ) {
new_a = RTLIL : : State : : S0 ;
break ;
} else if ( bit . wire ! = NULL ) {
new_a = RTLIL : : State : : Sm ;
}
if ( new_a ! = RTLIL : : State : : Sm & & RTLIL : : SigSpec ( new_a ) ! = sig_a ) {
2016-03-31 08:43:28 +02:00
cover ( " opt.opt_expr.fine.$reduce_and " ) ;
2019-04-22 17:25:52 +02:00
log_debug ( " Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s \n " ,
2014-07-21 21:38:55 +02:00
cell - > type . c_str ( ) , cell - > name . c_str ( ) , module - > name . c_str ( ) , log_signal ( sig_a ) , log_signal ( new_a ) ) ;
2019-08-15 23:50:10 +02:00
cell - > setPort ( ID : : A , sig_a = new_a ) ;
2020-04-02 18:51:32 +02:00
cell - > parameters . at ( ID : : A_WIDTH ) = 1 ;
2014-07-21 21:38:55 +02:00
did_something = true ;
}
}
2019-08-09 18:58:14 +02:00
if ( cell - > type . in ( ID ( $ logic_not ) , ID ( $ logic_and ) , ID ( $ logic_or ) , ID ( $ reduce_or ) , ID ( $ reduce_bool ) ) )
2014-07-21 21:38:55 +02:00
{
2019-08-15 23:50:10 +02:00
RTLIL : : SigSpec sig_a = assign_map ( cell - > getPort ( ID : : A ) ) ;
2014-07-21 21:38:55 +02:00
RTLIL : : State new_a = RTLIL : : State : : S0 ;
for ( auto & bit : sig_a . to_sigbit_vector ( ) )
if ( bit = = RTLIL : : State : : Sx ) {
if ( new_a = = RTLIL : : State : : S0 )
new_a = RTLIL : : State : : Sx ;
} else if ( bit = = RTLIL : : State : : S1 ) {
new_a = RTLIL : : State : : S1 ;
break ;
} else if ( bit . wire ! = NULL ) {
new_a = RTLIL : : State : : Sm ;
}
if ( new_a ! = RTLIL : : State : : Sm & & RTLIL : : SigSpec ( new_a ) ! = sig_a ) {
2016-03-31 08:43:28 +02:00
cover_list ( " opt.opt_expr.fine.A " , " $logic_not " , " $logic_and " , " $logic_or " , " $reduce_or " , " $reduce_bool " , cell - > type . str ( ) ) ;
2019-04-22 17:25:52 +02:00
log_debug ( " Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s \n " ,
2014-07-21 21:38:55 +02:00
cell - > type . c_str ( ) , cell - > name . c_str ( ) , module - > name . c_str ( ) , log_signal ( sig_a ) , log_signal ( new_a ) ) ;
2019-08-15 23:50:10 +02:00
cell - > setPort ( ID : : A , sig_a = new_a ) ;
2020-04-02 18:51:32 +02:00
cell - > parameters . at ( ID : : A_WIDTH ) = 1 ;
2014-07-21 21:38:55 +02:00
did_something = true ;
}
}
2019-08-09 18:58:14 +02:00
if ( cell - > type . in ( ID ( $ logic_and ) , ID ( $ logic_or ) ) )
2014-07-21 21:38:55 +02:00
{
2019-08-15 23:50:10 +02:00
RTLIL : : SigSpec sig_b = assign_map ( cell - > getPort ( ID : : B ) ) ;
2014-07-21 21:38:55 +02:00
RTLIL : : State new_b = RTLIL : : State : : S0 ;
for ( auto & bit : sig_b . to_sigbit_vector ( ) )
if ( bit = = RTLIL : : State : : Sx ) {
if ( new_b = = RTLIL : : State : : S0 )
new_b = RTLIL : : State : : Sx ;
} else if ( bit = = RTLIL : : State : : S1 ) {
new_b = RTLIL : : State : : S1 ;
break ;
} else if ( bit . wire ! = NULL ) {
new_b = RTLIL : : State : : Sm ;
}
if ( new_b ! = RTLIL : : State : : Sm & & RTLIL : : SigSpec ( new_b ) ! = sig_b ) {
2016-03-31 08:43:28 +02:00
cover_list ( " opt.opt_expr.fine.B " , " $logic_and " , " $logic_or " , cell - > type . str ( ) ) ;
2019-04-22 17:25:52 +02:00
log_debug ( " Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s \n " ,
2014-07-21 21:38:55 +02:00
cell - > type . c_str ( ) , cell - > name . c_str ( ) , module - > name . c_str ( ) , log_signal ( sig_b ) , log_signal ( new_b ) ) ;
2019-08-15 23:50:10 +02:00
cell - > setPort ( ID : : B , sig_b = new_b ) ;
2020-04-02 18:51:32 +02:00
cell - > parameters . at ( ID : : B_WIDTH ) = 1 ;
2014-07-21 21:38:55 +02:00
did_something = true ;
}
}
2019-08-07 00:25:50 +02:00
2019-08-15 10:22:59 +02:00
if ( cell - > type . in ( ID ( $ add ) , ID ( $ sub ) ) )
2019-08-09 19:32:12 +02:00
{
2019-08-15 23:50:10 +02:00
RTLIL : : SigSpec sig_a = assign_map ( cell - > getPort ( ID : : A ) ) ;
RTLIL : : SigSpec sig_b = assign_map ( cell - > getPort ( ID : : B ) ) ;
RTLIL : : SigSpec sig_y = cell - > getPort ( ID : : Y ) ;
2020-05-01 19:10:26 +02:00
bool is_signed = cell - > getParam ( ID : : A_SIGNED ) . as_bool ( ) ;
2019-08-09 18:58:14 +02:00
bool sub = cell - > type = = ID ( $ sub ) ;
2019-08-07 00:25:50 +02:00
2020-05-01 19:10:26 +02:00
int minsz = GetSize ( sig_y ) ;
minsz = std : : min ( minsz , GetSize ( sig_a ) ) ;
minsz = std : : min ( minsz , GetSize ( sig_b ) ) ;
2019-08-07 00:25:50 +02:00
int i ;
2020-05-01 19:10:26 +02:00
for ( i = 0 ; i < minsz ; i + + ) {
RTLIL : : SigBit b = sig_b [ i ] ;
RTLIL : : SigBit a = sig_a [ i ] ;
if ( b = = State : : S0 )
2020-03-19 22:34:10 +01:00
module - > connect ( sig_y [ i ] , a ) ;
else if ( sub & & b = = State : : S1 & & a = = State : : S1 )
module - > connect ( sig_y [ i ] , State : : S0 ) ;
2020-05-01 19:10:26 +02:00
else if ( ! sub & & a = = State : : S0 )
2020-03-19 22:34:10 +01:00
module - > connect ( sig_y [ i ] , b ) ;
2019-08-07 00:25:50 +02:00
else
break ;
}
if ( i > 0 ) {
cover_list ( " opt.opt_expr.fine " , " $add " , " $sub " , cell - > type . str ( ) ) ;
2020-05-01 19:10:26 +02:00
log_debug ( " Stripping %d LSB bits of %s cell %s in module %s. \n " , i , log_id ( cell - > type ) , log_id ( cell ) , log_id ( module ) ) ;
SigSpec new_a = sig_a . extract_end ( i ) ;
SigSpec new_b = sig_b . extract_end ( i ) ;
if ( new_a . empty ( ) & & is_signed )
new_a = sig_a [ i - 1 ] ;
if ( new_b . empty ( ) & & is_signed )
new_b = sig_b [ i - 1 ] ;
cell - > setPort ( ID : : A , new_a ) ;
cell - > setPort ( ID : : B , new_b ) ;
2019-08-15 23:50:10 +02:00
cell - > setPort ( ID : : Y , sig_y . extract_end ( i ) ) ;
2019-08-07 00:25:50 +02:00
cell - > fixup_parameters ( ) ;
did_something = true ;
}
}
2019-08-09 21:13:32 +02:00
2020-03-19 22:24:55 +01:00
if ( cell - > type = = ID ( $ alu ) )
2019-08-09 21:13:32 +02:00
{
2019-08-15 23:50:10 +02:00
RTLIL : : SigSpec sig_a = assign_map ( cell - > getPort ( ID : : A ) ) ;
RTLIL : : SigSpec sig_b = assign_map ( cell - > getPort ( ID : : B ) ) ;
2020-04-02 18:51:32 +02:00
RTLIL : : SigBit sig_ci = assign_map ( cell - > getPort ( ID : : CI ) ) ;
RTLIL : : SigBit sig_bi = assign_map ( cell - > getPort ( ID : : BI ) ) ;
RTLIL : : SigSpec sig_x = cell - > getPort ( ID : : X ) ;
2019-08-15 23:50:10 +02:00
RTLIL : : SigSpec sig_y = cell - > getPort ( ID : : Y ) ;
2020-04-02 18:51:32 +02:00
RTLIL : : SigSpec sig_co = cell - > getPort ( ID : : CO ) ;
2020-05-02 21:34:24 +02:00
bool is_signed = cell - > getParam ( ID : : A_SIGNED ) . as_bool ( ) ;
2019-08-09 21:13:32 +02:00
2020-04-13 19:29:39 +02:00
if ( sig_bi ! = State : : S0 & & sig_bi ! = State : : S1 )
goto skip_fine_alu ;
if ( sig_ci ! = State : : S0 & & sig_ci ! = State : : S1 )
goto skip_fine_alu ;
2019-08-09 21:13:32 +02:00
2020-04-13 19:29:39 +02:00
bool bi = sig_bi = = State : : S1 ;
bool ci = sig_ci = = State : : S1 ;
2019-08-09 21:13:32 +02:00
2020-05-02 21:34:24 +02:00
int minsz = GetSize ( sig_y ) ;
minsz = std : : min ( minsz , GetSize ( sig_a ) ) ;
minsz = std : : min ( minsz , GetSize ( sig_b ) ) ;
2019-08-09 21:13:32 +02:00
int i ;
2020-05-02 21:34:24 +02:00
for ( i = 0 ; i < minsz ; i + + ) {
RTLIL : : SigBit b = sig_b [ i ] ;
RTLIL : : SigBit a = sig_a [ i ] ;
if ( b = = ( ( bi ^ ci ) ? State : : S1 : State : : S0 ) ) {
2020-04-13 19:29:39 +02:00
module - > connect ( sig_y [ i ] , a ) ;
2024-12-17 19:48:28 +01:00
module - > connect ( sig_x [ i ] , ci ? module - > Not ( NEW_ID2_SUFFIX ( " x_inv " ) , a , false , cell - > get_src_attribute ( ) ) . as_bit ( ) : a ) ; // SILIMATE: Improve the naming
2020-04-13 19:29:39 +02:00
module - > connect ( sig_co [ i ] , ci ? State : : S1 : State : : S0 ) ;
2020-03-19 22:34:10 +01:00
}
2020-05-02 21:34:24 +02:00
else if ( a = = ( ci ? State : : S1 : State : : S0 ) ) {
2024-12-17 19:48:28 +01:00
module - > connect ( sig_y [ i ] , bi ? module - > Not ( NEW_ID2_SUFFIX ( " y_inv " ) , b , false , cell - > get_src_attribute ( ) ) . as_bit ( ) : b ) ; // SILIMATE: Improve the naming
module - > connect ( sig_x [ i ] , ( bi ^ ci ) ? module - > Not ( NEW_ID2_SUFFIX ( " x_inv " ) , b , false , cell - > get_src_attribute ( ) ) . as_bit ( ) : b ) ; // SILIMATE: Improve the naming
2020-04-13 19:29:39 +02:00
module - > connect ( sig_co [ i ] , ci ? State : : S1 : State : : S0 ) ;
2019-08-09 21:13:32 +02:00
}
else
break ;
}
if ( i > 0 ) {
2019-08-10 20:55:00 +02:00
cover ( " opt.opt_expr.fine.$alu " ) ;
2020-05-02 21:34:24 +02:00
log_debug ( " Stripping %d LSB bits of %s cell %s in module %s. \n " , i , log_id ( cell - > type ) , log_id ( cell ) , log_id ( module ) ) ;
SigSpec new_a = sig_a . extract_end ( i ) ;
SigSpec new_b = sig_b . extract_end ( i ) ;
if ( new_a . empty ( ) & & is_signed )
new_a = sig_a [ i - 1 ] ;
if ( new_b . empty ( ) & & is_signed )
new_b = sig_b [ i - 1 ] ;
cell - > setPort ( ID : : A , new_a ) ;
cell - > setPort ( ID : : B , new_b ) ;
2020-04-02 18:51:32 +02:00
cell - > setPort ( ID : : X , sig_x . extract_end ( i ) ) ;
2019-08-15 23:50:10 +02:00
cell - > setPort ( ID : : Y , sig_y . extract_end ( i ) ) ;
2020-04-02 18:51:32 +02:00
cell - > setPort ( ID : : CO , sig_co . extract_end ( i ) ) ;
2019-08-07 00:25:50 +02:00
cell - > fixup_parameters ( ) ;
did_something = true ;
}
}
2014-07-21 21:38:55 +02:00
}
2020-04-13 19:29:39 +02:00
skip_fine_alu :
2014-07-21 21:38:55 +02:00
2019-08-09 18:58:14 +02:00
if ( cell - > type . in ( ID ( $ reduce_xor ) , ID ( $ reduce_xnor ) , ID ( $ shift ) , ID ( $ shiftx ) , ID ( $ shl ) , ID ( $ shr ) , ID ( $ sshl ) , ID ( $ sshr ) ,
2020-04-21 12:51:58 +02:00
ID ( $ lt ) , ID ( $ le ) , ID ( $ ge ) , ID ( $ gt ) , ID ( $ neg ) , ID ( $ add ) , ID ( $ sub ) , ID ( $ mul ) , ID ( $ div ) , ID ( $ mod ) , ID ( $ divfloor ) , ID ( $ modfloor ) , ID ( $ pow ) ) )
2014-07-21 21:38:55 +02:00
{
2019-08-15 23:50:10 +02:00
RTLIL : : SigSpec sig_a = assign_map ( cell - > getPort ( ID : : A ) ) ;
RTLIL : : SigSpec sig_b = cell - > hasPort ( ID : : B ) ? assign_map ( cell - > getPort ( ID : : B ) ) : RTLIL : : SigSpec ( ) ;
2014-07-21 21:38:55 +02:00
2019-08-09 18:58:14 +02:00
if ( cell - > type . in ( ID ( $ shl ) , ID ( $ shr ) , ID ( $ sshl ) , ID ( $ sshr ) , ID ( $ shift ) , ID ( $ shiftx ) ) )
2014-07-21 21:38:55 +02:00
sig_a = RTLIL : : SigSpec ( ) ;
for ( auto & bit : sig_a . to_sigbit_vector ( ) )
if ( bit = = RTLIL : : State : : Sx )
goto found_the_x_bit ;
for ( auto & bit : sig_b . to_sigbit_vector ( ) )
if ( bit = = RTLIL : : State : : Sx )
goto found_the_x_bit ;
if ( 0 ) {
found_the_x_bit :
2016-03-31 08:43:28 +02:00
cover_list ( " opt.opt_expr.xbit " , " $reduce_xor " , " $reduce_xnor " , " $shl " , " $shr " , " $sshl " , " $sshr " , " $shift " , " $shiftx " ,
2020-04-21 12:51:58 +02:00
" $lt " , " $le " , " $ge " , " $gt " , " $neg " , " $add " , " $sub " , " $mul " , " $div " , " $mod " , " $divfloor " , " $modfloor " , " $pow " , cell - > type . str ( ) ) ;
2019-08-09 18:58:14 +02:00
if ( cell - > type . in ( ID ( $ reduce_xor ) , ID ( $ reduce_xnor ) , ID ( $ lt ) , ID ( $ le ) , ID ( $ ge ) , ID ( $ gt ) ) )
2019-08-15 23:50:10 +02:00
replace_cell ( assign_map , module , cell , " x-bit in input " , ID : : Y , RTLIL : : State : : Sx ) ;
2014-07-21 21:38:55 +02:00
else
2019-08-22 17:05:01 +02:00
replace_cell ( assign_map , module , cell , " x-bit in input " , ID : : Y , RTLIL : : SigSpec ( RTLIL : : State : : Sx , GetSize ( cell - > getPort ( ID : : Y ) ) ) ) ;
2014-07-21 16:34:16 +02:00
goto next_cell ;
2014-07-21 21:38:55 +02:00
}
}
2014-07-21 16:34:16 +02:00
2022-11-30 17:35:48 +01:00
if ( cell - > type . in ( ID ( $ shiftx ) , ID ( $ shift ) ) & & ( cell - > type = = ID ( $ shiftx ) | | ! cell - > getParam ( ID : : A_SIGNED ) . as_bool ( ) ) ) {
2019-08-22 04:18:05 +02:00
SigSpec sig_a = assign_map ( cell - > getPort ( ID : : A ) ) ;
int width ;
2019-08-22 17:37:27 +02:00
bool trim_x = cell - > type = = ID ( $ shiftx ) | | ! keepdc ;
2019-08-22 17:22:23 +02:00
bool trim_0 = cell - > type = = ID ( $ shift ) ;
2019-08-22 04:18:05 +02:00
for ( width = GetSize ( sig_a ) ; width > 1 ; width - - ) {
2019-08-22 17:22:23 +02:00
if ( ( trim_x & & sig_a [ width - 1 ] = = State : : Sx ) | |
( trim_0 & & sig_a [ width - 1 ] = = State : : S0 ) )
continue ;
break ;
2019-08-22 04:18:05 +02:00
}
if ( width < GetSize ( sig_a ) ) {
2019-08-22 17:43:44 +02:00
cover_list ( " opt.opt_expr.trim " , " $shiftx " , " $shift " , cell - > type . str ( ) ) ;
2019-08-22 04:18:05 +02:00
sig_a . remove ( width , GetSize ( sig_a ) - width ) ;
cell - > setPort ( ID : : A , sig_a ) ;
2020-04-02 18:51:32 +02:00
cell - > setParam ( ID : : A_WIDTH , width ) ;
2019-08-22 04:18:05 +02:00
did_something = true ;
goto next_cell ;
}
}
2019-08-22 17:05:01 +02:00
if ( cell - > type . in ( ID ( $ _NOT_ ) , ID ( $ not ) , ID ( $ logic_not ) ) & & GetSize ( cell - > getPort ( ID : : Y ) ) = = 1 & &
2019-08-15 23:50:10 +02:00
invert_map . count ( assign_map ( cell - > getPort ( ID : : A ) ) ) ! = 0 ) {
2016-03-31 08:43:28 +02:00
cover_list ( " opt.opt_expr.invert.double " , " $_NOT_ " , " $not " , " $logic_not " , cell - > type . str ( ) ) ;
2019-08-15 23:50:10 +02:00
replace_cell ( assign_map , module , cell , " double_invert " , ID : : Y , invert_map . at ( assign_map ( cell - > getPort ( ID : : A ) ) ) ) ;
2014-02-02 21:46:42 +01:00
goto next_cell ;
}
2020-04-02 18:51:32 +02:00
if ( cell - > type . in ( ID ( $ _MUX_ ) , ID ( $ mux ) ) & & invert_map . count ( assign_map ( cell - > getPort ( ID : : S ) ) ) ! = 0 ) {
2016-03-31 08:43:28 +02:00
cover_list ( " opt.opt_expr.invert.muxsel " , " $_MUX_ " , " $mux " , cell - > type . str ( ) ) ;
2019-04-22 17:25:52 +02:00
log_debug ( " Optimizing away select inverter for %s cell `%s' in module `%s'. \n " , log_id ( cell - > type ) , log_id ( cell ) , log_id ( module ) ) ;
2019-08-15 23:50:10 +02:00
RTLIL : : SigSpec tmp = cell - > getPort ( ID : : A ) ;
cell - > setPort ( ID : : A , cell - > getPort ( ID : : B ) ) ;
cell - > setPort ( ID : : B , tmp ) ;
2020-04-02 18:51:32 +02:00
cell - > setPort ( ID : : S , invert_map . at ( assign_map ( cell - > getPort ( ID : : S ) ) ) ) ;
2014-02-02 21:46:42 +01:00
did_something = true ;
goto next_cell ;
}
2019-08-09 18:58:14 +02:00
if ( cell - > type = = ID ( $ _NOT_ ) ) {
2019-08-15 23:50:10 +02:00
RTLIL : : SigSpec input = cell - > getPort ( ID : : A ) ;
2013-01-05 11:13:26 +01:00
assign_map . apply ( input ) ;
if ( input . match ( " 1 " ) ) ACTION_DO_Y ( 0 ) ;
if ( input . match ( " 0 " ) ) ACTION_DO_Y ( 1 ) ;
if ( input . match ( " * " ) ) ACTION_DO_Y ( x ) ;
}
2019-08-09 18:58:14 +02:00
if ( cell - > type = = ID ( $ _AND_ ) ) {
2013-01-05 11:13:26 +01:00
RTLIL : : SigSpec input ;
2019-08-15 23:50:10 +02:00
input . append ( cell - > getPort ( ID : : B ) ) ;
input . append ( cell - > getPort ( ID : : A ) ) ;
2013-01-05 11:13:26 +01:00
assign_map . apply ( input ) ;
if ( input . match ( " 0 " ) ) ACTION_DO_Y ( 0 ) ;
if ( input . match ( " 0 " ) ) ACTION_DO_Y ( 0 ) ;
if ( input . match ( " 11 " ) ) ACTION_DO_Y ( 1 ) ;
2013-05-17 14:55:18 +02:00
if ( input . match ( " ** " ) ) ACTION_DO_Y ( x ) ;
if ( input . match ( " 1* " ) ) ACTION_DO_Y ( x ) ;
if ( input . match ( " *1 " ) ) ACTION_DO_Y ( x ) ;
if ( consume_x ) {
if ( input . match ( " * " ) ) ACTION_DO_Y ( 0 ) ;
if ( input . match ( " * " ) ) ACTION_DO_Y ( 0 ) ;
}
2019-08-15 23:50:10 +02:00
if ( input . match ( " 1 " ) ) ACTION_DO ( ID : : Y , input . extract ( 1 , 1 ) ) ;
if ( input . match ( " 1 " ) ) ACTION_DO ( ID : : Y , input . extract ( 0 , 1 ) ) ;
2013-01-05 11:13:26 +01:00
}
2019-08-09 18:58:14 +02:00
if ( cell - > type = = ID ( $ _OR_ ) ) {
2013-01-05 11:13:26 +01:00
RTLIL : : SigSpec input ;
2019-08-15 23:50:10 +02:00
input . append ( cell - > getPort ( ID : : B ) ) ;
input . append ( cell - > getPort ( ID : : A ) ) ;
2013-01-05 11:13:26 +01:00
assign_map . apply ( input ) ;
if ( input . match ( " 1 " ) ) ACTION_DO_Y ( 1 ) ;
if ( input . match ( " 1 " ) ) ACTION_DO_Y ( 1 ) ;
if ( input . match ( " 00 " ) ) ACTION_DO_Y ( 0 ) ;
2013-05-17 14:55:18 +02:00
if ( input . match ( " ** " ) ) ACTION_DO_Y ( x ) ;
if ( input . match ( " 0* " ) ) ACTION_DO_Y ( x ) ;
if ( input . match ( " *0 " ) ) ACTION_DO_Y ( x ) ;
if ( consume_x ) {
if ( input . match ( " * " ) ) ACTION_DO_Y ( 1 ) ;
if ( input . match ( " * " ) ) ACTION_DO_Y ( 1 ) ;
}
2019-08-15 23:50:10 +02:00
if ( input . match ( " 0 " ) ) ACTION_DO ( ID : : Y , input . extract ( 1 , 1 ) ) ;
if ( input . match ( " 0 " ) ) ACTION_DO ( ID : : Y , input . extract ( 0 , 1 ) ) ;
2013-01-05 11:13:26 +01:00
}
2019-08-09 18:58:14 +02:00
if ( cell - > type = = ID ( $ _XOR_ ) ) {
2013-01-05 11:13:26 +01:00
RTLIL : : SigSpec input ;
2019-08-15 23:50:10 +02:00
input . append ( cell - > getPort ( ID : : B ) ) ;
input . append ( cell - > getPort ( ID : : A ) ) ;
2013-01-05 11:13:26 +01:00
assign_map . apply ( input ) ;
if ( input . match ( " 00 " ) ) ACTION_DO_Y ( 0 ) ;
if ( input . match ( " 01 " ) ) ACTION_DO_Y ( 1 ) ;
if ( input . match ( " 10 " ) ) ACTION_DO_Y ( 1 ) ;
if ( input . match ( " 11 " ) ) ACTION_DO_Y ( 0 ) ;
2020-05-08 20:07:44 +02:00
if ( consume_x ) {
2020-04-24 03:15:07 +02:00
if ( input . match ( " * " ) ) ACTION_DO_Y ( 0 ) ;
if ( input . match ( " * " ) ) ACTION_DO_Y ( 0 ) ;
2020-04-24 00:57:48 +02:00
}
2013-01-05 11:13:26 +01:00
}
2019-08-09 18:58:14 +02:00
if ( cell - > type = = ID ( $ _MUX_ ) ) {
2013-01-05 11:13:26 +01:00
RTLIL : : SigSpec input ;
2020-04-02 18:51:32 +02:00
input . append ( cell - > getPort ( ID : : S ) ) ;
2019-08-15 23:50:10 +02:00
input . append ( cell - > getPort ( ID : : B ) ) ;
input . append ( cell - > getPort ( ID : : A ) ) ;
2013-01-05 11:13:26 +01:00
assign_map . apply ( input ) ;
if ( input . extract ( 2 , 1 ) = = input . extract ( 1 , 1 ) )
2019-08-15 23:50:10 +02:00
ACTION_DO ( ID : : Y , input . extract ( 2 , 1 ) ) ;
if ( input . match ( " 0 " ) ) ACTION_DO ( ID : : Y , input . extract ( 2 , 1 ) ) ;
if ( input . match ( " 1 " ) ) ACTION_DO ( ID : : Y , input . extract ( 1 , 1 ) ) ;
if ( input . match ( " 01 " ) ) ACTION_DO ( ID : : Y , input . extract ( 0 , 1 ) ) ;
2013-12-28 10:30:31 +01:00
if ( input . match ( " 10 " ) ) {
2016-03-31 08:43:28 +02:00
cover ( " opt.opt_expr.mux_to_inv " ) ;
2019-08-09 18:58:14 +02:00
cell - > type = ID ( $ _NOT_ ) ;
2019-08-15 23:50:10 +02:00
cell - > setPort ( ID : : A , input . extract ( 0 , 1 ) ) ;
cell - > unsetPort ( ID : : B ) ;
2020-04-02 18:51:32 +02:00
cell - > unsetPort ( ID : : S ) ;
2013-12-28 10:30:31 +01:00
goto next_cell ;
}
2014-01-14 11:10:29 +01:00
if ( input . match ( " 11 " ) ) ACTION_DO_Y ( 1 ) ;
if ( input . match ( " 00 " ) ) ACTION_DO_Y ( 0 ) ;
if ( input . match ( " ** " ) ) ACTION_DO_Y ( x ) ;
2013-12-28 10:30:31 +01:00
if ( input . match ( " 01* " ) ) ACTION_DO_Y ( x ) ;
if ( input . match ( " 10* " ) ) ACTION_DO_Y ( x ) ;
2014-01-14 11:10:29 +01:00
if ( mux_undef ) {
2019-08-15 23:50:10 +02:00
if ( input . match ( " * " ) ) ACTION_DO ( ID : : Y , input . extract ( 1 , 1 ) ) ;
if ( input . match ( " * " ) ) ACTION_DO ( ID : : Y , input . extract ( 2 , 1 ) ) ;
if ( input . match ( " * " ) ) ACTION_DO ( ID : : Y , input . extract ( 2 , 1 ) ) ;
2014-01-14 11:10:29 +01:00
}
2013-01-05 11:13:26 +01:00
}
2019-08-09 18:58:14 +02:00
if ( cell - > type . in ( ID ( $ _TBUF_ ) , ID ( $ tribuf ) ) ) {
2020-04-02 18:51:32 +02:00
RTLIL : : SigSpec input = cell - > getPort ( cell - > type = = ID ( $ _TBUF_ ) ? ID : : E : ID : : EN ) ;
2019-08-15 23:50:10 +02:00
RTLIL : : SigSpec a = cell - > getPort ( ID : : A ) ;
2018-05-12 15:18:27 +02:00
assign_map . apply ( input ) ;
assign_map . apply ( a ) ;
if ( input = = State : : S1 )
2019-08-15 23:50:10 +02:00
ACTION_DO ( ID : : Y , cell - > getPort ( ID : : A ) ) ;
2018-05-12 15:18:27 +02:00
if ( input = = State : : S0 & & ! a . is_fully_undef ( ) ) {
cover ( " opt.opt_expr.action_ " S__LINE__ ) ;
2019-04-22 17:25:52 +02:00
log_debug ( " Replacing data input of %s cell `%s' in module `%s' with constant undef. \n " ,
2018-05-12 15:18:27 +02:00
cell - > type . c_str ( ) , cell - > name . c_str ( ) , module - > name . c_str ( ) ) ;
2019-08-15 23:50:10 +02:00
cell - > setPort ( ID : : A , SigSpec ( State : : Sx , GetSize ( a ) ) ) ;
2018-05-12 15:18:27 +02:00
did_something = true ;
goto next_cell ;
}
}
2019-08-09 18:58:14 +02:00
if ( cell - > type . in ( ID ( $ eq ) , ID ( $ ne ) , ID ( $ eqx ) , ID ( $ nex ) ) )
2013-01-05 11:13:26 +01:00
{
2019-08-15 23:50:10 +02:00
RTLIL : : SigSpec a = cell - > getPort ( ID : : A ) ;
RTLIL : : SigSpec b = cell - > getPort ( ID : : B ) ;
2013-11-07 11:54:59 +01:00
2020-04-02 18:51:32 +02:00
if ( cell - > parameters [ ID : : A_WIDTH ] . as_int ( ) ! = cell - > parameters [ ID : : B_WIDTH ] . as_int ( ) ) {
int width = max ( cell - > parameters [ ID : : A_WIDTH ] . as_int ( ) , cell - > parameters [ ID : : B_WIDTH ] . as_int ( ) ) ;
a . extend_u0 ( width , cell - > parameters [ ID : : A_SIGNED ] . as_bool ( ) & & cell - > parameters [ ID : : B_SIGNED ] . as_bool ( ) ) ;
b . extend_u0 ( width , cell - > parameters [ ID : : A_SIGNED ] . as_bool ( ) & & cell - > parameters [ ID : : B_SIGNED ] . as_bool ( ) ) ;
2013-01-05 11:13:26 +01:00
}
RTLIL : : SigSpec new_a , new_b ;
2014-10-10 16:59:44 +02:00
log_assert ( GetSize ( a ) = = GetSize ( b ) ) ;
for ( int i = 0 ; i < GetSize ( a ) ; i + + ) {
2014-07-23 16:09:27 +02:00
if ( a [ i ] . wire = = NULL & & b [ i ] . wire = = NULL & & a [ i ] ! = b [ i ] & & a [ i ] . data < = RTLIL : : State : : S1 & & b [ i ] . data < = RTLIL : : State : : S1 ) {
2016-03-31 08:43:28 +02:00
cover_list ( " opt.opt_expr.eqneq.isneq " , " $eq " , " $ne " , " $eqx " , " $nex " , cell - > type . str ( ) ) ;
2019-08-09 18:58:14 +02:00
RTLIL : : SigSpec new_y = RTLIL : : SigSpec ( cell - > type . in ( ID ( $ eq ) , ID ( $ eqx ) ) ? RTLIL : : State : : S0 : RTLIL : : State : : S1 ) ;
2020-04-02 18:51:32 +02:00
new_y . extend_u0 ( cell - > parameters [ ID : : Y_WIDTH ] . as_int ( ) , false ) ;
2019-08-15 23:50:10 +02:00
replace_cell ( assign_map , module , cell , " isneq " , ID : : Y , new_y ) ;
2013-12-27 15:10:07 +01:00
goto next_cell ;
}
2014-07-23 16:09:27 +02:00
if ( a [ i ] = = b [ i ] )
2013-12-27 14:21:24 +01:00
continue ;
2014-07-23 16:09:27 +02:00
new_a . append ( a [ i ] ) ;
new_b . append ( b [ i ] ) ;
2013-01-05 11:13:26 +01:00
}
2014-07-22 20:15:14 +02:00
if ( new_a . size ( ) = = 0 ) {
2016-03-31 08:43:28 +02:00
cover_list ( " opt.opt_expr.eqneq.empty " , " $eq " , " $ne " , " $eqx " , " $nex " , cell - > type . str ( ) ) ;
2019-08-09 18:58:14 +02:00
RTLIL : : SigSpec new_y = RTLIL : : SigSpec ( cell - > type . in ( ID ( $ eq ) , ID ( $ eqx ) ) ? RTLIL : : State : : S1 : RTLIL : : State : : S0 ) ;
2020-04-02 18:51:32 +02:00
new_y . extend_u0 ( cell - > parameters [ ID : : Y_WIDTH ] . as_int ( ) , false ) ;
2019-08-15 23:50:10 +02:00
replace_cell ( assign_map , module , cell , " empty " , ID : : Y , new_y ) ;
2013-11-07 16:53:28 +01:00
goto next_cell ;
}
2014-07-22 20:15:14 +02:00
if ( new_a . size ( ) < a . size ( ) | | new_b . size ( ) < b . size ( ) ) {
2016-03-31 08:43:28 +02:00
cover_list ( " opt.opt_expr.eqneq.resize " , " $eq " , " $ne " , " $eqx " , " $nex " , cell - > type . str ( ) ) ;
2019-08-15 23:50:10 +02:00
cell - > setPort ( ID : : A , new_a ) ;
cell - > setPort ( ID : : B , new_b ) ;
2020-04-02 18:51:32 +02:00
cell - > parameters [ ID : : A_WIDTH ] = new_a . size ( ) ;
cell - > parameters [ ID : : B_WIDTH ] = new_b . size ( ) ;
2013-01-05 11:13:26 +01:00
}
}
2020-04-02 18:51:32 +02:00
if ( cell - > type . in ( ID ( $ eq ) , ID ( $ ne ) ) & & cell - > parameters [ ID : : Y_WIDTH ] . as_int ( ) = = 1 & &
cell - > parameters [ ID : : A_WIDTH ] . as_int ( ) = = 1 & & cell - > parameters [ ID : : B_WIDTH ] . as_int ( ) = = 1 )
2013-03-19 13:33:33 +01:00
{
2019-08-15 23:50:10 +02:00
RTLIL : : SigSpec a = assign_map ( cell - > getPort ( ID : : A ) ) ;
RTLIL : : SigSpec b = assign_map ( cell - > getPort ( ID : : B ) ) ;
2013-03-19 13:33:33 +01:00
2015-01-31 23:25:32 +01:00
if ( a . is_fully_const ( ) & & ! b . is_fully_const ( ) ) {
2016-03-31 08:43:28 +02:00
cover_list ( " opt.opt_expr.eqneq.swapconst " , " $eq " , " $ne " , cell - > type . str ( ) ) ;
2019-08-15 23:50:10 +02:00
cell - > setPort ( ID : : A , b ) ;
cell - > setPort ( ID : : B , a ) ;
2015-01-31 23:25:32 +01:00
std : : swap ( a , b ) ;
2013-03-19 13:33:33 +01:00
}
if ( b . is_fully_const ( ) ) {
2019-09-13 13:39:39 +02:00
if ( b . is_fully_undef ( ) ) {
RTLIL : : SigSpec input = b ;
ACTION_DO ( ID : : Y , Const ( State : : Sx , GetSize ( cell - > getPort ( ID : : Y ) ) ) ) ;
} else
2019-08-09 18:58:14 +02:00
if ( b . as_bool ( ) = = ( cell - > type = = ID ( $ eq ) ) ) {
2013-03-19 13:33:33 +01:00
RTLIL : : SigSpec input = b ;
2019-08-15 23:50:10 +02:00
ACTION_DO ( ID : : Y , cell - > getPort ( ID : : A ) ) ;
2013-03-19 13:33:33 +01:00
} else {
2016-03-31 08:43:28 +02:00
cover_list ( " opt.opt_expr.eqneq.isnot " , " $eq " , " $ne " , cell - > type . str ( ) ) ;
2019-04-22 17:25:52 +02:00
log_debug ( " Replacing %s cell `%s' in module `%s' with inverter. \n " , log_id ( cell - > type ) , log_id ( cell ) , log_id ( module ) ) ;
2019-08-09 18:58:14 +02:00
cell - > type = ID ( $ not ) ;
2020-04-02 18:51:32 +02:00
cell - > parameters . erase ( ID : : B_WIDTH ) ;
cell - > parameters . erase ( ID : : B_SIGNED ) ;
2019-08-15 23:50:10 +02:00
cell - > unsetPort ( ID : : B ) ;
2014-08-24 15:14:45 +02:00
did_something = true ;
2013-03-19 13:33:33 +01:00
}
goto next_cell ;
}
}
2019-08-09 18:58:14 +02:00
if ( cell - > type . in ( ID ( $ eq ) , ID ( $ ne ) ) & &
2019-08-15 23:50:10 +02:00
( assign_map ( cell - > getPort ( ID : : A ) ) . is_fully_zero ( ) | | assign_map ( cell - > getPort ( ID : : B ) ) . is_fully_zero ( ) ) )
2015-04-29 07:28:15 +02:00
{
2016-03-31 08:43:28 +02:00
cover_list ( " opt.opt_expr.eqneq.cmpzero " , " $eq " , " $ne " , cell - > type . str ( ) ) ;
2019-04-22 17:25:52 +02:00
log_debug ( " Replacing %s cell `%s' in module `%s' with %s. \n " , log_id ( cell - > type ) , log_id ( cell ) ,
2019-12-15 20:40:38 +01:00
log_id ( module ) , cell - > type = = ID ( $ eq ) ? " $logic_not " : " $reduce_bool " ) ;
2019-08-09 18:58:14 +02:00
cell - > type = cell - > type = = ID ( $ eq ) ? ID ( $ logic_not ) : ID ( $ reduce_bool ) ;
2019-08-15 23:50:10 +02:00
if ( assign_map ( cell - > getPort ( ID : : A ) ) . is_fully_zero ( ) ) {
cell - > setPort ( ID : : A , cell - > getPort ( ID : : B ) ) ;
2020-04-02 18:51:32 +02:00
cell - > setParam ( ID : : A_SIGNED , cell - > getParam ( ID : : B_SIGNED ) ) ;
cell - > setParam ( ID : : A_WIDTH , cell - > getParam ( ID : : B_WIDTH ) ) ;
2015-04-29 07:28:15 +02:00
}
2019-08-15 23:50:10 +02:00
cell - > unsetPort ( ID : : B ) ;
2020-04-02 18:51:32 +02:00
cell - > unsetParam ( ID : : B_SIGNED ) ;
cell - > unsetParam ( ID : : B_WIDTH ) ;
2015-04-29 07:28:15 +02:00
did_something = true ;
goto next_cell ;
}
2022-11-30 17:35:48 +01:00
if ( cell - > type . in ( ID ( $ shl ) , ID ( $ shr ) , ID ( $ sshl ) , ID ( $ sshr ) , ID ( $ shift ) , ID ( $ shiftx ) ) & & ( keepdc ? assign_map ( cell - > getPort ( ID : : B ) ) . is_fully_def ( ) : assign_map ( cell - > getPort ( ID : : B ) ) . is_fully_const ( ) ) )
2014-08-24 17:08:07 +02:00
{
2020-04-02 18:51:32 +02:00
bool sign_ext = cell - > type = = ID ( $ sshr ) & & cell - > getParam ( ID : : A_SIGNED ) . as_bool ( ) ;
int shift_bits = assign_map ( cell - > getPort ( ID : : B ) ) . as_int ( cell - > type . in ( ID ( $ shift ) , ID ( $ shiftx ) ) & & cell - > getParam ( ID : : B_SIGNED ) . as_bool ( ) ) ;
2014-08-24 17:08:07 +02:00
2019-08-09 18:58:14 +02:00
if ( cell - > type . in ( ID ( $ shl ) , ID ( $ sshl ) ) )
2014-08-24 17:08:07 +02:00
shift_bits * = - 1 ;
2019-08-15 23:50:10 +02:00
RTLIL : : SigSpec sig_a = assign_map ( cell - > getPort ( ID : : A ) ) ;
2020-04-02 18:51:32 +02:00
RTLIL : : SigSpec sig_y ( cell - > type = = ID ( $ shiftx ) ? RTLIL : : State : : Sx : RTLIL : : State : : S0 , cell - > getParam ( ID : : Y_WIDTH ) . as_int ( ) ) ;
2014-08-24 17:08:07 +02:00
2025-02-14 01:29:24 +01:00
// Limit indexing to the size of a, which is behaviourally identical (result is all 0)
// and avoids integer overflow of i + shift_bits when e.g. ID::B == INT_MAX
shift_bits = min ( shift_bits , GetSize ( sig_a ) ) ;
2022-11-30 17:35:48 +01:00
if ( cell - > type ! = ID ( $ shiftx ) & & GetSize ( sig_a ) < GetSize ( sig_y ) )
2020-04-02 18:51:32 +02:00
sig_a . extend_u0 ( GetSize ( sig_y ) , cell - > getParam ( ID : : A_SIGNED ) . as_bool ( ) ) ;
2014-08-24 17:08:07 +02:00
2014-10-10 16:59:44 +02:00
for ( int i = 0 ; i < GetSize ( sig_y ) ; i + + ) {
2014-08-24 17:08:07 +02:00
int idx = i + shift_bits ;
2014-10-10 16:59:44 +02:00
if ( 0 < = idx & & idx < GetSize ( sig_a ) )
2014-08-24 17:08:07 +02:00
sig_y [ i ] = sig_a [ idx ] ;
2014-10-10 16:59:44 +02:00
else if ( GetSize ( sig_a ) < = idx & & sign_ext )
sig_y [ i ] = sig_a [ GetSize ( sig_a ) - 1 ] ;
2014-08-24 17:08:07 +02:00
}
2016-03-31 08:43:28 +02:00
cover_list ( " opt.opt_expr.constshift " , " $shl " , " $shr " , " $sshl " , " $sshr " , " $shift " , " $shiftx " , cell - > type . str ( ) ) ;
2014-08-24 17:08:07 +02:00
2019-04-22 17:25:52 +02:00
log_debug ( " Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s \n " ,
2019-08-15 23:50:10 +02:00
log_id ( cell - > type ) , log_id ( cell ) , log_signal ( assign_map ( cell - > getPort ( ID : : B ) ) ) , shift_bits , log_id ( module ) , log_signal ( sig_y ) ) ;
2014-08-24 17:08:07 +02:00
2019-08-15 23:50:10 +02:00
module - > connect ( cell - > getPort ( ID : : Y ) , sig_y ) ;
2014-08-24 17:08:07 +02:00
module - > remove ( cell ) ;
did_something = true ;
goto next_cell ;
}
2020-05-08 20:12:43 +02:00
if ( consume_x )
2014-07-21 14:09:11 +02:00
{
bool identity_wrt_a = false ;
bool identity_wrt_b = false ;
2015-09-25 17:27:06 +02:00
bool arith_inverse = false ;
2014-07-21 14:09:11 +02:00
2020-03-19 22:24:55 +01:00
if ( cell - > type . in ( ID ( $ add ) , ID ( $ sub ) , ID ( $ alu ) , ID ( $ or ) , ID ( $ xor ) ) )
2014-07-21 14:09:11 +02:00
{
2019-08-15 23:50:10 +02:00
RTLIL : : SigSpec a = assign_map ( cell - > getPort ( ID : : A ) ) ;
RTLIL : : SigSpec b = assign_map ( cell - > getPort ( ID : : B ) ) ;
2014-07-21 14:09:11 +02:00
2020-03-19 22:24:55 +01:00
bool sub = cell - > type = = ID ( $ sub ) ;
if ( cell - > type = = ID ( $ alu ) ) {
2020-04-02 18:51:32 +02:00
RTLIL : : SigBit sig_ci = assign_map ( cell - > getPort ( ID : : CI ) ) ;
RTLIL : : SigBit sig_bi = assign_map ( cell - > getPort ( ID : : BI ) ) ;
2020-03-19 22:24:55 +01:00
sub = ( sig_ci = = State : : S1 & & sig_bi = = State : : S1 ) ;
// If not a subtraction, yet there is a carry or B is inverted
// then no optimisation is possible as carry will not be constant
if ( ! sub & & ( sig_ci ! = State : : S0 | | sig_bi ! = State : : S0 ) )
2020-04-13 19:29:39 +02:00
goto skip_identity ;
2020-03-19 22:24:55 +01:00
}
if ( ! sub & & a . is_fully_const ( ) & & a . as_bool ( ) = = false )
2014-07-21 14:09:11 +02:00
identity_wrt_b = true ;
if ( b . is_fully_const ( ) & & b . as_bool ( ) = = false )
identity_wrt_a = true ;
}
2019-08-09 18:58:14 +02:00
if ( cell - > type . in ( ID ( $ shl ) , ID ( $ shr ) , ID ( $ sshl ) , ID ( $ sshr ) , ID ( $ shift ) , ID ( $ shiftx ) ) )
2014-07-21 14:09:11 +02:00
{
2019-08-15 23:50:10 +02:00
RTLIL : : SigSpec b = assign_map ( cell - > getPort ( ID : : B ) ) ;
2014-07-21 14:09:11 +02:00
if ( b . is_fully_const ( ) & & b . as_bool ( ) = = false )
2014-09-04 02:07:52 +02:00
identity_wrt_a = true ;
2014-07-21 14:09:11 +02:00
}
2019-08-09 18:58:14 +02:00
if ( cell - > type = = ID ( $ mul ) )
2014-07-21 14:09:11 +02:00
{
2019-08-15 23:50:10 +02:00
RTLIL : : SigSpec a = assign_map ( cell - > getPort ( ID : : A ) ) ;
RTLIL : : SigSpec b = assign_map ( cell - > getPort ( ID : : B ) ) ;
2014-07-21 14:09:11 +02:00
2020-04-02 18:51:32 +02:00
if ( a . is_fully_const ( ) & & is_one_or_minus_one ( a . as_const ( ) , cell - > getParam ( ID : : A_SIGNED ) . as_bool ( ) , arith_inverse ) )
2014-07-21 14:09:11 +02:00
identity_wrt_b = true ;
2015-09-25 17:27:06 +02:00
else
2020-04-02 18:51:32 +02:00
if ( b . is_fully_const ( ) & & is_one_or_minus_one ( b . as_const ( ) , cell - > getParam ( ID : : B_SIGNED ) . as_bool ( ) , arith_inverse ) )
2014-07-21 14:09:11 +02:00
identity_wrt_a = true ;
}
2019-08-09 18:58:14 +02:00
if ( cell - > type = = ID ( $ div ) )
2014-07-21 14:09:11 +02:00
{
2019-08-15 23:50:10 +02:00
RTLIL : : SigSpec b = assign_map ( cell - > getPort ( ID : : B ) ) ;
2014-07-21 14:09:11 +02:00
2014-07-22 20:15:14 +02:00
if ( b . is_fully_const ( ) & & b . size ( ) < = 32 & & b . as_int ( ) = = 1 )
2014-07-21 14:09:11 +02:00
identity_wrt_a = true ;
}
if ( identity_wrt_a | | identity_wrt_b )
{
2014-07-24 19:36:43 +02:00
if ( identity_wrt_a )
2020-03-19 22:24:55 +01:00
cover_list ( " opt.opt_expr.identwrt.a " , " $add " , " $sub " , " $alu " , " $or " , " $xor " , " $shl " , " $shr " , " $sshl " , " $sshr " , " $shift " , " $shiftx " , " $mul " , " $div " , cell - > type . str ( ) ) ;
2014-07-24 19:36:43 +02:00
if ( identity_wrt_b )
2020-03-19 22:24:55 +01:00
cover_list ( " opt.opt_expr.identwrt.b " , " $add " , " $sub " , " $alu " , " $or " , " $xor " , " $shl " , " $shr " , " $sshl " , " $sshr " , " $shift " , " $shiftx " , " $mul " , " $div " , cell - > type . str ( ) ) ;
2014-07-24 19:36:43 +02:00
2019-04-22 17:25:52 +02:00
log_debug ( " Replacing %s cell `%s' in module `%s' with identity for port %c. \n " ,
2014-07-21 14:09:11 +02:00
cell - > type . c_str ( ) , cell - > name . c_str ( ) , module - > name . c_str ( ) , identity_wrt_a ? ' A ' : ' B ' ) ;
2020-03-19 22:24:55 +01:00
if ( cell - > type = = ID ( $ alu ) ) {
2020-04-14 18:59:49 +02:00
bool a_signed = cell - > parameters [ ID : : A_SIGNED ] . as_bool ( ) ;
bool b_signed = cell - > parameters [ ID : : B_SIGNED ] . as_bool ( ) ;
bool is_signed = a_signed & & b_signed ;
RTLIL : : SigBit sig_ci = assign_map ( cell - > getPort ( ID : : CI ) ) ;
2020-04-02 18:51:32 +02:00
int y_width = GetSize ( cell - > getPort ( ID : : Y ) ) ;
2020-04-14 18:59:49 +02:00
if ( sig_ci = = State : : S1 ) {
/* sub, b is 0 */
RTLIL : : SigSpec a = cell - > getPort ( ID : : A ) ;
a . extend_u0 ( y_width , is_signed ) ;
2024-12-17 19:48:28 +01:00
module - > connect ( cell - > getPort ( ID : : X ) , module - > Not ( NEW_ID2_SUFFIX ( " ci_inv " ) , a , false , cell - > get_src_attribute ( ) ) ) ; // SILIMATE: Improve the naming
2020-04-14 18:59:49 +02:00
module - > connect ( cell - > getPort ( ID : : CO ) , RTLIL : : Const ( State : : S1 , y_width ) ) ;
} else {
/* add */
RTLIL : : SigSpec ab = cell - > getPort ( identity_wrt_a ? ID : : A : ID : : B ) ;
ab . extend_u0 ( y_width , is_signed ) ;
module - > connect ( cell - > getPort ( ID : : X ) , ab ) ;
module - > connect ( cell - > getPort ( ID : : CO ) , RTLIL : : Const ( State : : S0 , y_width ) ) ;
}
2020-04-02 18:51:32 +02:00
cell - > unsetPort ( ID : : BI ) ;
cell - > unsetPort ( ID : : CI ) ;
cell - > unsetPort ( ID : : X ) ;
cell - > unsetPort ( ID : : CO ) ;
2020-03-19 22:24:55 +01:00
}
2014-07-21 14:09:11 +02:00
if ( ! identity_wrt_a ) {
2019-08-15 23:50:10 +02:00
cell - > setPort ( ID : : A , cell - > getPort ( ID : : B ) ) ;
2020-04-02 18:51:32 +02:00
cell - > setParam ( ID : : A_WIDTH , cell - > getParam ( ID : : B_WIDTH ) ) ;
cell - > setParam ( ID : : A_SIGNED , cell - > getParam ( ID : : B_SIGNED ) ) ;
2014-07-21 14:09:11 +02:00
}
2019-08-09 18:58:14 +02:00
cell - > type = arith_inverse ? ID ( $ neg ) : ID ( $ pos ) ;
2019-08-15 23:50:10 +02:00
cell - > unsetPort ( ID : : B ) ;
2020-04-02 18:51:32 +02:00
cell - > parameters . erase ( ID : : B_WIDTH ) ;
cell - > parameters . erase ( ID : : B_SIGNED ) ;
2014-07-21 14:09:11 +02:00
cell - > check ( ) ;
did_something = true ;
goto next_cell ;
}
}
2020-04-13 19:29:39 +02:00
skip_identity :
2014-07-21 14:09:11 +02:00
2019-08-09 18:58:14 +02:00
if ( mux_bool & & cell - > type . in ( ID ( $ mux ) , ID ( $ _MUX_ ) ) & &
2019-08-15 23:50:10 +02:00
cell - > getPort ( ID : : A ) = = State : : S0 & & cell - > getPort ( ID : : B ) = = State : : S1 ) {
2016-03-31 08:43:28 +02:00
cover_list ( " opt.opt_expr.mux_bool " , " $mux " , " $_MUX_ " , cell - > type . str ( ) ) ;
2020-04-02 18:51:32 +02:00
replace_cell ( assign_map , module , cell , " mux_bool " , ID : : Y , cell - > getPort ( ID : : S ) ) ;
2014-02-02 22:11:08 +01:00
goto next_cell ;
}
2019-08-09 18:58:14 +02:00
if ( mux_bool & & cell - > type . in ( ID ( $ mux ) , ID ( $ _MUX_ ) ) & &
2019-08-15 23:50:10 +02:00
cell - > getPort ( ID : : A ) = = State : : S1 & & cell - > getPort ( ID : : B ) = = State : : S0 ) {
2016-03-31 08:43:28 +02:00
cover_list ( " opt.opt_expr.mux_invert " , " $mux " , " $_MUX_ " , cell - > type . str ( ) ) ;
2019-04-22 17:25:52 +02:00
log_debug ( " Replacing %s cell `%s' in module `%s' with inverter. \n " , log_id ( cell - > type ) , log_id ( cell ) , log_id ( module ) ) ;
2020-04-02 18:51:32 +02:00
cell - > setPort ( ID : : A , cell - > getPort ( ID : : S ) ) ;
2019-08-15 23:50:10 +02:00
cell - > unsetPort ( ID : : B ) ;
2020-04-02 18:51:32 +02:00
cell - > unsetPort ( ID : : S ) ;
2019-08-09 18:58:14 +02:00
if ( cell - > type = = ID ( $ mux ) ) {
2020-04-02 18:51:32 +02:00
Const width = cell - > parameters [ ID : : WIDTH ] ;
cell - > parameters [ ID : : A_WIDTH ] = width ;
cell - > parameters [ ID : : Y_WIDTH ] = width ;
cell - > parameters [ ID : : A_SIGNED ] = 0 ;
cell - > parameters . erase ( ID : : WIDTH ) ;
2019-08-09 18:58:14 +02:00
cell - > type = ID ( $ not ) ;
2014-02-02 22:41:24 +01:00
} else
2019-08-09 18:58:14 +02:00
cell - > type = ID ( $ _NOT_ ) ;
2014-02-02 22:41:24 +01:00
did_something = true ;
goto next_cell ;
}
2019-08-15 23:50:10 +02:00
if ( consume_x & & mux_bool & & cell - > type . in ( ID ( $ mux ) , ID ( $ _MUX_ ) ) & & cell - > getPort ( ID : : A ) = = State : : S0 ) {
2016-03-31 08:43:28 +02:00
cover_list ( " opt.opt_expr.mux_and " , " $mux " , " $_MUX_ " , cell - > type . str ( ) ) ;
2019-04-22 17:25:52 +02:00
log_debug ( " Replacing %s cell `%s' in module `%s' with and-gate. \n " , log_id ( cell - > type ) , log_id ( cell ) , log_id ( module ) ) ;
2020-04-02 18:51:32 +02:00
cell - > setPort ( ID : : A , cell - > getPort ( ID : : S ) ) ;
cell - > unsetPort ( ID : : S ) ;
2019-08-09 18:58:14 +02:00
if ( cell - > type = = ID ( $ mux ) ) {
2020-04-02 18:51:32 +02:00
Const width = cell - > parameters [ ID : : WIDTH ] ;
cell - > parameters [ ID : : A_WIDTH ] = width ;
cell - > parameters [ ID : : B_WIDTH ] = width ;
cell - > parameters [ ID : : Y_WIDTH ] = width ;
cell - > parameters [ ID : : A_SIGNED ] = 0 ;
cell - > parameters [ ID : : B_SIGNED ] = 0 ;
cell - > parameters . erase ( ID : : WIDTH ) ;
2019-08-09 18:58:14 +02:00
cell - > type = ID ( $ and ) ;
2014-02-02 22:41:24 +01:00
} else
2019-08-09 18:58:14 +02:00
cell - > type = ID ( $ _AND_ ) ;
2014-02-02 22:41:24 +01:00
did_something = true ;
goto next_cell ;
}
2019-08-15 23:50:10 +02:00
if ( consume_x & & mux_bool & & cell - > type . in ( ID ( $ mux ) , ID ( $ _MUX_ ) ) & & cell - > getPort ( ID : : B ) = = State : : S1 ) {
2016-03-31 08:43:28 +02:00
cover_list ( " opt.opt_expr.mux_or " , " $mux " , " $_MUX_ " , cell - > type . str ( ) ) ;
2019-04-22 17:25:52 +02:00
log_debug ( " Replacing %s cell `%s' in module `%s' with or-gate. \n " , log_id ( cell - > type ) , log_id ( cell ) , log_id ( module ) ) ;
2020-04-02 18:51:32 +02:00
cell - > setPort ( ID : : B , cell - > getPort ( ID : : S ) ) ;
cell - > unsetPort ( ID : : S ) ;
2019-08-09 18:58:14 +02:00
if ( cell - > type = = ID ( $ mux ) ) {
2020-04-02 18:51:32 +02:00
Const width = cell - > parameters [ ID : : WIDTH ] ;
cell - > parameters [ ID : : A_WIDTH ] = width ;
cell - > parameters [ ID : : B_WIDTH ] = width ;
cell - > parameters [ ID : : Y_WIDTH ] = width ;
cell - > parameters [ ID : : A_SIGNED ] = 0 ;
cell - > parameters [ ID : : B_SIGNED ] = 0 ;
cell - > parameters . erase ( ID : : WIDTH ) ;
2019-08-09 18:58:14 +02:00
cell - > type = ID ( $ or ) ;
2014-02-02 22:41:24 +01:00
} else
2019-08-09 18:58:14 +02:00
cell - > type = ID ( $ _OR_ ) ;
2014-02-02 22:11:08 +01:00
did_something = true ;
goto next_cell ;
}
2019-08-09 18:58:14 +02:00
if ( mux_undef & & cell - > type . in ( ID ( $ mux ) , ID ( $ pmux ) ) ) {
2014-01-14 11:10:29 +01:00
RTLIL : : SigSpec new_a , new_b , new_s ;
2019-08-22 17:05:01 +02:00
int width = GetSize ( cell - > getPort ( ID : : A ) ) ;
2019-08-15 23:50:10 +02:00
if ( ( cell - > getPort ( ID : : A ) . is_fully_undef ( ) & & cell - > getPort ( ID : : B ) . is_fully_undef ( ) ) | |
2020-04-02 18:51:32 +02:00
cell - > getPort ( ID : : S ) . is_fully_undef ( ) ) {
2016-03-31 08:43:28 +02:00
cover_list ( " opt.opt_expr.mux_undef " , " $mux " , " $pmux " , cell - > type . str ( ) ) ;
2019-08-15 23:50:10 +02:00
replace_cell ( assign_map , module , cell , " mux_undef " , ID : : Y , cell - > getPort ( ID : : A ) ) ;
2014-01-14 11:10:29 +01:00
goto next_cell ;
}
2020-04-02 18:51:32 +02:00
for ( int i = 0 ; i < cell - > getPort ( ID : : S ) . size ( ) ; i + + ) {
2019-08-15 23:50:10 +02:00
RTLIL : : SigSpec old_b = cell - > getPort ( ID : : B ) . extract ( i * width , width ) ;
2020-04-02 18:51:32 +02:00
RTLIL : : SigSpec old_s = cell - > getPort ( ID : : S ) . extract ( i , 1 ) ;
2014-01-14 11:10:29 +01:00
if ( old_b . is_fully_undef ( ) | | old_s . is_fully_undef ( ) )
continue ;
new_b . append ( old_b ) ;
new_s . append ( old_s ) ;
}
2019-08-15 23:50:10 +02:00
new_a = cell - > getPort ( ID : : A ) ;
2014-07-22 20:15:14 +02:00
if ( new_a . is_fully_undef ( ) & & new_s . size ( ) > 0 ) {
new_a = new_b . extract ( ( new_s . size ( ) - 1 ) * width , width ) ;
new_b = new_b . extract ( 0 , ( new_s . size ( ) - 1 ) * width ) ;
new_s = new_s . extract ( 0 , new_s . size ( ) - 1 ) ;
2014-01-14 11:10:29 +01:00
}
2014-07-22 20:15:14 +02:00
if ( new_s . size ( ) = = 0 ) {
2016-03-31 08:43:28 +02:00
cover_list ( " opt.opt_expr.mux_empty " , " $mux " , " $pmux " , cell - > type . str ( ) ) ;
2019-08-15 23:50:10 +02:00
replace_cell ( assign_map , module , cell , " mux_empty " , ID : : Y , new_a ) ;
2014-01-14 11:10:29 +01:00
goto next_cell ;
}
if ( new_a = = RTLIL : : SigSpec ( RTLIL : : State : : S0 ) & & new_b = = RTLIL : : SigSpec ( RTLIL : : State : : S1 ) ) {
2016-03-31 08:43:28 +02:00
cover_list ( " opt.opt_expr.mux_sel01 " , " $mux " , " $pmux " , cell - > type . str ( ) ) ;
2019-08-15 23:50:10 +02:00
replace_cell ( assign_map , module , cell , " mux_sel01 " , ID : : Y , new_s ) ;
2014-01-14 11:10:29 +01:00
goto next_cell ;
}
2020-04-02 18:51:32 +02:00
if ( cell - > getPort ( ID : : S ) . size ( ) ! = new_s . size ( ) ) {
2016-03-31 08:43:28 +02:00
cover_list ( " opt.opt_expr.mux_reduce " , " $mux " , " $pmux " , cell - > type . str ( ) ) ;
2019-04-22 17:25:52 +02:00
log_debug ( " Optimized away %d select inputs of %s cell `%s' in module `%s'. \n " ,
2020-04-02 18:51:32 +02:00
GetSize ( cell - > getPort ( ID : : S ) ) - GetSize ( new_s ) , log_id ( cell - > type ) , log_id ( cell ) , log_id ( module ) ) ;
2019-08-15 23:50:10 +02:00
cell - > setPort ( ID : : A , new_a ) ;
cell - > setPort ( ID : : B , new_b ) ;
2020-04-02 18:51:32 +02:00
cell - > setPort ( ID : : S , new_s ) ;
2014-07-22 20:15:14 +02:00
if ( new_s . size ( ) > 1 ) {
2019-08-09 18:58:14 +02:00
cell - > type = ID ( $ pmux ) ;
2020-04-02 18:51:32 +02:00
cell - > parameters [ ID : : S_WIDTH ] = new_s . size ( ) ;
2014-01-14 11:10:29 +01:00
} else {
2019-08-09 18:58:14 +02:00
cell - > type = ID ( $ mux ) ;
2020-04-02 18:51:32 +02:00
cell - > parameters . erase ( ID : : S_WIDTH ) ;
2014-01-14 11:10:29 +01:00
}
did_something = true ;
}
}
2013-01-05 11:13:26 +01:00
# define FOLD_1ARG_CELL(_t) \
2020-04-02 18:51:32 +02:00
if ( cell - > type = = ID ( $ # # _t ) ) { \
2019-08-15 23:50:10 +02:00
RTLIL : : SigSpec a = cell - > getPort ( ID : : A ) ; \
2013-01-05 11:13:26 +01:00
assign_map . apply ( a ) ; \
if ( a . is_fully_const ( ) ) { \
RTLIL : : Const dummy_arg ( RTLIL : : State : : S0 , 1 ) ; \
2014-07-22 20:58:44 +02:00
RTLIL : : SigSpec y ( RTLIL : : const_ # # _t ( a . as_const ( ) , dummy_arg , \
2020-04-02 18:51:32 +02:00
cell - > parameters [ ID : : A_SIGNED ] . as_bool ( ) , false , \
cell - > parameters [ ID : : Y_WIDTH ] . as_int ( ) ) ) ; \
2016-03-31 08:43:28 +02:00
cover ( " opt.opt_expr.const.$ " # _t ) ; \
2019-08-15 23:50:10 +02:00
replace_cell ( assign_map , module , cell , stringf ( " %s " , log_signal ( a ) ) , ID : : Y , y ) ; \
2013-01-05 11:13:26 +01:00
goto next_cell ; \
} \
}
# define FOLD_2ARG_CELL(_t) \
2020-04-02 18:51:32 +02:00
if ( cell - > type = = ID ( $ # # _t ) ) { \
2019-08-15 23:50:10 +02:00
RTLIL : : SigSpec a = cell - > getPort ( ID : : A ) ; \
RTLIL : : SigSpec b = cell - > getPort ( ID : : B ) ; \
2013-01-05 11:13:26 +01:00
assign_map . apply ( a ) , assign_map . apply ( b ) ; \
if ( a . is_fully_const ( ) & & b . is_fully_const ( ) ) { \
2014-07-22 20:58:44 +02:00
RTLIL : : SigSpec y ( RTLIL : : const_ # # _t ( a . as_const ( ) , b . as_const ( ) , \
2020-04-02 18:51:32 +02:00
cell - > parameters [ ID : : A_SIGNED ] . as_bool ( ) , \
cell - > parameters [ ID : : B_SIGNED ] . as_bool ( ) , \
cell - > parameters [ ID : : Y_WIDTH ] . as_int ( ) ) ) ; \
2016-03-31 08:43:28 +02:00
cover ( " opt.opt_expr.const.$ " # _t ) ; \
2019-08-15 23:50:10 +02:00
replace_cell ( assign_map , module , cell , stringf ( " %s, %s " , log_signal ( a ) , log_signal ( b ) ) , ID : : Y , y ) ; \
2013-01-05 11:13:26 +01:00
goto next_cell ; \
} \
}
2022-11-02 17:58:49 +01:00
# define FOLD_2ARG_SIMPLE_CELL(_t, B_ID) \
if ( cell - > type = = ID ( $ # # _t ) ) { \
RTLIL : : SigSpec a = cell - > getPort ( ID : : A ) ; \
RTLIL : : SigSpec b = cell - > getPort ( B_ID ) ; \
assign_map . apply ( a ) , assign_map . apply ( b ) ; \
if ( a . is_fully_const ( ) & & b . is_fully_const ( ) ) { \
RTLIL : : SigSpec y ( RTLIL : : const_ # # _t ( a . as_const ( ) , b . as_const ( ) ) ) ; \
cover ( " opt.opt_expr.const.$ " # _t ) ; \
replace_cell ( assign_map , module , cell , stringf ( " %s, %s " , log_signal ( a ) , log_signal ( b ) ) , ID : : Y , y ) ; \
goto next_cell ; \
} \
}
# define FOLD_MUX_CELL(_t) \
if ( cell - > type = = ID ( $ # # _t ) ) { \
RTLIL : : SigSpec a = cell - > getPort ( ID : : A ) ; \
RTLIL : : SigSpec b = cell - > getPort ( ID : : B ) ; \
RTLIL : : SigSpec s = cell - > getPort ( ID : : S ) ; \
assign_map . apply ( a ) , assign_map . apply ( b ) , assign_map . apply ( s ) ; \
if ( a . is_fully_const ( ) & & b . is_fully_const ( ) & & s . is_fully_const ( ) ) { \
RTLIL : : SigSpec y ( RTLIL : : const_ # # _t ( a . as_const ( ) , b . as_const ( ) , s . as_const ( ) ) ) ; \
cover ( " opt.opt_expr.const.$ " # _t ) ; \
replace_cell ( assign_map , module , cell , stringf ( " %s, %s, %s " , log_signal ( a ) , log_signal ( b ) , log_signal ( s ) ) , ID : : Y , y ) ; \
goto next_cell ; \
} \
}
2013-01-05 11:13:26 +01:00
FOLD_1ARG_CELL ( not )
FOLD_2ARG_CELL ( and )
FOLD_2ARG_CELL ( or )
FOLD_2ARG_CELL ( xor )
FOLD_2ARG_CELL ( xnor )
FOLD_1ARG_CELL ( reduce_and )
FOLD_1ARG_CELL ( reduce_or )
FOLD_1ARG_CELL ( reduce_xor )
FOLD_1ARG_CELL ( reduce_xnor )
FOLD_1ARG_CELL ( reduce_bool )
FOLD_1ARG_CELL ( logic_not )
FOLD_2ARG_CELL ( logic_and )
FOLD_2ARG_CELL ( logic_or )
FOLD_2ARG_CELL ( shl )
FOLD_2ARG_CELL ( shr )
FOLD_2ARG_CELL ( sshl )
FOLD_2ARG_CELL ( sshr )
2014-07-29 14:42:33 +02:00
FOLD_2ARG_CELL ( shift )
FOLD_2ARG_CELL ( shiftx )
2013-01-05 11:13:26 +01:00
FOLD_2ARG_CELL ( lt )
FOLD_2ARG_CELL ( le )
FOLD_2ARG_CELL ( eq )
FOLD_2ARG_CELL ( ne )
FOLD_2ARG_CELL ( gt )
FOLD_2ARG_CELL ( ge )
2022-11-02 17:58:49 +01:00
FOLD_2ARG_CELL ( eqx )
FOLD_2ARG_CELL ( nex )
2013-01-05 11:13:26 +01:00
FOLD_2ARG_CELL ( add )
FOLD_2ARG_CELL ( sub )
FOLD_2ARG_CELL ( mul )
FOLD_2ARG_CELL ( div )
FOLD_2ARG_CELL ( mod )
2020-04-21 12:51:58 +02:00
FOLD_2ARG_CELL ( divfloor )
2020-04-08 19:30:47 +02:00
FOLD_2ARG_CELL ( modfloor )
2013-01-05 11:13:26 +01:00
FOLD_2ARG_CELL ( pow )
FOLD_1ARG_CELL ( pos )
FOLD_1ARG_CELL ( neg )
2022-11-02 17:58:49 +01:00
FOLD_MUX_CELL ( mux ) ;
FOLD_MUX_CELL ( pmux ) ;
FOLD_2ARG_SIMPLE_CELL ( bmux , ID : : S ) ;
FOLD_2ARG_SIMPLE_CELL ( demux , ID : : S ) ;
2022-11-02 17:54:45 +01:00
FOLD_2ARG_SIMPLE_CELL ( bweqx , ID : : B ) ;
FOLD_MUX_CELL ( bwmux ) ;
2022-11-02 17:58:49 +01:00
2013-03-19 13:32:39 +01:00
// be very conservative with optimizing $mux cells as we do not want to break mux trees
2019-08-09 18:58:14 +02:00
if ( cell - > type = = ID ( $ mux ) ) {
2020-04-02 18:51:32 +02:00
RTLIL : : SigSpec input = assign_map ( cell - > getPort ( ID : : S ) ) ;
2019-08-15 23:50:10 +02:00
RTLIL : : SigSpec inA = assign_map ( cell - > getPort ( ID : : A ) ) ;
RTLIL : : SigSpec inB = assign_map ( cell - > getPort ( ID : : B ) ) ;
2022-10-21 15:41:20 +02:00
if ( input . is_fully_const ( ) & & ( ! keepdc | | input . is_fully_def ( ) ) )
2019-08-15 23:50:10 +02:00
ACTION_DO ( ID : : Y , input . as_bool ( ) ? cell - > getPort ( ID : : B ) : cell - > getPort ( ID : : A ) ) ;
2013-03-19 13:32:39 +01:00
else if ( inA = = inB )
2019-08-15 23:50:10 +02:00
ACTION_DO ( ID : : Y , cell - > getPort ( ID : : A ) ) ;
2013-01-05 11:13:26 +01:00
}
2019-08-09 18:58:14 +02:00
if ( ! keepdc & & cell - > type = = ID ( $ mul ) )
2014-07-21 17:19:50 +02:00
{
2020-04-02 18:51:32 +02:00
bool a_signed = cell - > parameters [ ID : : A_SIGNED ] . as_bool ( ) ;
bool b_signed = cell - > parameters [ ID : : B_SIGNED ] . as_bool ( ) ;
2014-07-21 17:19:50 +02:00
bool swapped_ab = false ;
2019-08-15 23:50:10 +02:00
RTLIL : : SigSpec sig_a = assign_map ( cell - > getPort ( ID : : A ) ) ;
RTLIL : : SigSpec sig_b = assign_map ( cell - > getPort ( ID : : B ) ) ;
RTLIL : : SigSpec sig_y = assign_map ( cell - > getPort ( ID : : Y ) ) ;
2014-07-21 17:19:50 +02:00
2021-06-09 18:41:57 +02:00
if ( sig_b . is_fully_const ( ) )
2014-07-21 17:19:50 +02:00
std : : swap ( sig_a , sig_b ) , std : : swap ( a_signed , b_signed ) , swapped_ab = true ;
2021-06-09 18:41:57 +02:00
if ( sig_a . is_fully_def ( ) )
2014-07-21 17:19:50 +02:00
{
2021-06-09 18:41:57 +02:00
if ( sig_a . is_fully_zero ( ) )
2014-07-21 17:19:50 +02:00
{
2016-03-31 08:43:28 +02:00
cover ( " opt.opt_expr.mul_shift.zero " ) ;
2014-07-24 19:36:43 +02:00
2019-04-22 17:25:52 +02:00
log_debug ( " Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver. \n " ,
2014-07-21 17:19:50 +02:00
cell - > name . c_str ( ) , module - > name . c_str ( ) ) ;
2014-07-26 14:32:50 +02:00
module - > connect ( RTLIL : : SigSig ( sig_y , RTLIL : : SigSpec ( 0 , sig_y . size ( ) ) ) ) ;
2014-07-21 17:19:50 +02:00
module - > remove ( cell ) ;
did_something = true ;
goto next_cell ;
}
2021-06-09 18:41:57 +02:00
int exp ;
if ( sig_a . is_onehot ( & exp ) & & ! ( a_signed & & exp = = GetSize ( sig_a ) - 1 ) )
{
if ( swapped_ab )
cover ( " opt.opt_expr.mul_shift.swapped " ) ;
else
cover ( " opt.opt_expr.mul_shift.unswapped " ) ;
2014-07-21 17:19:50 +02:00
2021-06-09 18:41:57 +02:00
log_debug ( " Replacing multiply-by-%s cell `%s' in module `%s' with shift-by-%d. \n " ,
log_signal ( sig_a ) , cell - > name . c_str ( ) , module - > name . c_str ( ) , exp ) ;
2014-07-21 17:19:50 +02:00
2021-06-09 18:41:57 +02:00
if ( ! swapped_ab ) {
cell - > setPort ( ID : : A , cell - > getPort ( ID : : B ) ) ;
cell - > parameters . at ( ID : : A_WIDTH ) = cell - > parameters . at ( ID : : B_WIDTH ) ;
cell - > parameters . at ( ID : : A_SIGNED ) = cell - > parameters . at ( ID : : B_SIGNED ) ;
}
2014-07-21 21:38:55 +02:00
2021-06-09 18:41:57 +02:00
Const new_b = exp ;
2014-07-21 21:38:55 +02:00
2021-06-09 18:41:57 +02:00
cell - > type = ID ( $ shl ) ;
cell - > parameters [ ID : : B_WIDTH ] = GetSize ( new_b ) ;
cell - > parameters [ ID : : B_SIGNED ] = false ;
cell - > setPort ( ID : : B , new_b ) ;
cell - > check ( ) ;
2014-07-21 17:19:50 +02:00
2021-06-09 18:41:57 +02:00
did_something = true ;
goto next_cell ;
}
2014-07-21 17:19:50 +02:00
}
2020-04-12 22:37:44 +02:00
sig_a = assign_map ( cell - > getPort ( ID : : A ) ) ;
sig_b = assign_map ( cell - > getPort ( ID : : B ) ) ;
int a_zeros , b_zeros ;
for ( a_zeros = 0 ; a_zeros < GetSize ( sig_a ) ; a_zeros + + )
if ( sig_a [ a_zeros ] ! = RTLIL : : State : : S0 )
break ;
for ( b_zeros = 0 ; b_zeros < GetSize ( sig_b ) ; b_zeros + + )
if ( sig_b [ b_zeros ] ! = RTLIL : : State : : S0 )
break ;
if ( a_zeros | | b_zeros ) {
int y_zeros = a_zeros + b_zeros ;
cover ( " opt.opt_expr.mul_low_zeros " ) ;
log_debug ( " Removing low %d A and %d B bits from cell `%s' in module `%s'. \n " ,
a_zeros , b_zeros , cell - > name . c_str ( ) , module - > name . c_str ( ) ) ;
2020-07-05 00:55:38 +02:00
if ( y_zeros > = GetSize ( sig_y ) ) {
module - > connect ( sig_y , RTLIL : : SigSpec ( 0 , GetSize ( sig_y ) ) ) ;
module - > remove ( cell ) ;
did_something = true ;
goto next_cell ;
}
2020-04-12 22:37:44 +02:00
if ( a_zeros ) {
cell - > setPort ( ID : : A , sig_a . extract_end ( a_zeros ) ) ;
cell - > parameters [ ID : : A_WIDTH ] = GetSize ( sig_a ) - a_zeros ;
}
if ( b_zeros ) {
cell - > setPort ( ID : : B , sig_b . extract_end ( b_zeros ) ) ;
cell - > parameters [ ID : : B_WIDTH ] = GetSize ( sig_b ) - b_zeros ;
}
cell - > setPort ( ID : : Y , sig_y . extract_end ( y_zeros ) ) ;
cell - > parameters [ ID : : Y_WIDTH ] = GetSize ( sig_y ) - y_zeros ;
module - > connect ( RTLIL : : SigSig ( sig_y . extract ( 0 , y_zeros ) , RTLIL : : SigSpec ( 0 , y_zeros ) ) ) ;
cell - > check ( ) ;
did_something = true ;
goto next_cell ;
}
2014-07-21 17:19:50 +02:00
}
2021-06-09 18:41:57 +02:00
if ( cell - > type . in ( ID ( $ div ) , ID ( $ mod ) , ID ( $ divfloor ) , ID ( $ modfloor ) ) )
2016-05-29 12:17:36 +02:00
{
2020-04-08 19:30:47 +02:00
bool a_signed = cell - > parameters [ ID : : A_SIGNED ] . as_bool ( ) ;
2020-04-02 18:51:32 +02:00
bool b_signed = cell - > parameters [ ID : : B_SIGNED ] . as_bool ( ) ;
2020-04-08 19:30:47 +02:00
SigSpec sig_a = assign_map ( cell - > getPort ( ID : : A ) ) ;
2019-08-15 23:50:10 +02:00
SigSpec sig_b = assign_map ( cell - > getPort ( ID : : B ) ) ;
SigSpec sig_y = assign_map ( cell - > getPort ( ID : : Y ) ) ;
2016-05-29 12:17:36 +02:00
2021-06-09 18:41:57 +02:00
if ( sig_b . is_fully_def ( ) )
2016-05-29 12:17:36 +02:00
{
2021-06-09 18:41:57 +02:00
if ( sig_b . is_fully_zero ( ) )
2016-05-29 12:17:36 +02:00
{
cover ( " opt.opt_expr.divmod_zero " ) ;
2019-04-22 17:25:52 +02:00
log_debug ( " Replacing divide-by-zero cell `%s' in module `%s' with undef-driver. \n " ,
2016-05-29 12:17:36 +02:00
cell - > name . c_str ( ) , module - > name . c_str ( ) ) ;
module - > connect ( RTLIL : : SigSig ( sig_y , RTLIL : : SigSpec ( State : : Sx , sig_y . size ( ) ) ) ) ;
module - > remove ( cell ) ;
did_something = true ;
goto next_cell ;
}
2021-06-09 18:41:57 +02:00
int exp ;
if ( ! keepdc & & sig_b . is_onehot ( & exp ) & & ! ( b_signed & & exp = = GetSize ( sig_b ) - 1 ) )
{
if ( cell - > type . in ( ID ( $ div ) , ID ( $ divfloor ) ) )
2016-05-29 12:17:36 +02:00
{
2021-06-09 18:41:57 +02:00
cover ( " opt.opt_expr.div_shift " ) ;
2016-05-29 12:17:36 +02:00
2021-06-09 18:41:57 +02:00
bool is_truncating = cell - > type = = ID ( $ div ) ;
log_debug ( " Replacing %s-divide-by-%s cell `%s' in module `%s' with shift-by-%d. \n " ,
is_truncating ? " truncating " : " flooring " ,
log_signal ( sig_b ) , cell - > name . c_str ( ) , module - > name . c_str ( ) , exp ) ;
2016-05-29 12:17:36 +02:00
2021-06-09 18:41:57 +02:00
Const new_b = exp ;
2016-05-29 12:17:36 +02:00
2021-06-09 18:41:57 +02:00
cell - > type = ID ( $ sshr ) ;
cell - > parameters [ ID : : B_WIDTH ] = GetSize ( new_b ) ;
cell - > parameters [ ID : : B_SIGNED ] = false ;
cell - > setPort ( ID : : B , new_b ) ;
2020-04-21 12:51:58 +02:00
2021-06-09 18:41:57 +02:00
// Truncating division is the same as flooring division, except when
// the result is negative and there is a remainder - then trunc = floor + 1
if ( is_truncating & & a_signed & & GetSize ( sig_a ) ! = 0 & & exp ! = 0 ) {
2024-11-12 02:06:11 +01:00
Wire * flooring = module - > addWire ( NEW_ID2_SUFFIX ( " flooring " ) , sig_y . size ( ) ) ; // SILIMATE: Improve the naming
2021-06-09 18:41:57 +02:00
cell - > setPort ( ID : : Y , flooring ) ;
2020-04-21 12:51:58 +02:00
2021-06-09 18:41:57 +02:00
SigSpec a_sign = sig_a [ sig_a . size ( ) - 1 ] ;
2024-11-12 02:06:11 +01:00
SigSpec rem_nonzero = module - > ReduceOr ( NEW_ID2_SUFFIX ( " rem_nonzero " ) , sig_a . extract ( 0 , exp ) ) ; // SILIMATE: Improve the naming
SigSpec should_add = module - > And ( NEW_ID2_SUFFIX ( " should_add " ) , a_sign , rem_nonzero ) ; // SILIMATE: Improve the naming
module - > addAdd ( NEW_ID2_SUFFIX ( " add " ) , flooring , should_add , sig_y ) ; // SILIMATE: Improve the naming
2016-05-29 12:17:36 +02:00
}
2021-06-09 18:41:57 +02:00
cell - > check ( ) ;
}
else if ( cell - > type . in ( ID ( $ mod ) , ID ( $ modfloor ) ) )
{
cover ( " opt.opt_expr.mod_mask " ) ;
bool is_truncating = cell - > type = = ID ( $ mod ) ;
log_debug ( " Replacing %s-modulo-by-%s cell `%s' in module `%s' with bitmask. \n " ,
is_truncating ? " truncating " : " flooring " ,
log_signal ( sig_b ) , cell - > name . c_str ( ) , module - > name . c_str ( ) ) ;
// truncating modulo has the same masked bits as flooring modulo, but
// the sign bits are those of A (except when R=0)
if ( is_truncating & & a_signed & & GetSize ( sig_a ) ! = 0 & & exp ! = 0 )
2016-05-29 12:17:36 +02:00
{
2021-06-09 18:41:57 +02:00
SigSpec truncating = sig_a . extract ( 0 , exp ) ;
2016-05-29 12:17:36 +02:00
2021-06-09 18:41:57 +02:00
SigSpec a_sign = sig_a [ sig_a . size ( ) - 1 ] ;
2024-11-12 02:06:11 +01:00
SigSpec rem_nonzero = module - > ReduceOr ( NEW_ID2_SUFFIX ( " rem_nonzero " ) , sig_a . extract ( 0 , exp ) , false , cell - > get_src_attribute ( ) ) ; // SILIMATE: Improve the naming
SigSpec extend_bit = module - > And ( NEW_ID2_SUFFIX ( " extend_bit " ) , a_sign , rem_nonzero , false , cell - > get_src_attribute ( ) ) ; // SILIMATE: Improve the naming
2016-05-29 12:17:36 +02:00
2021-06-09 18:41:57 +02:00
truncating . append ( extend_bit ) ;
2024-11-12 02:06:11 +01:00
module - > addPos ( NEW_ID2_SUFFIX ( " pos " ) , truncating , sig_y , true , cell - > get_src_attribute ( ) ) ; // SILIMATE: Improve the naming
2024-11-12 10:22:12 +01:00
module - > remove ( cell ) ;
2021-06-09 18:41:57 +02:00
}
else
{
std : : vector < RTLIL : : SigBit > new_b = RTLIL : : SigSpec ( State : : S1 , exp ) ;
2016-05-29 12:17:36 +02:00
2021-06-09 18:41:57 +02:00
if ( b_signed | | exp = = 0 )
2016-05-29 12:17:36 +02:00
new_b . push_back ( State : : S0 ) ;
2019-08-09 18:58:14 +02:00
cell - > type = ID ( $ and ) ;
2020-04-02 18:51:32 +02:00
cell - > parameters [ ID : : B_WIDTH ] = GetSize ( new_b ) ;
2019-08-15 23:50:10 +02:00
cell - > setPort ( ID : : B , new_b ) ;
2016-05-29 12:17:36 +02:00
cell - > check ( ) ;
}
}
2021-06-09 18:41:57 +02:00
did_something = true ;
goto next_cell ;
}
2016-05-29 12:17:36 +02:00
}
}
2017-01-31 16:20:56 +01:00
2020-04-13 19:29:39 +02:00
// Find places in $alu cell where the carry is constant, and split it at these points.
if ( do_fine & & ! keepdc & & cell - > type = = ID ( $ alu ) )
{
bool a_signed = cell - > parameters [ ID : : A_SIGNED ] . as_bool ( ) ;
bool b_signed = cell - > parameters [ ID : : B_SIGNED ] . as_bool ( ) ;
bool is_signed = a_signed & & b_signed ;
RTLIL : : SigSpec sig_a = assign_map ( cell - > getPort ( ID : : A ) ) ;
RTLIL : : SigSpec sig_b = assign_map ( cell - > getPort ( ID : : B ) ) ;
RTLIL : : SigSpec sig_y = assign_map ( cell - > getPort ( ID : : Y ) ) ;
RTLIL : : SigSpec sig_bi = assign_map ( cell - > getPort ( ID : : BI ) ) ;
if ( GetSize ( sig_a ) = = 0 )
sig_a = State : : S0 ;
if ( GetSize ( sig_b ) = = 0 )
sig_b = State : : S0 ;
sig_a . extend_u0 ( GetSize ( sig_y ) , is_signed ) ;
sig_b . extend_u0 ( GetSize ( sig_y ) , is_signed ) ;
if ( sig_bi ! = State : : S0 & & sig_bi ! = State : : S1 )
goto skip_alu_split ;
std : : vector < std : : pair < int , State > > split_points ;
for ( int i = 0 ; i < GetSize ( sig_y ) ; i + + ) {
SigBit bit_a = sig_a [ i ] ;
SigBit bit_b = sig_b [ i ] ;
if ( bit_a ! = State : : S0 & & bit_a ! = State : : S1 )
continue ;
if ( bit_b ! = State : : S0 & & bit_b ! = State : : S1 )
continue ;
if ( sig_bi = = State : : S1 ) {
if ( bit_b = = State : : S0 )
bit_b = State : : S1 ;
else
bit_b = State : : S0 ;
}
if ( bit_a ! = bit_b )
continue ;
split_points . push_back ( std : : make_pair ( i + 1 , bit_a . data ) ) ;
}
if ( split_points . empty ( ) | | split_points [ 0 ] . first = = GetSize ( sig_y ) )
goto skip_alu_split ;
for ( auto & p : split_points )
log_debug ( " Splitting $alu cell `%s' in module `%s' at const-carry point %d. \n " ,
cell - > name . c_str ( ) , module - > name . c_str ( ) , p . first ) ;
if ( split_points . back ( ) . first ! = GetSize ( sig_y ) )
split_points . push_back ( std : : make_pair ( GetSize ( sig_y ) , State : : Sx ) ) ;
RTLIL : : SigSpec sig_ci = assign_map ( cell - > getPort ( ID : : CI ) ) ;
int prev = 0 ;
RTLIL : : SigSpec sig_x = assign_map ( cell - > getPort ( ID : : X ) ) ;
RTLIL : : SigSpec sig_co = assign_map ( cell - > getPort ( ID : : CO ) ) ;
for ( auto & p : split_points ) {
int cur = p . first ;
int sz = cur - prev ;
bool last = cur = = GetSize ( sig_y ) ;
2024-11-12 02:06:11 +01:00
// SILIMATE: New cell takes on old cell's name
RTLIL : : IdString cell_name = cell - > name ;
module - > rename ( cell - > name , NEW_ID ) ;
2024-11-12 12:44:22 +01:00
RTLIL : : Cell * c = module - > addCell ( NEW_ID3 , cell - > type ) ; // SILIMATE: Improve the naming
2024-11-12 02:06:11 +01:00
c - > set_src_attribute ( cell - > get_src_attribute ( ) ) ;
2020-04-13 19:29:39 +02:00
c - > setPort ( ID : : A , sig_a . extract ( prev , sz ) ) ;
c - > setPort ( ID : : B , sig_b . extract ( prev , sz ) ) ;
c - > setPort ( ID : : BI , sig_bi ) ;
c - > setPort ( ID : : CI , sig_ci ) ;
c - > setPort ( ID : : Y , sig_y . extract ( prev , sz ) ) ;
c - > setPort ( ID : : X , sig_x . extract ( prev , sz ) ) ;
RTLIL : : SigSpec new_co = sig_co . extract ( prev , sz ) ;
if ( p . second ! = State : : Sx ) {
module - > connect ( new_co [ sz - 1 ] , p . second ) ;
2024-11-12 12:44:22 +01:00
RTLIL : : Wire * dummy = module - > addWire ( NEW_ID3_SUFFIX ( " dummy " ) ) ; // SILIMATE: Improve the naming
2020-04-13 19:29:39 +02:00
new_co [ sz - 1 ] = dummy ;
}
c - > setPort ( ID : : CO , new_co ) ;
c - > parameters [ ID : : A_WIDTH ] = sz ;
c - > parameters [ ID : : B_WIDTH ] = sz ;
c - > parameters [ ID : : Y_WIDTH ] = sz ;
c - > parameters [ ID : : A_SIGNED ] = last ? a_signed : false ;
c - > parameters [ ID : : B_SIGNED ] = last ? b_signed : false ;
prev = p . first ;
sig_ci = p . second ;
}
cover ( " opt.opt_expr.alu_split " ) ;
module - > remove ( cell ) ;
did_something = true ;
goto next_cell ;
}
skip_alu_split :
2017-08-25 16:02:15 +02:00
// remove redundant pairs of bits in ==, ===, !=, and !==
// replace cell with const driver if inputs can't be equal
2019-08-09 18:58:14 +02:00
if ( do_fine & & cell - > type . in ( ID ( $ eq ) , ID ( $ ne ) , ID ( $ eqx ) , ID ( $ nex ) ) )
2017-08-25 16:02:15 +02:00
{
pool < pair < SigBit , SigBit > > redundant_cache ;
mfp < SigBit > contradiction_cache ;
contradiction_cache . promote ( State : : S0 ) ;
contradiction_cache . promote ( State : : S1 ) ;
2020-04-02 18:51:32 +02:00
int a_width = cell - > getParam ( ID : : A_WIDTH ) . as_int ( ) ;
int b_width = cell - > getParam ( ID : : B_WIDTH ) . as_int ( ) ;
2017-08-25 16:02:15 +02:00
2020-04-02 18:51:32 +02:00
bool is_signed = cell - > getParam ( ID : : A_SIGNED ) . as_bool ( ) ;
2017-08-25 16:02:15 +02:00
int width = is_signed ? std : : min ( a_width , b_width ) : std : : max ( a_width , b_width ) ;
2019-08-15 23:50:10 +02:00
SigSpec sig_a = cell - > getPort ( ID : : A ) ;
SigSpec sig_b = cell - > getPort ( ID : : B ) ;
2017-08-25 16:02:15 +02:00
int redundant_bits = 0 ;
for ( int i = width - 1 ; i > = 0 ; i - - )
{
SigBit bit_a = i < a_width ? assign_map ( sig_a [ i ] ) : State : : S0 ;
SigBit bit_b = i < b_width ? assign_map ( sig_b [ i ] ) : State : : S0 ;
2017-08-25 16:18:17 +02:00
if ( bit_a ! = State : : Sx & & bit_a ! = State : : Sz & &
bit_b ! = State : : Sx & & bit_b ! = State : : Sz )
contradiction_cache . merge ( bit_a , bit_b ) ;
2017-08-25 16:02:15 +02:00
if ( bit_b < bit_a )
std : : swap ( bit_a , bit_b ) ;
pair < SigBit , SigBit > key ( bit_a , bit_b ) ;
if ( redundant_cache . count ( key ) ) {
if ( i < a_width ) sig_a . remove ( i ) ;
if ( i < b_width ) sig_b . remove ( i ) ;
redundant_bits + + ;
continue ;
}
redundant_cache . insert ( key ) ;
}
if ( contradiction_cache . find ( State : : S0 ) = = contradiction_cache . find ( State : : S1 ) )
{
2019-08-15 23:50:10 +02:00
SigSpec y_sig = cell - > getPort ( ID : : Y ) ;
2019-08-09 18:58:14 +02:00
Const y_value ( cell - > type . in ( ID ( $ eq ) , ID ( $ eqx ) ) ? 0 : 1 , GetSize ( y_sig ) ) ;
2017-08-25 16:02:15 +02:00
2019-04-22 17:25:52 +02:00
log_debug ( " Replacing cell `%s' in module `%s' with constant driver %s. \n " ,
2017-08-25 16:02:15 +02:00
log_id ( cell ) , log_id ( module ) , log_signal ( y_value ) ) ;
module - > connect ( y_sig , y_value ) ;
module - > remove ( cell ) ;
did_something = true ;
goto next_cell ;
}
if ( redundant_bits )
{
2019-04-22 17:25:52 +02:00
log_debug ( " Removed %d redundant input bits from %s cell `%s' in module `%s'. \n " ,
2017-08-25 16:02:15 +02:00
redundant_bits , log_id ( cell - > type ) , log_id ( cell ) , log_id ( module ) ) ;
2019-08-15 23:50:10 +02:00
cell - > setPort ( ID : : A , sig_a ) ;
cell - > setPort ( ID : : B , sig_b ) ;
2020-04-02 18:51:32 +02:00
cell - > setParam ( ID : : A_WIDTH , GetSize ( sig_a ) ) ;
cell - > setParam ( ID : : B_WIDTH , GetSize ( sig_b ) ) ;
2017-08-25 16:02:15 +02:00
did_something = true ;
goto next_cell ;
}
}
2019-01-02 03:45:49 +01:00
// simplify comparisons
2019-08-09 18:58:14 +02:00
if ( do_fine & & cell - > type . in ( ID ( $ lt ) , ID ( $ ge ) , ID ( $ gt ) , ID ( $ le ) ) )
2017-01-31 16:20:56 +01:00
{
2019-01-02 03:45:49 +01:00
IdString cmp_type = cell - > type ;
2019-08-15 23:50:10 +02:00
SigSpec var_sig = cell - > getPort ( ID : : A ) ;
SigSpec const_sig = cell - > getPort ( ID : : B ) ;
2020-04-02 18:51:32 +02:00
int var_width = cell - > parameters [ ID : : A_WIDTH ] . as_int ( ) ;
int const_width = cell - > parameters [ ID : : B_WIDTH ] . as_int ( ) ;
bool is_signed = cell - > getParam ( ID : : A_SIGNED ) . as_bool ( ) ;
2017-01-31 16:20:56 +01:00
2019-01-02 03:45:49 +01:00
if ( ! const_sig . is_fully_const ( ) )
2017-01-31 16:20:56 +01:00
{
2019-01-02 03:45:49 +01:00
std : : swap ( var_sig , const_sig ) ;
std : : swap ( var_width , const_width ) ;
2019-08-09 18:58:14 +02:00
if ( cmp_type = = ID ( $ gt ) )
cmp_type = ID ( $ lt ) ;
else if ( cmp_type = = ID ( $ lt ) )
cmp_type = ID ( $ gt ) ;
else if ( cmp_type = = ID ( $ ge ) )
cmp_type = ID ( $ le ) ;
else if ( cmp_type = = ID ( $ le ) )
cmp_type = ID ( $ ge ) ;
2019-01-02 03:45:49 +01:00
}
if ( const_sig . is_fully_def ( ) & & const_sig . is_fully_const ( ) )
2017-01-31 16:20:56 +01:00
{
2019-01-02 04:01:25 +01:00
std : : string condition , replacement ;
2019-08-15 23:50:10 +02:00
SigSpec replace_sig ( State : : S0 , GetSize ( cell - > getPort ( ID : : Y ) ) ) ;
2019-01-02 04:01:25 +01:00
bool replace = false ;
2019-01-02 05:31:20 +01:00
bool remove = false ;
2019-01-02 03:45:49 +01:00
if ( ! is_signed )
2019-01-02 04:01:25 +01:00
{ /* unsigned */
2019-08-09 18:58:14 +02:00
if ( const_sig . is_fully_zero ( ) & & cmp_type = = ID ( $ lt ) ) {
2019-01-02 03:45:49 +01:00
condition = " unsigned X<0 " ;
replacement = " constant 0 " ;
2019-01-02 05:31:20 +01:00
replace_sig [ 0 ] = State : : S0 ;
2019-01-02 04:01:25 +01:00
replace = true ;
2019-01-02 03:45:49 +01:00
}
2019-08-09 18:58:14 +02:00
if ( const_sig . is_fully_zero ( ) & & cmp_type = = ID ( $ ge ) ) {
2019-01-02 03:45:49 +01:00
condition = " unsigned X>=0 " ;
replacement = " constant 1 " ;
2019-01-02 05:31:20 +01:00
replace_sig [ 0 ] = State : : S1 ;
2019-01-02 04:01:25 +01:00
replace = true ;
2019-01-02 03:45:49 +01:00
}
2019-08-09 18:58:14 +02:00
if ( const_width = = var_width & & const_sig . is_fully_ones ( ) & & cmp_type = = ID ( $ gt ) ) {
2019-01-02 03:45:49 +01:00
condition = " unsigned X>~0 " ;
replacement = " constant 0 " ;
2019-01-02 05:31:20 +01:00
replace_sig [ 0 ] = State : : S0 ;
2019-01-02 04:01:25 +01:00
replace = true ;
2019-01-02 03:45:49 +01:00
}
2019-08-09 18:58:14 +02:00
if ( const_width = = var_width & & const_sig . is_fully_ones ( ) & & cmp_type = = ID ( $ le ) ) {
2019-01-02 03:45:49 +01:00
condition = " unsigned X<=~0 " ;
replacement = " constant 1 " ;
2019-01-02 05:31:20 +01:00
replace_sig [ 0 ] = State : : S1 ;
2019-01-02 04:01:25 +01:00
replace = true ;
2017-01-31 16:20:56 +01:00
}
2021-06-09 18:41:57 +02:00
int const_bit_hot ;
if ( const_sig . is_onehot ( & const_bit_hot ) & & const_bit_hot < var_width )
2019-01-02 05:31:20 +01:00
{
2019-01-02 06:04:28 +01:00
RTLIL : : SigSpec var_high_sig ( RTLIL : : State : : S0 , var_width - const_bit_hot ) ;
for ( int i = const_bit_hot ; i < var_width ; i + + ) {
var_high_sig [ i - const_bit_hot ] = var_sig [ i ] ;
2019-01-02 05:31:20 +01:00
}
2019-08-09 18:58:14 +02:00
if ( cmp_type = = ID ( $ lt ) )
2019-01-02 05:31:20 +01:00
{
2024-11-12 02:06:11 +01:00
// SILIMATE: New cell takes on old cell's name
RTLIL : : IdString cell_name = cell - > name ;
module - > rename ( cell - > name , NEW_ID ) ;
2019-01-02 05:31:20 +01:00
condition = stringf ( " unsigned X<%s " , log_signal ( const_sig ) ) ;
2019-01-02 06:04:28 +01:00
replacement = stringf ( " !X[%d:%d] " , var_width - 1 , const_bit_hot ) ;
2024-11-12 12:44:22 +01:00
module - > addLogicNot ( NEW_ID3 , var_high_sig , cell - > getPort ( ID : : Y ) , false , cell - > get_src_attribute ( ) ) ; // SILIMATE: Improve the naming
2019-01-02 05:31:20 +01:00
remove = true ;
}
2019-08-09 18:58:14 +02:00
if ( cmp_type = = ID ( $ ge ) )
2019-01-02 05:31:20 +01:00
{
2024-11-12 02:06:11 +01:00
// SILIMATE: New cell takes on old cell's name
RTLIL : : IdString cell_name = cell - > name ;
module - > rename ( cell - > name , NEW_ID ) ;
2019-01-02 05:31:20 +01:00
condition = stringf ( " unsigned X>=%s " , log_signal ( const_sig ) ) ;
2019-01-02 06:04:28 +01:00
replacement = stringf ( " |X[%d:%d] " , var_width - 1 , const_bit_hot ) ;
2024-11-12 12:44:22 +01:00
module - > addReduceOr ( NEW_ID3 , var_high_sig , cell - > getPort ( ID : : Y ) , false , cell - > get_src_attribute ( ) ) ; // SILIMATE: Improve the naming
2019-01-02 05:31:20 +01:00
remove = true ;
}
2017-01-31 16:20:56 +01:00
}
2019-01-02 06:04:28 +01:00
int const_bit_set = get_highest_hot_index ( const_sig ) ;
2020-03-20 00:33:54 +01:00
if ( const_bit_set > = var_width )
2019-01-02 06:04:28 +01:00
{
string cmp_name ;
2019-08-09 18:58:14 +02:00
if ( cmp_type = = ID ( $ lt ) | | cmp_type = = ID ( $ le ) )
2019-01-02 06:04:28 +01:00
{
2019-08-09 18:58:14 +02:00
if ( cmp_type = = ID ( $ lt ) ) cmp_name = " < " ;
if ( cmp_type = = ID ( $ le ) ) cmp_name = " <= " ;
2019-01-02 06:04:28 +01:00
condition = stringf ( " unsigned X[%d:0]%s%s " , var_width - 1 , cmp_name . c_str ( ) , log_signal ( const_sig ) ) ;
replacement = " constant 1 " ;
replace_sig [ 0 ] = State : : S1 ;
replace = true ;
}
2019-08-09 18:58:14 +02:00
if ( cmp_type = = ID ( $ gt ) | | cmp_type = = ID ( $ ge ) )
2019-01-02 06:04:28 +01:00
{
2019-08-09 18:58:14 +02:00
if ( cmp_type = = ID ( $ gt ) ) cmp_name = " > " ;
if ( cmp_type = = ID ( $ ge ) ) cmp_name = " >= " ;
2019-01-02 06:04:28 +01:00
condition = stringf ( " unsigned X[%d:0]%s%s " , var_width - 1 , cmp_name . c_str ( ) , log_signal ( const_sig ) ) ;
replacement = " constant 0 " ;
replace_sig [ 0 ] = State : : S0 ;
replace = true ;
}
2017-01-31 16:20:56 +01:00
}
}
2019-01-02 04:01:25 +01:00
else
{ /* signed */
2019-08-09 18:58:14 +02:00
if ( const_sig . is_fully_zero ( ) & & cmp_type = = ID ( $ lt ) )
2019-01-02 04:01:25 +01:00
{
condition = " signed X<0 " ;
replacement = stringf ( " X[%d] " , var_width - 1 ) ;
2019-01-02 05:31:20 +01:00
replace_sig [ 0 ] = var_sig [ var_width - 1 ] ;
2019-01-02 04:01:25 +01:00
replace = true ;
2017-02-10 16:28:19 +01:00
}
2019-08-09 18:58:14 +02:00
if ( const_sig . is_fully_zero ( ) & & cmp_type = = ID ( $ ge ) )
2019-01-02 04:01:25 +01:00
{
2024-11-12 02:06:11 +01:00
// SILIMATE: New cell takes on old cell's name
RTLIL : : IdString cell_name = cell - > name ;
module - > rename ( cell - > name , NEW_ID ) ;
2019-01-02 04:01:25 +01:00
condition = " signed X>=0 " ;
replacement = stringf ( " X[%d] " , var_width - 1 ) ;
2024-11-12 12:44:22 +01:00
module - > addLogicNot ( NEW_ID3 , var_sig [ var_width - 1 ] , cell - > getPort ( ID : : Y ) , false , cell - > get_src_attribute ( ) ) ; // SILIMATE: Improve the naming
2019-01-02 05:31:20 +01:00
remove = true ;
2017-02-10 16:28:19 +01:00
}
2019-01-02 03:45:49 +01:00
}
2019-01-02 05:31:20 +01:00
if ( replace | | remove )
2019-01-02 03:45:49 +01:00
{
2019-04-22 17:25:52 +02:00
log_debug ( " Replacing %s cell `%s' (implementing %s) with %s. \n " ,
2019-01-02 04:01:25 +01:00
log_id ( cell - > type ) , log_id ( cell ) , condition . c_str ( ) , replacement . c_str ( ) ) ;
2019-01-02 05:31:20 +01:00
if ( replace )
2019-08-15 23:50:10 +02:00
module - > connect ( cell - > getPort ( ID : : Y ) , replace_sig ) ;
2017-02-10 16:28:19 +01:00
module - > remove ( cell ) ;
did_something = true ;
goto next_cell ;
}
2017-01-31 16:20:56 +01:00
}
}
2016-05-29 12:17:36 +02:00
2013-01-05 11:13:26 +01:00
next_cell : ;
# undef ACTION_DO
# undef ACTION_DO_Y
# undef FOLD_1ARG_CELL
# undef FOLD_2ARG_CELL
}
}
2021-07-27 15:24:48 +02:00
void replace_const_connections ( RTLIL : : Module * module ) {
SigMap assign_map ( module ) ;
for ( auto cell : module - > selected_cells ( ) )
{
std : : vector < std : : pair < RTLIL : : IdString , SigSpec > > changes ;
for ( auto & conn : cell - > connections ( ) ) {
SigSpec mapped = assign_map ( conn . second ) ;
if ( conn . second ! = mapped & & mapped . is_fully_const ( ) )
changes . push_back ( { conn . first , mapped } ) ;
}
if ( ! changes . empty ( ) )
did_something = true ;
for ( auto & it : changes )
cell - > setPort ( it . first , it . second ) ;
}
}
2016-03-31 08:43:28 +02:00
struct OptExprPass : public Pass {
OptExprPass ( ) : Pass ( " opt_expr " , " perform const folding and simple expression rewriting " ) { }
2020-06-19 01:34:52 +02:00
void help ( ) override
2013-03-01 08:58:55 +01:00
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log ( " \n " ) ;
2016-03-31 08:43:28 +02:00
log ( " opt_expr [options] [selection] \n " ) ;
2013-03-01 08:58:55 +01:00
log ( " \n " ) ;
log ( " This pass performs const folding on internal cell types with constant inputs. \n " ) ;
2018-12-07 20:14:07 +01:00
log ( " It also performs some simple expression rewriting. \n " ) ;
2013-03-01 08:58:55 +01:00
log ( " \n " ) ;
2014-01-14 11:10:29 +01:00
log ( " -mux_undef \n " ) ;
log ( " remove 'undef' inputs from $mux, $pmux and $_MUX_ cells \n " ) ;
log ( " \n " ) ;
2014-02-02 22:11:08 +01:00
log ( " -mux_bool \n " ) ;
log ( " replace $mux cells with inverters or buffers when possible \n " ) ;
log ( " \n " ) ;
2014-02-06 15:49:03 +01:00
log ( " -undriven \n " ) ;
log ( " replace undriven nets with undef (x) constants \n " ) ;
log ( " \n " ) ;
2020-07-24 13:08:54 +02:00
log ( " -noclkinv \n " ) ;
log ( " do not optimize clock inverters by changing FF types \n " ) ;
2015-07-01 10:49:21 +02:00
log ( " \n " ) ;
2014-10-31 03:36:51 +01:00
log ( " -fine \n " ) ;
log ( " perform fine-grain optimizations \n " ) ;
log ( " \n " ) ;
log ( " -full \n " ) ;
log ( " alias for -mux_undef -mux_bool -undriven -fine \n " ) ;
log ( " \n " ) ;
2014-07-21 21:38:55 +02:00
log ( " -keepdc \n " ) ;
log ( " some optimizations change the behavior of the circuit with respect to \n " ) ;
log ( " don't-care bits. for example in 'a+0' a single x-bit in 'a' will cause \n " ) ;
log ( " all result bits to be set to x. this behavior changes when 'a+0' is \n " ) ;
log ( " replaced by 'a'. the -keepdc option disables all such optimizations. \n " ) ;
log ( " \n " ) ;
2013-03-01 08:58:55 +01:00
}
2020-06-19 01:34:52 +02:00
void execute ( std : : vector < std : : string > args , RTLIL : : Design * design ) override
2013-01-05 11:13:26 +01:00
{
2014-01-14 11:10:29 +01:00
bool mux_undef = false ;
2014-02-02 22:11:08 +01:00
bool mux_bool = false ;
2014-02-06 15:49:03 +01:00
bool undriven = false ;
2020-07-24 13:08:54 +02:00
bool noclkinv = false ;
2014-07-21 16:34:16 +02:00
bool do_fine = false ;
2014-07-21 21:38:55 +02:00
bool keepdc = false ;
2014-01-14 11:10:29 +01:00
2016-04-21 23:28:37 +02:00
log_header ( design , " Executing OPT_EXPR pass (perform const folding). \n " ) ;
2013-01-05 11:13:26 +01:00
log_push ( ) ;
2014-01-14 11:10:29 +01:00
size_t argidx ;
for ( argidx = 1 ; argidx < args . size ( ) ; argidx + + ) {
if ( args [ argidx ] = = " -mux_undef " ) {
mux_undef = true ;
continue ;
}
2014-02-02 22:11:08 +01:00
if ( args [ argidx ] = = " -mux_bool " ) {
mux_bool = true ;
continue ;
}
2014-02-06 15:49:03 +01:00
if ( args [ argidx ] = = " -undriven " ) {
undriven = true ;
continue ;
}
2020-07-24 13:08:54 +02:00
if ( args [ argidx ] = = " -noclkinv " ) {
noclkinv = true ;
2015-07-01 10:49:21 +02:00
continue ;
}
2014-07-21 16:34:16 +02:00
if ( args [ argidx ] = = " -fine " ) {
do_fine = true ;
continue ;
}
2014-10-31 03:36:51 +01:00
if ( args [ argidx ] = = " -full " ) {
mux_undef = true ;
mux_bool = true ;
undriven = true ;
do_fine = true ;
continue ;
}
2014-07-21 21:38:55 +02:00
if ( args [ argidx ] = = " -keepdc " ) {
keepdc = true ;
continue ;
}
2014-01-14 11:10:29 +01:00
break ;
}
extra_args ( args , argidx , design ) ;
2013-01-05 11:13:26 +01:00
2020-03-18 20:21:40 +01:00
CellTypes ct ( design ) ;
2015-02-03 23:45:01 +01:00
for ( auto module : design - > selected_modules ( ) )
2014-02-06 15:49:03 +01:00
{
2019-04-22 17:25:52 +02:00
log ( " Optimizing module %s. \n " , log_id ( module ) ) ;
if ( undriven ) {
did_something = false ;
2020-03-18 20:21:40 +01:00
replace_undriven ( module , ct ) ;
2019-04-22 17:25:52 +02:00
if ( did_something )
design - > scratchpad_set_bool ( " opt.did_something " , true ) ;
}
2014-02-06 15:49:03 +01:00
2013-01-05 11:13:26 +01:00
do {
2013-05-17 14:55:18 +02:00
do {
did_something = false ;
2020-07-24 13:08:54 +02:00
replace_const_cells ( design , module , false /* consume_x */ , mux_undef , mux_bool , do_fine , keepdc , noclkinv ) ;
2014-08-30 19:37:12 +02:00
if ( did_something )
design - > scratchpad_set_bool ( " opt.did_something " , true ) ;
2013-05-17 14:55:18 +02:00
} while ( did_something ) ;
2020-05-08 20:12:43 +02:00
if ( ! keepdc )
2020-07-24 13:08:54 +02:00
replace_const_cells ( design , module , true /* consume_x */ , mux_undef , mux_bool , do_fine , keepdc , noclkinv ) ;
2019-04-22 17:25:52 +02:00
if ( did_something )
design - > scratchpad_set_bool ( " opt.did_something " , true ) ;
2013-01-05 11:13:26 +01:00
} while ( did_something ) ;
2019-04-22 17:25:52 +02:00
2021-07-27 15:24:48 +02:00
did_something = false ;
replace_const_connections ( module ) ;
if ( did_something )
design - > scratchpad_set_bool ( " opt.did_something " , true ) ;
2019-04-22 17:25:52 +02:00
log_suppressed ( ) ;
2014-02-06 15:49:03 +01:00
}
2013-01-05 11:13:26 +01:00
log_pop ( ) ;
}
2016-03-31 08:43:28 +02:00
} OptExprPass ;
2013-01-05 11:13:26 +01:00
2014-09-27 16:17:53 +02:00
PRIVATE_NAMESPACE_END