2021-10-06 22:16:55 +02:00
/*
* yosys - - Yosys Open SYnthesis Suite
*
* Copyright ( C ) 2020 Marcelina Kościelnicka < mwk @ 0x04 . net >
*
* Permission to use , copy , modify , and / or distribute this software for any
* purpose with or without fee is hereby granted , provided that the above
* copyright notice and this permission notice appear in all copies .
*
* THE SOFTWARE IS PROVIDED " AS IS " AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS . IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL , DIRECT , INDIRECT , OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE , DATA OR PROFITS , WHETHER IN AN
* ACTION OF CONTRACT , NEGLIGENCE OR OTHER TORTIOUS ACTION , ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
*
*/
# include "kernel/ff.h"
USING_YOSYS_NAMESPACE
2025-07-18 12:34:10 +02:00
// sorry
template < typename InputType , typename OutputType , typename = std : : enable_if_t < std : : is_base_of_v < FfTypeData , OutputType > > >
void manufacture_info ( InputType flop , OutputType & info , FfInitVals * initvals ) {
Cell * cell = nullptr ;
IdString type ;
constexpr bool have_cell = std : : is_same_v < InputType , Cell * > ;
if constexpr ( std : : is_same_v < InputType , IdString > ) {
type = flop ;
} else {
static_assert ( std : : is_same_v < InputType , Cell * > ) ;
cell = flop ;
type = flop - > type ;
}
if constexpr ( have_cell ) {
info . sig_q = cell - > getPort ( ID : : Q ) ;
info . width = GetSize ( info . sig_q ) ;
info . attributes = cell - > attributes ;
if ( initvals )
info . val_init = ( * initvals ) ( info . sig_q ) ;
}
2021-10-06 22:16:55 +02:00
2025-07-18 12:34:10 +02:00
std : : string type_str = type . str ( ) ;
2021-10-06 22:16:55 +02:00
2025-07-18 12:34:10 +02:00
if ( type . in ( ID ( $ anyinit ) , ID ( $ ff ) , ID ( $ dff ) , ID ( $ dffe ) , ID ( $ dffsr ) , ID ( $ dffsre ) , ID ( $ adff ) , ID ( $ adffe ) , ID ( $ aldff ) , ID ( $ aldffe ) , ID ( $ sdff ) , ID ( $ sdffe ) , ID ( $ sdffce ) , ID ( $ dlatch ) , ID ( $ adlatch ) , ID ( $ dlatchsr ) , ID ( $ sr ) ) ) {
if ( type . in ( ID ( $ anyinit ) , ID ( $ ff ) ) ) {
info . has_gclk = true ;
if constexpr ( have_cell )
info . sig_d = cell - > getPort ( ID : : D ) ;
if ( type = = ID ( $ anyinit ) ) {
info . is_anyinit = true ;
if constexpr ( have_cell )
log_assert ( info . val_init . is_fully_undef ( ) ) ;
2022-07-21 14:22:15 +02:00
}
2025-07-18 12:34:10 +02:00
} else if ( type = = ID ( $ sr ) ) {
2021-10-06 22:16:55 +02:00
// No data input at all.
2025-07-18 12:34:10 +02:00
} else if ( type . in ( ID ( $ dlatch ) , ID ( $ adlatch ) , ID ( $ dlatchsr ) ) ) {
info . has_aload = true ;
if constexpr ( have_cell ) {
info . sig_aload = cell - > getPort ( ID : : EN ) ;
info . pol_aload = cell - > getParam ( ID : : EN_POLARITY ) . as_bool ( ) ;
info . sig_ad = cell - > getPort ( ID : : D ) ;
}
2021-10-06 22:16:55 +02:00
} else {
2025-07-18 12:34:10 +02:00
info . has_clk = true ;
if constexpr ( have_cell ) {
info . sig_clk = cell - > getPort ( ID : : CLK ) ;
info . pol_clk = cell - > getParam ( ID : : CLK_POLARITY ) . as_bool ( ) ;
info . sig_d = cell - > getPort ( ID : : D ) ;
}
2021-10-06 22:16:55 +02:00
}
2025-07-18 12:34:10 +02:00
if ( type . in ( ID ( $ dffe ) , ID ( $ dffsre ) , ID ( $ adffe ) , ID ( $ aldffe ) , ID ( $ sdffe ) , ID ( $ sdffce ) ) ) {
info . has_ce = true ;
if constexpr ( have_cell ) {
info . sig_ce = cell - > getPort ( ID : : EN ) ;
info . pol_ce = cell - > getParam ( ID : : EN_POLARITY ) . as_bool ( ) ;
}
2021-10-06 22:16:55 +02:00
}
2025-07-18 12:34:10 +02:00
if ( type . in ( ID ( $ dffsr ) , ID ( $ dffsre ) , ID ( $ dlatchsr ) , ID ( $ sr ) ) ) {
info . has_sr = true ;
if constexpr ( have_cell ) {
info . sig_clr = cell - > getPort ( ID : : CLR ) ;
info . sig_set = cell - > getPort ( ID : : SET ) ;
info . pol_clr = cell - > getParam ( ID : : CLR_POLARITY ) . as_bool ( ) ;
info . pol_set = cell - > getParam ( ID : : SET_POLARITY ) . as_bool ( ) ;
}
2021-10-06 22:16:55 +02:00
}
2025-07-18 12:34:10 +02:00
if ( type . in ( ID ( $ aldff ) , ID ( $ aldffe ) ) ) {
info . has_aload = true ;
if constexpr ( have_cell ) {
info . sig_aload = cell - > getPort ( ID : : ALOAD ) ;
info . pol_aload = cell - > getParam ( ID : : ALOAD_POLARITY ) . as_bool ( ) ;
info . sig_ad = cell - > getPort ( ID : : AD ) ;
}
2021-10-06 22:16:55 +02:00
}
2025-07-18 12:34:10 +02:00
if ( type . in ( ID ( $ adff ) , ID ( $ adffe ) , ID ( $ adlatch ) ) ) {
info . has_arst = true ;
if constexpr ( have_cell ) {
info . sig_arst = cell - > getPort ( ID : : ARST ) ;
info . pol_arst = cell - > getParam ( ID : : ARST_POLARITY ) . as_bool ( ) ;
info . val_arst = cell - > getParam ( ID : : ARST_VALUE ) ;
}
2021-10-06 22:16:55 +02:00
}
2025-07-18 12:34:10 +02:00
if ( type . in ( ID ( $ sdff ) , ID ( $ sdffe ) , ID ( $ sdffce ) ) ) {
info . has_srst = true ;
if constexpr ( have_cell ) {
info . sig_srst = cell - > getPort ( ID : : SRST ) ;
info . pol_srst = cell - > getParam ( ID : : SRST_POLARITY ) . as_bool ( ) ;
info . val_srst = cell - > getParam ( ID : : SRST_VALUE ) ;
}
info . ce_over_srst = type = = ID ( $ sdffce ) ;
2021-10-06 22:16:55 +02:00
}
2025-07-18 12:34:10 +02:00
} else if ( type = = ID ( $ _FF_ ) ) {
info . is_fine = true ;
info . has_gclk = true ;
if constexpr ( have_cell )
info . sig_d = cell - > getPort ( ID : : D ) ;
2021-10-06 22:16:55 +02:00
} else if ( type_str . substr ( 0 , 5 ) = = " $_SR_ " ) {
2025-07-18 12:34:10 +02:00
info . is_fine = true ;
info . has_sr = true ;
info . pol_set = type_str [ 5 ] = = ' P ' ;
info . pol_clr = type_str [ 6 ] = = ' P ' ;
if constexpr ( have_cell ) {
info . sig_set = cell - > getPort ( ID : : S ) ;
info . sig_clr = cell - > getPort ( ID : : R ) ;
}
2021-10-06 22:16:55 +02:00
} else if ( type_str . substr ( 0 , 6 ) = = " $_DFF_ " & & type_str . size ( ) = = 8 ) {
2025-07-18 12:34:10 +02:00
info . is_fine = true ;
info . has_clk = true ;
info . pol_clk = type_str [ 6 ] = = ' P ' ;
if constexpr ( have_cell ) {
info . sig_d = cell - > getPort ( ID : : D ) ;
info . sig_clk = cell - > getPort ( ID : : C ) ;
}
2021-10-06 22:16:55 +02:00
} else if ( type_str . substr ( 0 , 7 ) = = " $_DFFE_ " & & type_str . size ( ) = = 10 ) {
2025-07-18 12:34:10 +02:00
info . is_fine = true ;
info . has_clk = true ;
info . pol_clk = type_str [ 7 ] = = ' P ' ;
info . has_ce = true ;
info . pol_ce = type_str [ 8 ] = = ' P ' ;
if constexpr ( have_cell ) {
info . sig_d = cell - > getPort ( ID : : D ) ;
info . sig_clk = cell - > getPort ( ID : : C ) ;
info . sig_ce = cell - > getPort ( ID : : E ) ;
}
2021-10-06 22:16:55 +02:00
} else if ( type_str . substr ( 0 , 6 ) = = " $_DFF_ " & & type_str . size ( ) = = 10 ) {
2025-07-18 12:34:10 +02:00
info . is_fine = true ;
info . has_clk = true ;
info . pol_clk = type_str [ 6 ] = = ' P ' ;
info . has_arst = true ;
info . pol_arst = type_str [ 7 ] = = ' P ' ;
info . val_arst = type_str [ 8 ] = = ' 1 ' ? State : : S1 : State : : S0 ;
if constexpr ( have_cell ) {
info . sig_d = cell - > getPort ( ID : : D ) ;
info . sig_clk = cell - > getPort ( ID : : C ) ;
info . sig_arst = cell - > getPort ( ID : : R ) ;
}
2021-10-06 22:16:55 +02:00
} else if ( type_str . substr ( 0 , 7 ) = = " $_DFFE_ " & & type_str . size ( ) = = 12 ) {
2025-07-18 12:34:10 +02:00
info . is_fine = true ;
info . has_clk = true ;
info . pol_clk = type_str [ 7 ] = = ' P ' ;
info . has_arst = true ;
info . pol_arst = type_str [ 8 ] = = ' P ' ;
info . val_arst = type_str [ 9 ] = = ' 1 ' ? State : : S1 : State : : S0 ;
info . has_ce = true ;
info . pol_ce = type_str [ 10 ] = = ' P ' ;
if constexpr ( have_cell ) {
info . sig_d = cell - > getPort ( ID : : D ) ;
info . sig_clk = cell - > getPort ( ID : : C ) ;
info . sig_arst = cell - > getPort ( ID : : R ) ;
info . sig_ce = cell - > getPort ( ID : : E ) ;
}
2021-10-06 22:16:55 +02:00
} else if ( type_str . substr ( 0 , 8 ) = = " $_ALDFF_ " & & type_str . size ( ) = = 11 ) {
2025-07-18 12:34:10 +02:00
info . is_fine = true ;
info . has_clk = true ;
info . pol_clk = type_str [ 8 ] = = ' P ' ;
info . has_aload = true ;
info . pol_aload = type_str [ 9 ] = = ' P ' ;
if constexpr ( have_cell ) {
info . sig_d = cell - > getPort ( ID : : D ) ;
info . sig_clk = cell - > getPort ( ID : : C ) ;
info . sig_aload = cell - > getPort ( ID : : L ) ;
info . sig_ad = cell - > getPort ( ID : : AD ) ;
}
2021-10-06 22:16:55 +02:00
} else if ( type_str . substr ( 0 , 9 ) = = " $_ALDFFE_ " & & type_str . size ( ) = = 13 ) {
2025-07-18 12:34:10 +02:00
info . is_fine = true ;
info . has_clk = true ;
info . pol_clk = type_str [ 9 ] = = ' P ' ;
info . has_aload = true ;
info . pol_aload = type_str [ 10 ] = = ' P ' ;
info . has_ce = true ;
info . pol_ce = type_str [ 11 ] = = ' P ' ;
if constexpr ( have_cell ) {
info . sig_d = cell - > getPort ( ID : : D ) ;
info . sig_clk = cell - > getPort ( ID : : C ) ;
info . sig_aload = cell - > getPort ( ID : : L ) ;
info . sig_ad = cell - > getPort ( ID : : AD ) ;
info . sig_ce = cell - > getPort ( ID : : E ) ;
}
2021-10-06 22:16:55 +02:00
} else if ( type_str . substr ( 0 , 8 ) = = " $_DFFSR_ " & & type_str . size ( ) = = 12 ) {
2025-07-18 12:34:10 +02:00
info . is_fine = true ;
info . has_clk = true ;
info . pol_clk = type_str [ 8 ] = = ' P ' ;
info . has_sr = true ;
info . pol_set = type_str [ 9 ] = = ' P ' ;
info . pol_clr = type_str [ 10 ] = = ' P ' ;
if constexpr ( have_cell ) {
info . sig_d = cell - > getPort ( ID : : D ) ;
info . sig_clk = cell - > getPort ( ID : : C ) ;
info . sig_set = cell - > getPort ( ID : : S ) ;
info . sig_clr = cell - > getPort ( ID : : R ) ;
}
2021-10-06 22:16:55 +02:00
} else if ( type_str . substr ( 0 , 9 ) = = " $_DFFSRE_ " & & type_str . size ( ) = = 14 ) {
2025-07-18 12:34:10 +02:00
info . is_fine = true ;
info . has_clk = true ;
info . pol_clk = type_str [ 9 ] = = ' P ' ;
info . has_sr = true ;
info . pol_set = type_str [ 10 ] = = ' P ' ;
info . pol_clr = type_str [ 11 ] = = ' P ' ;
info . has_ce = true ;
info . pol_ce = type_str [ 12 ] = = ' P ' ;
if constexpr ( have_cell ) {
info . sig_d = cell - > getPort ( ID : : D ) ;
info . sig_clk = cell - > getPort ( ID : : C ) ;
info . sig_set = cell - > getPort ( ID : : S ) ;
info . sig_clr = cell - > getPort ( ID : : R ) ;
info . sig_ce = cell - > getPort ( ID : : E ) ;
}
2021-10-06 22:16:55 +02:00
} else if ( type_str . substr ( 0 , 7 ) = = " $_SDFF_ " & & type_str . size ( ) = = 11 ) {
2025-07-18 12:34:10 +02:00
info . is_fine = true ;
info . has_clk = true ;
info . pol_clk = type_str [ 7 ] = = ' P ' ;
info . has_srst = true ;
info . pol_srst = type_str [ 8 ] = = ' P ' ;
info . val_srst = type_str [ 9 ] = = ' 1 ' ? State : : S1 : State : : S0 ;
if constexpr ( have_cell ) {
info . sig_d = cell - > getPort ( ID : : D ) ;
info . sig_clk = cell - > getPort ( ID : : C ) ;
info . sig_srst = cell - > getPort ( ID : : R ) ;
}
2021-10-06 22:16:55 +02:00
} else if ( type_str . substr ( 0 , 8 ) = = " $_SDFFE_ " & & type_str . size ( ) = = 13 ) {
2025-07-18 12:34:10 +02:00
info . is_fine = true ;
info . has_clk = true ;
info . pol_clk = type_str [ 8 ] = = ' P ' ;
info . has_srst = true ;
info . pol_srst = type_str [ 9 ] = = ' P ' ;
info . val_srst = type_str [ 10 ] = = ' 1 ' ? State : : S1 : State : : S0 ;
info . has_ce = true ;
info . pol_ce = type_str [ 11 ] = = ' P ' ;
if constexpr ( have_cell ) {
info . sig_d = cell - > getPort ( ID : : D ) ;
info . sig_clk = cell - > getPort ( ID : : C ) ;
info . sig_srst = cell - > getPort ( ID : : R ) ;
info . sig_ce = cell - > getPort ( ID : : E ) ;
}
2021-10-06 22:16:55 +02:00
} else if ( type_str . substr ( 0 , 9 ) = = " $_SDFFCE_ " & & type_str . size ( ) = = 14 ) {
2025-07-18 12:34:10 +02:00
info . is_fine = true ;
info . has_clk = true ;
info . pol_clk = type_str [ 9 ] = = ' P ' ;
info . has_srst = true ;
info . pol_srst = type_str [ 10 ] = = ' P ' ;
info . val_srst = type_str [ 11 ] = = ' 1 ' ? State : : S1 : State : : S0 ;
info . has_ce = true ;
info . pol_ce = type_str [ 12 ] = = ' P ' ;
info . ce_over_srst = true ;
if constexpr ( have_cell ) {
info . sig_d = cell - > getPort ( ID : : D ) ;
info . sig_clk = cell - > getPort ( ID : : C ) ;
info . sig_srst = cell - > getPort ( ID : : R ) ;
info . sig_ce = cell - > getPort ( ID : : E ) ;
}
2021-10-06 22:16:55 +02:00
} else if ( type_str . substr ( 0 , 9 ) = = " $_DLATCH_ " & & type_str . size ( ) = = 11 ) {
2025-07-18 12:34:10 +02:00
info . is_fine = true ;
info . has_aload = true ;
info . has_aload = true ;
info . pol_aload = type_str [ 9 ] = = ' P ' ;
if constexpr ( have_cell ) {
info . sig_ad = cell - > getPort ( ID : : D ) ;
info . sig_aload = cell - > getPort ( ID : : E ) ;
}
2021-10-06 22:16:55 +02:00
} else if ( type_str . substr ( 0 , 9 ) = = " $_DLATCH_ " & & type_str . size ( ) = = 13 ) {
2025-07-18 12:34:10 +02:00
info . is_fine = true ;
info . has_aload = true ;
info . has_aload = true ;
info . pol_aload = type_str [ 9 ] = = ' P ' ;
info . has_arst = true ;
info . pol_arst = type_str [ 10 ] = = ' P ' ;
info . val_arst = type_str [ 11 ] = = ' 1 ' ? State : : S1 : State : : S0 ;
if constexpr ( have_cell ) {
info . sig_ad = cell - > getPort ( ID : : D ) ;
info . sig_aload = cell - > getPort ( ID : : E ) ;
info . sig_arst = cell - > getPort ( ID : : R ) ;
}
2021-10-06 22:16:55 +02:00
} else if ( type_str . substr ( 0 , 11 ) = = " $_DLATCHSR_ " & & type_str . size ( ) = = 15 ) {
2025-07-18 12:34:10 +02:00
info . is_fine = true ;
info . has_aload = true ;
info . has_aload = true ;
info . pol_aload = type_str [ 11 ] = = ' P ' ;
info . has_sr = true ;
info . pol_set = type_str [ 12 ] = = ' P ' ;
info . pol_clr = type_str [ 13 ] = = ' P ' ;
if constexpr ( have_cell ) {
info . sig_ad = cell - > getPort ( ID : : D ) ;
info . sig_aload = cell - > getPort ( ID : : E ) ;
info . sig_set = cell - > getPort ( ID : : S ) ;
info . sig_clr = cell - > getPort ( ID : : R ) ;
}
2021-10-06 22:16:55 +02:00
} else {
log_assert ( 0 ) ;
}
2025-07-18 12:34:10 +02:00
if constexpr ( have_cell )
if ( info . has_aload & & ! info . has_clk & & ! info . has_sr & & ! info . has_arst & & info . sig_ad . is_fully_const ( ) ) {
// Plain D latches with const D treated specially.
info . has_aload = false ;
info . has_arst = true ;
info . sig_arst = info . sig_aload ;
info . pol_arst = info . pol_aload ;
info . val_arst = info . sig_ad . as_const ( ) ;
}
}
FfTypeData : : FfTypeData ( IdString type ) : FfTypeData ( )
{
manufacture_info ( type , * this , nullptr ) ;
}
FfData : : FfData ( FfInitVals * initvals , Cell * cell_ ) : FfData ( cell_ - > module , initvals , cell_ - > name )
{
cell = cell_ ;
manufacture_info ( cell , * this , initvals ) ;
2021-10-06 22:16:55 +02:00
}
FfData FfData : : slice ( const std : : vector < int > & bits ) {
FfData res ( module , initvals , NEW_ID ) ;
res . sig_clk = sig_clk ;
res . sig_ce = sig_ce ;
res . sig_aload = sig_aload ;
res . sig_arst = sig_arst ;
res . sig_srst = sig_srst ;
res . has_clk = has_clk ;
res . has_gclk = has_gclk ;
res . has_ce = has_ce ;
res . has_aload = has_aload ;
res . has_arst = has_arst ;
res . has_srst = has_srst ;
res . has_sr = has_sr ;
res . ce_over_srst = ce_over_srst ;
res . is_fine = is_fine ;
2022-07-21 14:22:15 +02:00
res . is_anyinit = is_anyinit ;
2021-10-06 22:16:55 +02:00
res . pol_clk = pol_clk ;
res . pol_ce = pol_ce ;
res . pol_aload = pol_aload ;
res . pol_arst = pol_arst ;
res . pol_srst = pol_srst ;
res . pol_clr = pol_clr ;
res . pol_set = pol_set ;
res . attributes = attributes ;
2025-08-28 03:55:47 +02:00
std : : optional < Const : : Builder > arst_bits ;
if ( has_arst )
arst_bits . emplace ( bits . size ( ) ) ;
std : : optional < Const : : Builder > srst_bits ;
if ( has_srst )
srst_bits . emplace ( bits . size ( ) ) ;
std : : optional < Const : : Builder > init_bits ;
if ( initvals )
init_bits . emplace ( bits . size ( ) ) ;
2021-10-06 22:16:55 +02:00
for ( int i : bits ) {
res . sig_q . append ( sig_q [ i ] ) ;
if ( has_clk | | has_gclk )
res . sig_d . append ( sig_d [ i ] ) ;
if ( has_aload )
res . sig_ad . append ( sig_ad [ i ] ) ;
if ( has_sr ) {
res . sig_clr . append ( sig_clr [ i ] ) ;
res . sig_set . append ( sig_set [ i ] ) ;
}
if ( has_arst )
2025-08-28 03:55:47 +02:00
arst_bits - > push_back ( val_arst [ i ] ) ;
2021-10-06 22:16:55 +02:00
if ( has_srst )
2025-08-28 03:55:47 +02:00
srst_bits - > push_back ( val_srst [ i ] ) ;
2021-10-06 22:16:55 +02:00
if ( initvals )
2025-08-28 03:55:47 +02:00
init_bits - > push_back ( val_init [ i ] ) ;
2021-10-06 22:16:55 +02:00
}
2025-08-28 03:55:47 +02:00
if ( has_arst )
res . val_arst = arst_bits - > build ( ) ;
if ( has_srst )
res . val_srst = srst_bits - > build ( ) ;
if ( initvals )
res . val_init = init_bits - > build ( ) ;
2021-10-06 22:16:55 +02:00
res . width = GetSize ( res . sig_q ) ;
return res ;
}
2021-10-27 10:14:07 +02:00
void FfData : : add_dummy_ce ( ) {
if ( has_ce )
return ;
has_ce = true ;
pol_ce = true ;
sig_ce = State : : S1 ;
ce_over_srst = false ;
}
void FfData : : add_dummy_srst ( ) {
if ( has_srst )
return ;
has_srst = true ;
pol_srst = true ;
sig_srst = State : : S0 ;
val_srst = Const ( State : : Sx , width ) ;
ce_over_srst = false ;
}
void FfData : : add_dummy_arst ( ) {
if ( has_arst )
return ;
has_arst = true ;
pol_arst = true ;
sig_arst = State : : S0 ;
val_arst = Const ( State : : Sx , width ) ;
}
void FfData : : add_dummy_aload ( ) {
if ( has_aload )
return ;
has_aload = true ;
pol_aload = true ;
sig_aload = State : : S0 ;
sig_ad = Const ( State : : Sx , width ) ;
}
void FfData : : add_dummy_sr ( ) {
if ( has_sr )
return ;
has_sr = true ;
pol_clr = true ;
pol_set = true ;
sig_clr = Const ( State : : S0 , width ) ;
sig_set = Const ( State : : S0 , width ) ;
}
void FfData : : add_dummy_clk ( ) {
if ( has_clk )
return ;
has_clk = true ;
pol_clk = true ;
sig_clk = State : : S0 ;
sig_d = Const ( State : : Sx , width ) ;
}
void FfData : : arst_to_aload ( ) {
log_assert ( has_arst ) ;
log_assert ( ! has_aload ) ;
pol_aload = pol_arst ;
sig_aload = sig_arst ;
sig_ad = val_arst ;
has_aload = true ;
has_arst = false ;
}
void FfData : : arst_to_sr ( ) {
log_assert ( has_arst ) ;
log_assert ( ! has_sr ) ;
pol_clr = pol_arst ;
pol_set = pol_arst ;
sig_clr = Const ( pol_arst ? State : : S0 : State : : S1 , width ) ;
sig_set = Const ( pol_arst ? State : : S0 : State : : S1 , width ) ;
has_sr = true ;
has_arst = false ;
for ( int i = 0 ; i < width ; i + + ) {
if ( val_arst [ i ] = = State : : S1 )
sig_set [ i ] = sig_arst ;
else
sig_clr [ i ] = sig_arst ;
}
}
void FfData : : aload_to_sr ( ) {
log_assert ( has_aload ) ;
log_assert ( ! has_sr ) ;
has_sr = true ;
has_aload = false ;
if ( ! is_fine ) {
pol_clr = false ;
pol_set = true ;
if ( pol_aload ) {
sig_clr = module - > Mux ( NEW_ID , Const ( State : : S1 , width ) , sig_ad , sig_aload ) ;
sig_set = module - > Mux ( NEW_ID , Const ( State : : S0 , width ) , sig_ad , sig_aload ) ;
} else {
sig_clr = module - > Mux ( NEW_ID , sig_ad , Const ( State : : S1 , width ) , sig_aload ) ;
sig_set = module - > Mux ( NEW_ID , sig_ad , Const ( State : : S0 , width ) , sig_aload ) ;
}
} else {
pol_clr = pol_aload ;
pol_set = pol_aload ;
if ( pol_aload ) {
sig_clr = module - > AndnotGate ( NEW_ID , sig_aload , sig_ad ) ;
sig_set = module - > AndGate ( NEW_ID , sig_aload , sig_ad ) ;
} else {
sig_clr = module - > OrGate ( NEW_ID , sig_aload , sig_ad ) ;
sig_set = module - > OrnotGate ( NEW_ID , sig_aload , sig_ad ) ;
}
}
}
void FfData : : convert_ce_over_srst ( bool val ) {
if ( ! has_ce | | ! has_srst | | ce_over_srst = = val )
return ;
if ( val ) {
// sdffe to sdffce
if ( ! is_fine ) {
if ( pol_ce ) {
if ( pol_srst ) {
sig_ce = module - > Or ( NEW_ID , sig_ce , sig_srst ) ;
} else {
SigSpec tmp = module - > Not ( NEW_ID , sig_srst ) ;
sig_ce = module - > Or ( NEW_ID , sig_ce , tmp ) ;
}
} else {
if ( pol_srst ) {
SigSpec tmp = module - > Not ( NEW_ID , sig_srst ) ;
sig_ce = module - > And ( NEW_ID , sig_ce , tmp ) ;
} else {
sig_ce = module - > And ( NEW_ID , sig_ce , sig_srst ) ;
}
}
} else {
if ( pol_ce ) {
if ( pol_srst ) {
sig_ce = module - > OrGate ( NEW_ID , sig_ce , sig_srst ) ;
} else {
sig_ce = module - > OrnotGate ( NEW_ID , sig_ce , sig_srst ) ;
}
} else {
if ( pol_srst ) {
sig_ce = module - > AndnotGate ( NEW_ID , sig_ce , sig_srst ) ;
} else {
sig_ce = module - > AndGate ( NEW_ID , sig_ce , sig_srst ) ;
}
}
}
} else {
// sdffce to sdffe
if ( ! is_fine ) {
if ( pol_srst ) {
if ( pol_ce ) {
sig_srst = cell - > module - > And ( NEW_ID , sig_srst , sig_ce ) ;
} else {
SigSpec tmp = module - > Not ( NEW_ID , sig_ce ) ;
sig_srst = cell - > module - > And ( NEW_ID , sig_srst , tmp ) ;
}
} else {
if ( pol_ce ) {
SigSpec tmp = module - > Not ( NEW_ID , sig_ce ) ;
sig_srst = cell - > module - > Or ( NEW_ID , sig_srst , tmp ) ;
} else {
sig_srst = cell - > module - > Or ( NEW_ID , sig_srst , sig_ce ) ;
}
}
} else {
if ( pol_srst ) {
if ( pol_ce ) {
sig_srst = cell - > module - > AndGate ( NEW_ID , sig_srst , sig_ce ) ;
} else {
sig_srst = cell - > module - > AndnotGate ( NEW_ID , sig_srst , sig_ce ) ;
}
} else {
if ( pol_ce ) {
sig_srst = cell - > module - > OrnotGate ( NEW_ID , sig_srst , sig_ce ) ;
} else {
sig_srst = cell - > module - > OrGate ( NEW_ID , sig_srst , sig_ce ) ;
}
}
}
}
ce_over_srst = val ;
}
2021-10-06 22:16:55 +02:00
void FfData : : unmap_ce ( ) {
if ( ! has_ce )
return ;
log_assert ( has_clk ) ;
if ( has_srst & & ce_over_srst )
unmap_srst ( ) ;
if ( ! is_fine ) {
if ( pol_ce )
sig_d = module - > Mux ( NEW_ID , sig_q , sig_d , sig_ce ) ;
else
sig_d = module - > Mux ( NEW_ID , sig_d , sig_q , sig_ce ) ;
} else {
if ( pol_ce )
sig_d = module - > MuxGate ( NEW_ID , sig_q , sig_d , sig_ce ) ;
else
sig_d = module - > MuxGate ( NEW_ID , sig_d , sig_q , sig_ce ) ;
}
has_ce = false ;
}
void FfData : : unmap_srst ( ) {
if ( ! has_srst )
return ;
if ( has_ce & & ! ce_over_srst )
unmap_ce ( ) ;
if ( ! is_fine ) {
if ( pol_srst )
sig_d = module - > Mux ( NEW_ID , sig_d , val_srst , sig_srst ) ;
else
sig_d = module - > Mux ( NEW_ID , val_srst , sig_d , sig_srst ) ;
} else {
if ( pol_srst )
sig_d = module - > MuxGate ( NEW_ID , sig_d , val_srst [ 0 ] , sig_srst ) ;
else
sig_d = module - > MuxGate ( NEW_ID , val_srst [ 0 ] , sig_d , sig_srst ) ;
}
has_srst = false ;
}
Cell * FfData : : emit ( ) {
remove ( ) ;
if ( ! width )
return nullptr ;
if ( ! has_aload & & ! has_clk & & ! has_gclk & & ! has_sr ) {
if ( has_arst ) {
// Convert this case to a D latch.
2021-10-27 10:14:07 +02:00
arst_to_aload ( ) ;
2021-10-06 22:16:55 +02:00
} else {
// No control inputs left. Turn into a const driver.
module - > connect ( sig_q , val_init ) ;
return nullptr ;
}
}
if ( ! is_fine ) {
if ( has_gclk ) {
log_assert ( ! has_clk ) ;
log_assert ( ! has_ce ) ;
log_assert ( ! has_aload ) ;
log_assert ( ! has_arst ) ;
log_assert ( ! has_srst ) ;
log_assert ( ! has_sr ) ;
2022-07-21 14:22:15 +02:00
if ( is_anyinit ) {
cell = module - > addAnyinit ( name , sig_d , sig_q ) ;
log_assert ( val_init . is_fully_undef ( ) ) ;
} else {
cell = module - > addFf ( name , sig_d , sig_q ) ;
}
2021-10-06 22:16:55 +02:00
} else if ( ! has_aload & & ! has_clk ) {
log_assert ( has_sr ) ;
cell = module - > addSr ( name , sig_set , sig_clr , sig_q , pol_set , pol_clr ) ;
} else if ( ! has_clk ) {
log_assert ( ! has_srst ) ;
if ( has_sr )
cell = module - > addDlatchsr ( name , sig_aload , sig_set , sig_clr , sig_ad , sig_q , pol_aload , pol_set , pol_clr ) ;
else if ( has_arst )
cell = module - > addAdlatch ( name , sig_aload , sig_arst , sig_ad , sig_q , val_arst , pol_aload , pol_arst ) ;
else
cell = module - > addDlatch ( name , sig_aload , sig_ad , sig_q , pol_aload ) ;
} else {
if ( has_sr ) {
if ( has_ce )
cell = module - > addDffsre ( name , sig_clk , sig_ce , sig_set , sig_clr , sig_d , sig_q , pol_clk , pol_ce , pol_set , pol_clr ) ;
else
cell = module - > addDffsr ( name , sig_clk , sig_set , sig_clr , sig_d , sig_q , pol_clk , pol_set , pol_clr ) ;
} else if ( has_arst ) {
if ( has_ce )
cell = module - > addAdffe ( name , sig_clk , sig_ce , sig_arst , sig_d , sig_q , val_arst , pol_clk , pol_ce , pol_arst ) ;
else
cell = module - > addAdff ( name , sig_clk , sig_arst , sig_d , sig_q , val_arst , pol_clk , pol_arst ) ;
} else if ( has_aload ) {
if ( has_ce )
cell = module - > addAldffe ( name , sig_clk , sig_ce , sig_aload , sig_d , sig_q , sig_ad , pol_clk , pol_ce , pol_aload ) ;
else
cell = module - > addAldff ( name , sig_clk , sig_aload , sig_d , sig_q , sig_ad , pol_clk , pol_aload ) ;
} else if ( has_srst ) {
if ( has_ce )
if ( ce_over_srst )
cell = module - > addSdffce ( name , sig_clk , sig_ce , sig_srst , sig_d , sig_q , val_srst , pol_clk , pol_ce , pol_srst ) ;
else
cell = module - > addSdffe ( name , sig_clk , sig_ce , sig_srst , sig_d , sig_q , val_srst , pol_clk , pol_ce , pol_srst ) ;
else
cell = module - > addSdff ( name , sig_clk , sig_srst , sig_d , sig_q , val_srst , pol_clk , pol_srst ) ;
} else {
if ( has_ce )
cell = module - > addDffe ( name , sig_clk , sig_ce , sig_d , sig_q , pol_clk , pol_ce ) ;
else
cell = module - > addDff ( name , sig_clk , sig_d , sig_q , pol_clk ) ;
}
}
} else {
if ( has_gclk ) {
log_assert ( ! has_clk ) ;
log_assert ( ! has_ce ) ;
log_assert ( ! has_aload ) ;
log_assert ( ! has_arst ) ;
log_assert ( ! has_srst ) ;
log_assert ( ! has_sr ) ;
2022-07-21 14:22:15 +02:00
log_assert ( ! is_anyinit ) ;
2021-10-06 22:16:55 +02:00
cell = module - > addFfGate ( name , sig_d , sig_q ) ;
} else if ( ! has_aload & & ! has_clk ) {
log_assert ( has_sr ) ;
cell = module - > addSrGate ( name , sig_set , sig_clr , sig_q , pol_set , pol_clr ) ;
} else if ( ! has_clk ) {
log_assert ( ! has_srst ) ;
if ( has_sr )
cell = module - > addDlatchsrGate ( name , sig_aload , sig_set , sig_clr , sig_ad , sig_q , pol_aload , pol_set , pol_clr ) ;
else if ( has_arst )
cell = module - > addAdlatchGate ( name , sig_aload , sig_arst , sig_ad , sig_q , val_arst . as_bool ( ) , pol_aload , pol_arst ) ;
else
cell = module - > addDlatchGate ( name , sig_aload , sig_ad , sig_q , pol_aload ) ;
} else {
if ( has_sr ) {
if ( has_ce )
cell = module - > addDffsreGate ( name , sig_clk , sig_ce , sig_set , sig_clr , sig_d , sig_q , pol_clk , pol_ce , pol_set , pol_clr ) ;
else
cell = module - > addDffsrGate ( name , sig_clk , sig_set , sig_clr , sig_d , sig_q , pol_clk , pol_set , pol_clr ) ;
} else if ( has_arst ) {
if ( has_ce )
cell = module - > addAdffeGate ( name , sig_clk , sig_ce , sig_arst , sig_d , sig_q , val_arst . as_bool ( ) , pol_clk , pol_ce , pol_arst ) ;
else
cell = module - > addAdffGate ( name , sig_clk , sig_arst , sig_d , sig_q , val_arst . as_bool ( ) , pol_clk , pol_arst ) ;
} else if ( has_aload ) {
if ( has_ce )
cell = module - > addAldffeGate ( name , sig_clk , sig_ce , sig_aload , sig_d , sig_q , sig_ad , pol_clk , pol_ce , pol_aload ) ;
else
cell = module - > addAldffGate ( name , sig_clk , sig_aload , sig_d , sig_q , sig_ad , pol_clk , pol_aload ) ;
} else if ( has_srst ) {
if ( has_ce )
if ( ce_over_srst )
cell = module - > addSdffceGate ( name , sig_clk , sig_ce , sig_srst , sig_d , sig_q , val_srst . as_bool ( ) , pol_clk , pol_ce , pol_srst ) ;
else
cell = module - > addSdffeGate ( name , sig_clk , sig_ce , sig_srst , sig_d , sig_q , val_srst . as_bool ( ) , pol_clk , pol_ce , pol_srst ) ;
else
cell = module - > addSdffGate ( name , sig_clk , sig_srst , sig_d , sig_q , val_srst . as_bool ( ) , pol_clk , pol_srst ) ;
} else {
if ( has_ce )
cell = module - > addDffeGate ( name , sig_clk , sig_ce , sig_d , sig_q , pol_clk , pol_ce ) ;
else
cell = module - > addDffGate ( name , sig_clk , sig_d , sig_q , pol_clk ) ;
}
}
}
cell - > attributes = attributes ;
2026-03-09 23:38:10 +01:00
if ( initvals & & ! is_anyinit )
initvals - > set_init ( cell - > getPort ( ID : : Q ) , val_init ) ;
2021-10-06 22:16:55 +02:00
return cell ;
}
void FfData : : remove ( ) {
if ( cell ) {
remove_init ( ) ;
module - > remove ( cell ) ;
cell = nullptr ;
}
}
namespace {
State invert ( State s ) {
switch ( s ) {
case State : : S0 : return State : : S1 ;
case State : : S1 : return State : : S0 ;
default : return s ;
}
}
}
2022-05-13 16:59:52 +02:00
void FfData : : flip_rst_bits ( const pool < int > & bits ) {
2021-10-06 22:16:55 +02:00
if ( ! bits . size ( ) )
return ;
remove_init ( ) ;
for ( auto bit : bits ) {
if ( has_arst )
2025-08-28 03:55:47 +02:00
val_arst . set ( bit , invert ( val_arst [ bit ] ) ) ;
2021-10-06 22:16:55 +02:00
if ( has_srst )
2025-08-28 03:55:47 +02:00
val_srst . set ( bit , invert ( val_srst [ bit ] ) ) ;
val_init . set ( bit , invert ( val_init [ bit ] ) ) ;
2021-10-06 22:16:55 +02:00
}
2022-05-13 16:59:52 +02:00
}
void FfData : : flip_bits ( const pool < int > & bits ) {
if ( ! bits . size ( ) )
return ;
flip_rst_bits ( bits ) ;
Wire * new_q = module - > addWire ( NEW_ID , width ) ;
2021-10-06 22:16:55 +02:00
if ( has_sr & & cell ) {
2026-05-08 09:01:43 +02:00
log_warning ( " Flipping D/Q/init and inserting priority fixup to legalize %s.%s [%s]. \n " , module - > name . unescape ( ) , cell - > name . unescape ( ) , cell - > type . unescape ( ) ) ;
2021-10-06 22:16:55 +02:00
}
if ( is_fine ) {
if ( has_sr ) {
bool new_pol_clr = pol_set ;
SigSpec new_sig_clr ;
if ( pol_set ) {
if ( pol_clr ) {
new_sig_clr = module - > AndnotGate ( NEW_ID , sig_set , sig_clr ) ;
} else {
new_sig_clr = module - > AndGate ( NEW_ID , sig_set , sig_clr ) ;
}
} else {
if ( pol_clr ) {
new_sig_clr = module - > OrGate ( NEW_ID , sig_set , sig_clr ) ;
} else {
new_sig_clr = module - > OrnotGate ( NEW_ID , sig_set , sig_clr ) ;
}
}
pol_set = pol_clr ;
sig_set = sig_clr ;
pol_clr = new_pol_clr ;
sig_clr = new_sig_clr ;
}
if ( has_clk | | has_gclk )
sig_d = module - > NotGate ( NEW_ID , sig_d ) ;
if ( has_aload )
sig_ad = module - > NotGate ( NEW_ID , sig_ad ) ;
module - > addNotGate ( NEW_ID , new_q , sig_q ) ;
}
else
{
if ( has_sr ) {
SigSpec not_clr ;
if ( ! pol_clr ) {
not_clr = sig_clr ;
sig_clr = module - > Not ( NEW_ID , sig_clr ) ;
pol_clr = true ;
} else {
not_clr = module - > Not ( NEW_ID , sig_clr ) ;
}
if ( ! pol_set ) {
sig_set = module - > Not ( NEW_ID , sig_set ) ;
pol_set = true ;
}
SigSpec masked_set = module - > And ( NEW_ID , sig_set , not_clr ) ;
for ( auto bit : bits ) {
sig_set [ bit ] = sig_clr [ bit ] ;
sig_clr [ bit ] = masked_set [ bit ] ;
}
}
Const mask = Const ( State : : S0 , width ) ;
for ( auto bit : bits )
2025-08-28 03:55:47 +02:00
mask . set ( bit , State : : S1 ) ;
2021-10-06 22:16:55 +02:00
if ( has_clk | | has_gclk )
sig_d = module - > Xor ( NEW_ID , sig_d , mask ) ;
if ( has_aload )
sig_ad = module - > Xor ( NEW_ID , sig_ad , mask ) ;
module - > addXor ( NEW_ID , new_q , mask , sig_q ) ;
}
sig_q = new_q ;
}