2020-06-23 07:36:34 -05: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/yosys.h"
# include "kernel/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
enum FfType {
FF_DFF ,
FF_DFFE ,
FF_ADFF0 ,
FF_ADFF1 ,
FF_ADFFE0 ,
FF_ADFFE1 ,
FF_DFFSR ,
FF_DFFSRE ,
FF_SDFF0 ,
FF_SDFF1 ,
FF_SDFFE0 ,
FF_SDFFE1 ,
FF_SDFFCE0 ,
FF_SDFFCE1 ,
FF_SR ,
FF_DLATCH ,
FF_ADLATCH0 ,
FF_ADLATCH1 ,
FF_DLATCHSR ,
NUM_FFTYPES ,
} ;
enum FfNeg {
NEG_R = 0x1 ,
NEG_S = 0x2 ,
NEG_E = 0x4 ,
NEG_C = 0x8 ,
NUM_NEG = 0x10 ,
} ;
enum FfInit {
INIT_X = 0x1 ,
INIT_0 = 0x2 ,
INIT_1 = 0x4 ,
} ;
struct DffLegalizePass : public Pass {
DffLegalizePass ( ) : Pass ( " dfflegalize " , " convert FFs to types supported by the target " ) { }
void help ( ) override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log ( " \n " ) ;
log ( " dfflegalize [options] [selection] \n " ) ;
log ( " \n " ) ;
log ( " Converts FFs to types supported by the target. \n " ) ;
log ( " \n " ) ;
log ( " -cell <cell_type_pattern> <init_values> \n " ) ;
log ( " specifies a supported group of FF cells. <cell_type_pattern> \n " ) ;
log ( " is a yosys internal fine cell name, where ? characters can be \n " ) ;
log ( " as a wildcard matching any character. <init_values> specifies \n " ) ;
log ( " which initialization values these FF cells can support, and can \n " ) ;
log ( " be one of: \n " ) ;
log ( " \n " ) ;
log ( " - x (no init value supported) \n " ) ;
log ( " - 0 \n " ) ;
log ( " - 1 \n " ) ;
log ( " - r (init value has to match reset value, only for some FF types) \n " ) ;
log ( " - 01 (both 0 and 1 supported). \n " ) ;
log ( " \n " ) ;
log ( " -mince <num> \n " ) ;
log ( " specifies a minimum number of FFs that should be using any given \n " ) ;
log ( " clock enable signal. If a clock enable signal doesn't meet this \n " ) ;
log ( " threshold, it is unmapped into soft logic. \n " ) ;
log ( " \n " ) ;
log ( " -minsrst <num> \n " ) ;
log ( " specifies a minimum number of FFs that should be using any given \n " ) ;
log ( " sync set/reset signal. If a sync set/reset signal doesn't meet this \n " ) ;
log ( " threshold, it is unmapped into soft logic. \n " ) ;
log ( " \n " ) ;
log ( " The following cells are supported by this pass (ie. will be ingested, \n " ) ;
log ( " and can be specified as allowed targets): \n " ) ;
log ( " \n " ) ;
log ( " - $_DFF_[NP]_ \n " ) ;
log ( " - $_DFFE_[NP][NP]_ \n " ) ;
log ( " - $_DFF_[NP][NP][01]_ \n " ) ;
log ( " - $_DFFE_[NP][NP][01][NP]_ \n " ) ;
log ( " - $_DFFSR_[NP][NP][NP]_ \n " ) ;
log ( " - $_DFFSRE_[NP][NP][NP][NP]_ \n " ) ;
log ( " - $_SDFF_[NP][NP][01]_ \n " ) ;
log ( " - $_SDFFE_[NP][NP][01][NP]_ \n " ) ;
log ( " - $_SDFFCE_[NP][NP][01][NP]_ \n " ) ;
log ( " - $_SR_[NP][NP]_ \n " ) ;
log ( " - $_DLATCH_[NP]_ \n " ) ;
log ( " - $_DLATCH_[NP][NP][01]_ \n " ) ;
log ( " - $_DLATCHSR_[NP][NP][NP]_ \n " ) ;
log ( " \n " ) ;
log ( " The following transformations are performed by this pass: " ) ;
2020-07-03 05:12:03 -05:00
log ( " \n " ) ;
2020-06-23 07:36:34 -05:00
log ( " - upconversion from a less capable cell to a more capable cell, if the less " ) ;
log ( " capable cell is not supported (eg. dff -> dffe, or adff -> dffsr) " ) ;
2020-07-03 05:12:03 -05:00
log ( " \n " ) ;
2020-06-23 07:36:34 -05:00
log ( " - unmapping FFs with clock enable (due to unsupported cell type or -mince) " ) ;
2020-07-03 05:12:03 -05:00
log ( " \n " ) ;
2020-06-23 07:36:34 -05:00
log ( " - unmapping FFs with sync reset (due to unsupported cell type or -minsrst) " ) ;
2020-07-03 05:12:03 -05:00
log ( " \n " ) ;
2020-06-23 07:36:34 -05:00
log ( " - adding inverters on the control pins (due to unsupported polarity) " ) ;
2020-07-03 05:12:03 -05:00
log ( " \n " ) ;
2020-06-23 07:36:34 -05:00
log ( " - adding inverters on the D and Q pins and inverting the init/reset values \n " ) ;
log ( " (due to unsupported init or reset value) " ) ;
2020-07-03 05:12:03 -05:00
log ( " \n " ) ;
2020-06-23 07:36:34 -05:00
log ( " - converting sr into adlatch (by tying D to 1 and using E as set input) " ) ;
2020-07-03 05:12:03 -05:00
log ( " \n " ) ;
2020-06-23 07:36:34 -05:00
log ( " - emulating unsupported dffsr cell by adff + adff + sr + mux " ) ;
2020-07-03 05:12:03 -05:00
log ( " \n " ) ;
2020-06-23 07:36:34 -05:00
log ( " - emulating unsupported dlatchsr cell by adlatch + adlatch + sr + mux " ) ;
2020-07-03 05:12:03 -05:00
log ( " \n " ) ;
2020-06-23 07:36:34 -05:00
log ( " - emulating adff when the (reset, init) value combination is unsupported by \n " ) ;
log ( " dff + adff + dlatch + mux " ) ;
2020-07-03 05:12:03 -05:00
log ( " \n " ) ;
2020-06-23 07:36:34 -05:00
log ( " - emulating adlatch when the (reset, init) value combination is unsupported by \n " ) ;
log ( " - dlatch + adlatch + dlatch + mux " ) ;
2020-07-03 05:12:03 -05:00
log ( " \n " ) ;
2020-06-23 07:36:34 -05:00
log ( " If the pass is unable to realize a given cell type (eg. adff when only plain dff " ) ;
log ( " is available), an error is raised. " ) ;
}
// Table of all supported cell types.
// First index in the array is one of the FF_* values, second
// index is the set of negative-polarity inputs (OR of NEG_*
// values), and the value is the set of supported init values
// (OR of INIT_* values).
int supported_cells_neg [ NUM_FFTYPES ] [ NUM_NEG ] ;
// Aggregated table ignoring signal polarity.
int supported_cells [ NUM_FFTYPES ] ;
// Aggregated for all *dff* cells.
int supported_dff ;
// Aggregated for all dffsr* cells.
int supported_dffsr ;
// Aggregated for all adff* cells.
int supported_adff0 ;
int supported_adff1 ;
// Aggregated for all sdff* cells.
int supported_sdff0 ;
int supported_sdff1 ;
// Aggregated for all ways to obtain a SR latch.
int supported_sr ;
// Aggregated for all *dlatch* cells.
int supported_dlatch ;
int mince ;
int minsrst ;
dict < SigBit , int > ce_used ;
dict < SigBit , int > srst_used ;
SigMap sigmap ;
dict < SigBit , std : : pair < State , SigBit > > initbits ;
int flip_initmask ( int mask ) {
int res = mask & INIT_X ;
if ( mask & INIT_0 )
res | = INIT_1 ;
if ( mask & INIT_1 )
res | = INIT_0 ;
return res ;
}
void handle_ff ( Cell * cell ) {
std : : string type_str = cell - > type . str ( ) ;
FfType ff_type ;
int ff_neg = 0 ;
SigSpec sig_d ;
SigSpec sig_q ;
SigSpec sig_c ;
SigSpec sig_e ;
SigSpec sig_r ;
SigSpec sig_s ;
bool has_srst = false ;
if ( cell - > hasPort ( ID : : D ) )
sig_d = cell - > getPort ( ID : : D ) ;
if ( cell - > hasPort ( ID : : Q ) )
sig_q = cell - > getPort ( ID : : Q ) ;
if ( cell - > hasPort ( ID : : C ) )
sig_c = cell - > getPort ( ID : : C ) ;
if ( cell - > hasPort ( ID : : E ) )
sig_e = cell - > getPort ( ID : : E ) ;
if ( cell - > hasPort ( ID : : R ) )
sig_r = cell - > getPort ( ID : : R ) ;
if ( cell - > hasPort ( ID : : S ) )
sig_s = cell - > getPort ( ID : : S ) ;
if ( type_str . substr ( 0 , 5 ) = = " $_SR_ " ) {
ff_type = FF_SR ;
if ( type_str [ 5 ] = = ' N ' )
ff_neg | = NEG_S ;
if ( type_str [ 6 ] = = ' N ' )
ff_neg | = NEG_R ;
} else if ( type_str . substr ( 0 , 6 ) = = " $_DFF_ " & & type_str . size ( ) = = 8 ) {
ff_type = FF_DFF ;
if ( type_str [ 6 ] = = ' N ' )
ff_neg | = NEG_C ;
} else if ( type_str . substr ( 0 , 7 ) = = " $_DFFE_ " & & type_str . size ( ) = = 10 ) {
ff_type = FF_DFFE ;
if ( type_str [ 7 ] = = ' N ' )
ff_neg | = NEG_C ;
if ( type_str [ 8 ] = = ' N ' )
ff_neg | = NEG_E ;
} else if ( type_str . substr ( 0 , 6 ) = = " $_DFF_ " & & type_str . size ( ) = = 10 ) {
ff_type = type_str [ 8 ] = = ' 1 ' ? FF_ADFF1 : FF_ADFF0 ;
if ( type_str [ 6 ] = = ' N ' )
ff_neg | = NEG_C ;
if ( type_str [ 7 ] = = ' N ' )
ff_neg | = NEG_R ;
} else if ( type_str . substr ( 0 , 7 ) = = " $_DFFE_ " & & type_str . size ( ) = = 12 ) {
ff_type = type_str [ 9 ] = = ' 1 ' ? FF_ADFFE1 : FF_ADFFE0 ;
if ( type_str [ 7 ] = = ' N ' )
ff_neg | = NEG_C ;
if ( type_str [ 8 ] = = ' N ' )
ff_neg | = NEG_R ;
if ( type_str [ 10 ] = = ' N ' )
ff_neg | = NEG_E ;
} else if ( type_str . substr ( 0 , 8 ) = = " $_DFFSR_ " & & type_str . size ( ) = = 12 ) {
ff_type = FF_DFFSR ;
if ( type_str [ 8 ] = = ' N ' )
ff_neg | = NEG_C ;
if ( type_str [ 9 ] = = ' N ' )
ff_neg | = NEG_S ;
if ( type_str [ 10 ] = = ' N ' )
ff_neg | = NEG_R ;
} else if ( type_str . substr ( 0 , 9 ) = = " $_DFFSRE_ " & & type_str . size ( ) = = 14 ) {
ff_type = FF_DFFSRE ;
if ( type_str [ 9 ] = = ' N ' )
ff_neg | = NEG_C ;
if ( type_str [ 10 ] = = ' N ' )
ff_neg | = NEG_S ;
if ( type_str [ 11 ] = = ' N ' )
ff_neg | = NEG_R ;
if ( type_str [ 12 ] = = ' N ' )
ff_neg | = NEG_E ;
} else if ( type_str . substr ( 0 , 7 ) = = " $_SDFF_ " & & type_str . size ( ) = = 11 ) {
ff_type = type_str [ 9 ] = = ' 1 ' ? FF_SDFF1 : FF_SDFF0 ;
if ( type_str [ 7 ] = = ' N ' )
ff_neg | = NEG_C ;
if ( type_str [ 8 ] = = ' N ' )
ff_neg | = NEG_R ;
has_srst = true ;
} else if ( type_str . substr ( 0 , 8 ) = = " $_SDFFE_ " & & type_str . size ( ) = = 13 ) {
ff_type = type_str [ 10 ] = = ' 1 ' ? FF_SDFFE1 : FF_SDFFE0 ;
if ( type_str [ 8 ] = = ' N ' )
ff_neg | = NEG_C ;
if ( type_str [ 9 ] = = ' N ' )
ff_neg | = NEG_R ;
if ( type_str [ 11 ] = = ' N ' )
ff_neg | = NEG_E ;
has_srst = true ;
} else if ( type_str . substr ( 0 , 9 ) = = " $_SDFFCE_ " & & type_str . size ( ) = = 14 ) {
ff_type = type_str [ 11 ] = = ' 1 ' ? FF_SDFFCE1 : FF_SDFFCE0 ;
if ( type_str [ 9 ] = = ' N ' )
ff_neg | = NEG_C ;
if ( type_str [ 10 ] = = ' N ' )
ff_neg | = NEG_R ;
if ( type_str [ 12 ] = = ' N ' )
ff_neg | = NEG_E ;
has_srst = true ;
} else if ( type_str . substr ( 0 , 9 ) = = " $_DLATCH_ " & & type_str . size ( ) = = 11 ) {
ff_type = FF_DLATCH ;
if ( type_str [ 9 ] = = ' N ' )
ff_neg | = NEG_E ;
} else if ( type_str . substr ( 0 , 9 ) = = " $_DLATCH_ " & & type_str . size ( ) = = 13 ) {
ff_type = type_str [ 11 ] = = ' 1 ' ? FF_ADLATCH1 : FF_ADLATCH0 ;
if ( type_str [ 9 ] = = ' N ' )
ff_neg | = NEG_E ;
if ( type_str [ 10 ] = = ' N ' )
ff_neg | = NEG_R ;
} else if ( type_str . substr ( 0 , 11 ) = = " $_DLATCHSR_ " & & type_str . size ( ) = = 15 ) {
ff_type = FF_DLATCHSR ;
if ( type_str [ 11 ] = = ' N ' )
ff_neg | = NEG_E ;
if ( type_str [ 12 ] = = ' N ' )
ff_neg | = NEG_S ;
if ( type_str [ 13 ] = = ' N ' )
ff_neg | = NEG_R ;
} else {
log_warning ( " Ignoring unknown ff type %s [%s.%s]. \n " , log_id ( cell - > type ) , log_id ( cell - > module - > name ) , log_id ( cell - > name ) ) ;
return ;
}
State initval = State : : Sx ;
SigBit initbit ;
if ( GetSize ( sig_q ) > 0 & & initbits . count ( sigmap ( sig_q [ 0 ] ) ) ) {
const auto & d = initbits . at ( sigmap ( sig_q [ 0 ] ) ) ;
initval = d . first ;
initbit = d . second ;
}
FfInit initmask = INIT_X ;
if ( initval = = State : : S0 )
initmask = INIT_0 ;
else if ( initval = = State : : S1 )
initmask = INIT_1 ;
const char * reason ;
bool kill_ce = mince & & GetSize ( sig_c ) & & GetSize ( sig_e ) & & sig_e [ 0 ] . wire & & ce_used [ sig_e [ 0 ] ] < mince ;
bool kill_srst = minsrst & & has_srst & & sig_r [ 0 ] . wire & & srst_used [ sig_r [ 0 ] ] < minsrst ;
while ( ! ( supported_cells [ ff_type ] & initmask ) | | kill_ce | | kill_srst ) {
// Well, cell is not directly supported. Decide how to deal with it.
if ( ff_type = = FF_DFF | | ff_type = = FF_DFFE ) {
if ( kill_ce ) {
ff_type = FF_DFF ;
goto unmap_enable ;
}
if ( ! ( supported_dff & initmask ) ) {
// This init value is not supported at all...
if ( supported_dff & flip_initmask ( initmask ) ) {
// The other one is, though. Negate D, Q, and init.
flip_dqi :
if ( initval = = State : : S0 ) {
initval = State : : S1 ;
initmask = INIT_1 ;
} else if ( initval = = State : : S1 ) {
initval = State : : S0 ;
initmask = INIT_0 ;
}
if ( ff_type ! = FF_SR )
sig_d = cell - > module - > NotGate ( NEW_ID , sig_d [ 0 ] ) ;
SigBit new_q = SigSpec ( cell - > module - > addWire ( NEW_ID ) ) [ 0 ] ;
cell - > module - > addNotGate ( NEW_ID , new_q , sig_q [ 0 ] ) ;
if ( initbit . wire ) {
initbit . wire - > attributes . at ( ID : : init ) [ initbit . offset ] = State : : Sx ;
initbit = new_q ;
new_q . wire - > attributes [ ID : : init ] = initval ;
initbits [ new_q ] = std : : make_pair ( initval , new_q ) ;
}
sig_q = new_q ;
continue ;
}
if ( ! supported_dff )
reason = " dffs are not supported " ;
else
reason = " initialized dffs are not supported " ;
goto error ;
}
// Some DFF is supported with this init val. Just pick a type.
if ( ff_type = = FF_DFF ) {
// Try adding a set or reset pin.
for ( auto new_type : { FF_ADFF0 , FF_ADFF1 , FF_SDFF0 , FF_SDFF1 } )
if ( supported_cells [ new_type ] & initmask ) {
ff_type = new_type ;
sig_r = State : : S0 ;
goto cell_ok ;
}
// Try adding both.
if ( supported_cells [ FF_DFFSR ] & initmask ) {
ff_type = FF_DFFSR ;
sig_r = State : : S0 ;
sig_s = State : : S0 ;
break ;
}
// Nope. Will need to add enable and go the DFFE route.
sig_e = State : : S1 ;
if ( supported_cells [ FF_DFFE ] & initmask ) {
ff_type = FF_DFFE ;
break ;
}
}
// Try adding a set or reset pin.
for ( auto new_type : { FF_SDFFE0 , FF_SDFFE1 , FF_SDFFCE0 , FF_SDFFCE1 , FF_ADFFE0 , FF_ADFFE1 } )
if ( supported_cells [ new_type ] & initmask ) {
ff_type = new_type ;
sig_r = State : : S0 ;
goto cell_ok ;
}
// Try adding both.
if ( supported_cells [ FF_DFFSRE ] & initmask ) {
ff_type = FF_DFFSRE ;
sig_r = State : : S0 ;
sig_s = State : : S0 ;
break ;
}
// Seems that no DFFs with enable are supported.
// The enable input needs to be unmapped.
// This should not be reached if we started from plain DFF.
log_assert ( ff_type = = FF_DFFE ) ;
ff_type = FF_DFF ;
unmap_enable :
if ( ff_neg & NEG_E )
sig_d = cell - > module - > MuxGate ( NEW_ID , sig_d [ 0 ] , sig_q [ 0 ] , sig_e [ 0 ] ) ;
else
sig_d = cell - > module - > MuxGate ( NEW_ID , sig_q [ 0 ] , sig_d [ 0 ] , sig_e [ 0 ] ) ;
ff_neg & = ~ NEG_E ;
sig_e = SigSpec ( ) ;
kill_ce = false ;
// Now try again as plain DFF.
continue ;
} else if ( ff_type = = FF_ADFF0 | | ff_type = = FF_ADFF1 | | ff_type = = FF_ADFFE0 | | ff_type = = FF_ADFFE1 ) {
bool has_set = ff_type = = FF_ADFF1 | | ff_type = = FF_ADFFE1 ;
bool has_en = ff_type = = FF_ADFFE0 | | ff_type = = FF_ADFFE1 ;
if ( kill_ce ) {
ff_type = has_set ? FF_ADFF1 : FF_ADFF0 ;
goto unmap_enable ;
}
if ( ! has_en & & ( supported_cells [ has_set ? FF_ADFFE1 : FF_ADFFE0 ] & initmask ) ) {
// Just add enable.
sig_e = State : : S1 ;
ff_type = has_set ? FF_ADFFE1 : FF_ADFFE0 ;
break ;
}
if ( supported_dffsr & initmask ) {
// Throw in a set/reset, retry in DFFSR/DFFSRE branch.
if ( has_set ) {
sig_s = sig_r ;
sig_r = State : : S0 ;
if ( ff_neg & NEG_R ) {
ff_neg & = ~ NEG_R ;
ff_neg | = NEG_S ;
}
} else {
sig_s = State : : S0 ;
}
if ( has_en )
ff_type = FF_DFFSRE ;
else
ff_type = FF_DFFSR ;
continue ;
}
if ( has_en & & ( supported_cells [ has_set ? FF_ADFF1 : FF_ADFF0 ] & initmask ) ) {
// Unmap enable.
ff_type = has_set ? FF_ADFF1 : FF_ADFF0 ;
goto unmap_enable ;
}
log_assert ( ! ( ( has_set ? supported_adff1 : supported_adff0 ) & initmask ) ) ;
// Alright, so this particular combination of initval and
// resetval is not natively supported. First, try flipping
// them both to see whether this helps.
int flipmask = flip_initmask ( initmask ) ;
if ( ( has_set ? supported_adff0 : supported_adff1 ) & flipmask ) {
// Checks out, do it.
ff_type = has_en ? ( has_set ? FF_ADFFE0 : FF_ADFFE1 ) : ( has_set ? FF_ADFF0 : FF_ADFF1 ) ;
goto flip_dqi ;
}
if ( ! supported_adff0 & & ! supported_adff1 ) {
reason = " dffs with async set or reset are not supported " ;
goto error ;
}
if ( ! ( supported_dff & ~ INIT_X ) ) {
reason = " initialized dffs are not supported " ;
goto error ;
}
// If we got here, initialized dff is supported, but not this
// particular reset+init combination (nor its negation).
// The only hope left is breaking down to adff + dff + dlatch + mux.
if ( ! ( supported_dlatch & ~ INIT_X ) ) {
reason = " unsupported initial value and async reset value combination " ;
goto error ;
}
// If we have to unmap enable anyway, do it before breakdown.
if ( has_en & & ! supported_cells [ FF_ADFFE0 ] & & ! supported_cells [ FF_ADFFE1 ] ) {
ff_type = has_set ? FF_ADFF1 : FF_ADFF0 ;
goto unmap_enable ;
}
log_warning ( " Emulating mismatched async reset and init with several FFs and a mux for %s.%s \n " , log_id ( cell - > module - > name ) , log_id ( cell - > name ) ) ;
if ( initbit . wire )
initbit . wire - > attributes . at ( ID : : init ) [ initbit . offset ] = State : : Sx ;
Wire * adff_q = cell - > module - > addWire ( NEW_ID ) ;
Wire * dff_q = cell - > module - > addWire ( NEW_ID ) ;
Wire * sel_q = cell - > module - > addWire ( NEW_ID ) ;
dff_q - > attributes [ ID : : init ] = initval ;
initbits [ SigBit ( dff_q , 0 ) ] = std : : make_pair ( initval , SigBit ( dff_q , 0 ) ) ;
sel_q - > attributes [ ID : : init ] = State : : S0 ;
initbits [ SigBit ( sel_q , 0 ) ] = std : : make_pair ( State : : S0 , SigBit ( sel_q , 0 ) ) ;
Cell * cell_dff ;
Cell * cell_adff ;
Cell * cell_sel ;
if ( ! has_en ) {
cell_dff = cell - > module - > addDffGate ( NEW_ID , sig_c , sig_d , dff_q , ! ( ff_neg & NEG_C ) ) ;
cell_adff = cell - > module - > addAdffGate ( NEW_ID , sig_c , sig_r , sig_d , adff_q , has_set , ! ( ff_neg & NEG_C ) , ! ( ff_neg & NEG_R ) ) ;
} else {
cell_dff = cell - > module - > addDffeGate ( NEW_ID , sig_c , sig_e , sig_d , dff_q , ! ( ff_neg & NEG_C ) , ! ( ff_neg & NEG_E ) ) ;
cell_adff = cell - > module - > addAdffeGate ( NEW_ID , sig_c , sig_e , sig_r , sig_d , adff_q , has_set , ! ( ff_neg & NEG_C ) , ! ( ff_neg & NEG_E ) , ! ( ff_neg & NEG_R ) ) ;
}
cell_sel = cell - > module - > addDlatchGate ( NEW_ID , sig_r , State : : S1 , sel_q , ! ( ff_neg & NEG_R ) ) ;
cell - > module - > addMuxGate ( NEW_ID , dff_q , adff_q , sel_q , sig_q ) ;
// Bye, cell.
cell - > module - > remove ( cell ) ;
handle_ff ( cell_dff ) ;
handle_ff ( cell_adff ) ;
handle_ff ( cell_sel ) ;
return ;
} else if ( ff_type = = FF_DFFSR | | ff_type = = FF_DFFSRE ) {
if ( kill_ce ) {
ff_type = FF_DFFSR ;
goto unmap_enable ;
}
// First, see if mapping/unmapping enable will help.
if ( supported_cells [ FF_DFFSRE ] & initmask ) {
ff_type = FF_DFFSRE ;
sig_e = State : : S1 ;
break ;
}
if ( supported_cells [ FF_DFFSR ] & initmask ) {
ff_type = FF_DFFSR ;
goto unmap_enable ;
}
if ( supported_dffsr & flip_initmask ( initmask ) ) {
flip_dqisr : ;
log_warning ( " Flipping D/Q/init and inseerting set/reset fixup to handle init value on %s.%s [%s] \n " , log_id ( cell - > module - > name ) , log_id ( cell - > name ) , log_id ( cell - > type ) ) ;
SigSpec new_r ;
bool neg_r = ( ff_neg & NEG_R ) ;
bool neg_s = ( ff_neg & NEG_S ) ;
if ( ! ( ff_neg & NEG_S ) ) {
if ( ! ( ff_neg & NEG_R ) )
new_r = cell - > module - > AndnotGate ( NEW_ID , sig_s , sig_r ) ;
else
new_r = cell - > module - > AndGate ( NEW_ID , sig_s , sig_r ) ;
} else {
if ( ! ( ff_neg & NEG_R ) )
new_r = cell - > module - > OrGate ( NEW_ID , sig_s , sig_r ) ;
else
new_r = cell - > module - > OrnotGate ( NEW_ID , sig_s , sig_r ) ;
}
ff_neg & = ~ ( NEG_R | NEG_S ) ;
if ( neg_r )
ff_neg | = NEG_S ;
if ( neg_s )
ff_neg | = NEG_R ;
sig_s = sig_r ;
sig_r = new_r ;
goto flip_dqi ;
}
// No native DFFSR. However, if we can conjure
// a SR latch and ADFF, it can still be emulated.
int flipmask = flip_initmask ( initmask ) ;
bool init0 = true ;
bool init1 = true ;
State initsel = State : : Sx ;
if ( ( ( supported_adff0 & initmask ) | | ( supported_adff1 & flipmask ) ) & & ( ( supported_adff1 & initmask ) | | ( supported_adff0 & flipmask ) ) & & supported_sr ) {
// OK
} else if ( ( ( supported_adff0 & initmask ) | | ( supported_adff1 & flipmask ) ) & & ( supported_sr & INIT_0 ) ) {
init1 = false ;
initsel = State : : S0 ;
} else if ( ( ( supported_adff1 & initmask ) | | ( supported_adff0 & flipmask ) ) & & ( supported_sr & INIT_1 ) ) {
init0 = false ;
initsel = State : : S1 ;
} else if ( ( ( supported_adff0 & initmask ) | | ( supported_adff1 & flipmask ) ) & & ( supported_sr & INIT_1 ) ) {
init1 = false ;
initsel = State : : S0 ;
} else if ( ( ( supported_adff1 & initmask ) | | ( supported_adff0 & flipmask ) ) & & ( supported_sr & INIT_0 ) ) {
init0 = false ;
initsel = State : : S1 ;
} else {
if ( ! supported_dffsr )
reason = " dffs with async set and reset are not supported " ;
else
reason = " initialized dffs with async set and reset are not supported " ;
goto error ;
}
// If we have to unmap enable anyway, do it before breakdown.
if ( ff_type = = FF_DFFSRE & & ! supported_cells [ FF_ADFFE0 ] & & ! supported_cells [ FF_ADFFE1 ] ) {
ff_type = FF_DFFSR ;
goto unmap_enable ;
}
log_warning ( " Emulating async set + reset with several FFs and a mux for %s.%s \n " , log_id ( cell - > module - > name ) , log_id ( cell - > name ) ) ;
if ( initbit . wire )
initbit . wire - > attributes . at ( ID : : init ) [ initbit . offset ] = State : : Sx ;
Wire * adff0_q = cell - > module - > addWire ( NEW_ID ) ;
Wire * adff1_q = cell - > module - > addWire ( NEW_ID ) ;
Wire * sel_q = cell - > module - > addWire ( NEW_ID ) ;
if ( init0 ) {
adff0_q - > attributes [ ID : : init ] = initval ;
initbits [ SigBit ( adff0_q , 0 ) ] = std : : make_pair ( initval , SigBit ( adff0_q , 0 ) ) ;
}
if ( init1 ) {
adff1_q - > attributes [ ID : : init ] = initval ;
initbits [ SigBit ( adff1_q , 0 ) ] = std : : make_pair ( initval , SigBit ( adff1_q , 0 ) ) ;
}
sel_q - > attributes [ ID : : init ] = initsel ;
initbits [ SigBit ( sel_q , 0 ) ] = std : : make_pair ( initsel , SigBit ( sel_q , 0 ) ) ;
Cell * cell_adff0 ;
Cell * cell_adff1 ;
Cell * cell_sel ;
if ( ff_type = = FF_DFFSR ) {
cell_adff0 = cell - > module - > addAdffGate ( NEW_ID , sig_c , sig_r , sig_d , adff0_q , false , ! ( ff_neg & NEG_C ) , ! ( ff_neg & NEG_R ) ) ;
cell_adff1 = cell - > module - > addAdffGate ( NEW_ID , sig_c , sig_s , sig_d , adff1_q , true , ! ( ff_neg & NEG_C ) , ! ( ff_neg & NEG_S ) ) ;
} else {
cell_adff0 = cell - > module - > addAdffeGate ( NEW_ID , sig_c , sig_e , sig_r , sig_d , adff0_q , false , ! ( ff_neg & NEG_C ) , ! ( ff_neg & NEG_E ) , ! ( ff_neg & NEG_R ) ) ;
cell_adff1 = cell - > module - > addAdffeGate ( NEW_ID , sig_c , sig_e , sig_s , sig_d , adff1_q , true , ! ( ff_neg & NEG_C ) , ! ( ff_neg & NEG_E ) , ! ( ff_neg & NEG_S ) ) ;
}
cell_sel = cell - > module - > addSrGate ( NEW_ID , sig_s , sig_r , sel_q , ! ( ff_neg & NEG_S ) , ! ( ff_neg & NEG_R ) ) ;
cell - > module - > addMuxGate ( NEW_ID , adff0_q , adff1_q , sel_q , sig_q ) ;
// Bye, cell.
cell - > module - > remove ( cell ) ;
handle_ff ( cell_adff0 ) ;
handle_ff ( cell_adff1 ) ;
handle_ff ( cell_sel ) ;
return ;
} else if ( ff_type = = FF_SR ) {
if ( supported_cells [ FF_ADLATCH0 ] & initmask | | supported_cells [ FF_ADLATCH1 ] & flip_initmask ( initmask ) ) {
// Convert to ADLATCH0. May get converted to ADLATCH1.
ff_type = FF_ADLATCH0 ;
sig_e = sig_s ;
sig_d = State : : S1 ;
if ( ff_neg & NEG_S ) {
ff_neg & = ~ NEG_S ;
ff_neg | = NEG_E ;
}
continue ;
} else if ( supported_cells [ FF_DLATCHSR ] & initmask ) {
// Upgrade to DLATCHSR.
ff_type = FF_DLATCHSR ;
sig_e = State : : S0 ;
sig_d = State : : Sx ;
break ;
} else if ( supported_dffsr & initmask ) {
// Upgrade to DFFSR. May get further upgraded to DFFSRE.
ff_type = FF_DFFSR ;
sig_c = State : : S0 ;
sig_d = State : : Sx ;
continue ;
} else if ( supported_sr & flip_initmask ( initmask ) ) {
goto flip_dqisr ;
} else {
if ( ! supported_sr )
reason = " sr latches are not supported " ;
else
reason = " initialized sr latches are not supported " ;
goto error ;
}
} else if ( ff_type = = FF_DLATCH ) {
if ( ! ( supported_dlatch & initmask ) ) {
// This init value is not supported at all...
if ( supported_dlatch & flip_initmask ( initmask ) )
goto flip_dqi ;
if ( ! supported_dlatch )
reason = " dlatch are not supported " ;
else
reason = " initialized dlatch are not supported " ;
goto error ;
}
// Some DLATCH is supported with this init val. Just pick a type.
if ( supported_cells [ FF_ADLATCH0 ] & initmask ) {
ff_type = FF_ADLATCH0 ;
sig_r = State : : S0 ;
break ;
}
if ( supported_cells [ FF_ADLATCH1 ] & initmask ) {
ff_type = FF_ADLATCH1 ;
sig_r = State : : S0 ;
break ;
}
if ( supported_cells [ FF_DLATCHSR ] & initmask ) {
ff_type = FF_DLATCHSR ;
sig_r = State : : S0 ;
sig_s = State : : S0 ;
break ;
}
log_assert ( 0 ) ;
} else if ( ff_type = = FF_ADLATCH0 | | ff_type = = FF_ADLATCH1 ) {
if ( supported_cells [ FF_DLATCHSR ] & initmask ) {
if ( ff_type = = FF_ADLATCH1 ) {
sig_s = sig_r ;
sig_r = State : : S0 ;
if ( ff_neg & NEG_R ) {
ff_neg & = ~ NEG_R ;
ff_neg | = NEG_S ;
}
} else {
sig_s = State : : S0 ;
}
ff_type = FF_DLATCHSR ;
break ;
}
FfType flip_type = ff_type = = FF_ADLATCH0 ? FF_ADLATCH1 : FF_ADLATCH0 ;
if ( ( supported_cells [ flip_type ] | supported_cells [ FF_DLATCHSR ] ) & flip_initmask ( initmask ) ) {
ff_type = flip_type ;
goto flip_dqi ;
}
if ( ! supported_cells [ FF_ADLATCH0 ] & & ! supported_cells [ FF_ADLATCH1 ] & & ! supported_cells [ FF_DLATCHSR ] ) {
reason = " dlatch with async set or reset are not supported " ;
goto error ;
}
if ( ! ( supported_dlatch & ~ INIT_X ) ) {
reason = " initialized dlatch are not supported " ;
goto error ;
}
if ( ! ( supported_dlatch & ~ INIT_X ) ) {
reason = " initialized dlatch are not supported " ;
goto error ;
}
// If we got here, initialized dlatch is supported, but not this
// particular reset+init combination (nor its negation).
// The only hope left is breaking down to adff + dff + dlatch + mux.
log_warning ( " Emulating mismatched async reset and init with several latches and a mux for %s.%s \n " , log_id ( cell - > module - > name ) , log_id ( cell - > name ) ) ;
if ( initbit . wire )
initbit . wire - > attributes . at ( ID : : init ) [ initbit . offset ] = State : : Sx ;
Wire * adlatch_q = cell - > module - > addWire ( NEW_ID ) ;
Wire * dlatch_q = cell - > module - > addWire ( NEW_ID ) ;
Wire * sel_q = cell - > module - > addWire ( NEW_ID ) ;
dlatch_q - > attributes [ ID : : init ] = initval ;
initbits [ SigBit ( dlatch_q , 0 ) ] = std : : make_pair ( initval , SigBit ( dlatch_q , 0 ) ) ;
sel_q - > attributes [ ID : : init ] = State : : S0 ;
initbits [ SigBit ( sel_q , 0 ) ] = std : : make_pair ( State : : S0 , SigBit ( sel_q , 0 ) ) ;
Cell * cell_dlatch ;
Cell * cell_adlatch ;
Cell * cell_sel ;
cell_dlatch = cell - > module - > addDlatchGate ( NEW_ID , sig_e , sig_d , dlatch_q , ! ( ff_neg & NEG_E ) ) ;
cell_adlatch = cell - > module - > addAdlatchGate ( NEW_ID , sig_e , sig_r , sig_d , adlatch_q , ff_type = = FF_ADLATCH1 , ! ( ff_neg & NEG_E ) , ! ( ff_neg & NEG_R ) ) ;
cell_sel = cell - > module - > addDlatchGate ( NEW_ID , sig_r , State : : S1 , sel_q , ! ( ff_neg & NEG_R ) ) ;
cell - > module - > addMuxGate ( NEW_ID , dlatch_q , adlatch_q , sel_q , sig_q ) ;
// Bye, cell.
cell - > module - > remove ( cell ) ;
handle_ff ( cell_dlatch ) ;
handle_ff ( cell_adlatch ) ;
handle_ff ( cell_sel ) ;
return ;
} else if ( ff_type = = FF_DLATCHSR ) {
if ( supported_cells [ FF_DLATCHSR ] & flip_initmask ( initmask ) ) {
goto flip_dqisr ;
}
// No native DFFSR. However, if we can conjure
// a SR latch and ADFF, it can still be emulated.
int flipmask = flip_initmask ( initmask ) ;
bool init0 = true ;
bool init1 = true ;
State initsel = State : : Sx ;
if ( ( ( supported_cells [ FF_ADLATCH0 ] & initmask ) | | ( supported_cells [ FF_ADLATCH1 ] & flipmask ) ) & & ( ( supported_cells [ FF_ADLATCH1 ] & initmask ) | | ( supported_cells [ FF_ADLATCH0 ] & flipmask ) ) & & supported_sr ) {
// OK
} else if ( ( ( supported_cells [ FF_ADLATCH0 ] & initmask ) | | ( supported_cells [ FF_ADLATCH1 ] & flipmask ) ) & & ( supported_sr & INIT_0 ) ) {
init1 = false ;
initsel = State : : S0 ;
} else if ( ( ( supported_cells [ FF_ADLATCH1 ] & initmask ) | | ( supported_cells [ FF_ADLATCH0 ] & flipmask ) ) & & ( supported_sr & INIT_1 ) ) {
init0 = false ;
initsel = State : : S1 ;
} else if ( ( ( supported_cells [ FF_ADLATCH0 ] & initmask ) | | ( supported_cells [ FF_ADLATCH1 ] & flipmask ) ) & & ( supported_sr & INIT_1 ) ) {
init1 = false ;
initsel = State : : S0 ;
} else if ( ( ( supported_cells [ FF_ADLATCH1 ] & initmask ) | | ( supported_cells [ FF_ADLATCH0 ] & flipmask ) ) & & ( supported_sr & INIT_0 ) ) {
init0 = false ;
initsel = State : : S1 ;
} else {
if ( ! supported_cells [ FF_DLATCHSR ] )
reason = " dlatch with async set and reset are not supported " ;
else
reason = " initialized dlatch with async set and reset are not supported " ;
goto error ;
}
log_warning ( " Emulating async set + reset with several latches and a mux for %s.%s \n " , log_id ( cell - > module - > name ) , log_id ( cell - > name ) ) ;
if ( initbit . wire )
initbit . wire - > attributes . at ( ID : : init ) [ initbit . offset ] = State : : Sx ;
Wire * adlatch0_q = cell - > module - > addWire ( NEW_ID ) ;
Wire * adlatch1_q = cell - > module - > addWire ( NEW_ID ) ;
Wire * sel_q = cell - > module - > addWire ( NEW_ID ) ;
if ( init0 ) {
adlatch0_q - > attributes [ ID : : init ] = initval ;
initbits [ SigBit ( adlatch0_q , 0 ) ] = std : : make_pair ( initval , SigBit ( adlatch0_q , 0 ) ) ;
}
if ( init1 ) {
adlatch1_q - > attributes [ ID : : init ] = initval ;
initbits [ SigBit ( adlatch1_q , 0 ) ] = std : : make_pair ( initval , SigBit ( adlatch1_q , 0 ) ) ;
}
sel_q - > attributes [ ID : : init ] = initsel ;
initbits [ SigBit ( sel_q , 0 ) ] = std : : make_pair ( initsel , SigBit ( sel_q , 0 ) ) ;
Cell * cell_adlatch0 ;
Cell * cell_adlatch1 ;
Cell * cell_sel ;
cell_adlatch0 = cell - > module - > addAdlatchGate ( NEW_ID , sig_e , sig_r , sig_d , adlatch0_q , false , ! ( ff_neg & NEG_E ) , ! ( ff_neg & NEG_R ) ) ;
cell_adlatch1 = cell - > module - > addAdlatchGate ( NEW_ID , sig_e , sig_s , sig_d , adlatch1_q , true , ! ( ff_neg & NEG_E ) , ! ( ff_neg & NEG_S ) ) ;
cell_sel = cell - > module - > addSrGate ( NEW_ID , sig_s , sig_r , sel_q , ! ( ff_neg & NEG_S ) , ! ( ff_neg & NEG_R ) ) ;
cell - > module - > addMuxGate ( NEW_ID , adlatch0_q , adlatch1_q , sel_q , sig_q ) ;
// Bye, cell.
cell - > module - > remove ( cell ) ;
handle_ff ( cell_adlatch0 ) ;
handle_ff ( cell_adlatch1 ) ;
handle_ff ( cell_sel ) ;
return ;
} else if ( ff_type = = FF_SDFF0 | | ff_type = = FF_SDFF1 | | ff_type = = FF_SDFFE0 | | ff_type = = FF_SDFFE1 | | ff_type = = FF_SDFFCE0 | | ff_type = = FF_SDFFCE1 ) {
bool has_set = ff_type = = FF_SDFF1 | | ff_type = = FF_SDFFE1 | | ff_type = = FF_SDFFCE1 ;
bool has_en = ff_type = = FF_SDFFE0 | | ff_type = = FF_SDFFE1 ;
bool has_ce = ff_type = = FF_SDFFCE0 | | ff_type = = FF_SDFFCE1 ;
if ( has_en ) {
if ( kill_ce | | kill_srst ) {
ff_type = has_set ? FF_SDFF1 : FF_SDFF0 ;
goto unmap_enable ;
}
} else if ( has_ce ) {
if ( kill_ce | | kill_srst )
goto unmap_srst ;
} else {
log_assert ( ! kill_ce ) ;
if ( kill_srst )
goto unmap_srst ;
}
if ( ! has_ce ) {
if ( ! has_en & & ( supported_cells [ has_set ? FF_SDFFE1 : FF_SDFFE0 ] & initmask ) ) {
// Just add enable.
sig_e = State : : S1 ;
ff_type = has_set ? FF_SDFFE1 : FF_SDFFE0 ;
break ;
}
if ( ! has_en & & ( supported_cells [ has_set ? FF_SDFFCE1 : FF_SDFFCE0 ] & initmask ) ) {
// Just add enable.
sig_e = State : : S1 ;
ff_type = has_set ? FF_SDFFCE1 : FF_SDFFCE0 ;
break ;
}
if ( has_en & & ( supported_cells [ has_set ? FF_SDFFCE1 : FF_SDFFCE0 ] & initmask ) ) {
// Convert sdffe to sdffce
if ( ! ( ff_neg & NEG_E ) ) {
if ( ! ( ff_neg & NEG_R ) )
sig_e = cell - > module - > OrGate ( NEW_ID , sig_e , sig_r ) ;
else
sig_e = cell - > module - > OrnotGate ( NEW_ID , sig_e , sig_r ) ;
} else {
if ( ! ( ff_neg & NEG_R ) )
sig_e = cell - > module - > AndnotGate ( NEW_ID , sig_e , sig_r ) ;
else
sig_e = cell - > module - > AndGate ( NEW_ID , sig_e , sig_r ) ;
}
ff_type = has_set ? FF_SDFFCE1 : FF_SDFFCE0 ;
break ;
}
if ( has_en & & ( supported_cells [ has_set ? FF_SDFF1 : FF_SDFF0 ] & initmask ) ) {
// Unmap enable.
ff_type = has_set ? FF_SDFF1 : FF_SDFF0 ;
goto unmap_enable ;
}
log_assert ( ! ( ( has_set ? supported_sdff1 : supported_sdff0 ) & initmask ) ) ;
} else {
if ( ( has_set ? supported_sdff1 : supported_sdff0 ) & initmask ) {
// Convert sdffce to sdffe, which may be further converted to sdff.
if ( ! ( ff_neg & NEG_R ) ) {
if ( ! ( ff_neg & NEG_E ) )
sig_r = cell - > module - > AndGate ( NEW_ID , sig_r , sig_e ) ;
else
sig_r = cell - > module - > AndnotGate ( NEW_ID , sig_r , sig_e ) ;
} else {
if ( ! ( ff_neg & NEG_E ) )
sig_r = cell - > module - > OrnotGate ( NEW_ID , sig_r , sig_e ) ;
else
sig_r = cell - > module - > OrGate ( NEW_ID , sig_r , sig_e ) ;
}
ff_type = has_set ? FF_SDFFE1 : FF_SDFFE0 ;
continue ;
}
}
// Alright, so this particular combination of initval and
// resetval is not natively supported. First, try flipping
// them both to see whether this helps.
if ( ( has_set ? supported_sdff0 : supported_sdff1 ) & flip_initmask ( initmask ) ) {
// Checks out, do it.
ff_type = has_ce ? ( has_set ? FF_SDFFCE0 : FF_SDFFCE1 ) : has_en ? ( has_set ? FF_SDFFE0 : FF_SDFFE1 ) : ( has_set ? FF_SDFF0 : FF_SDFF1 ) ;
goto flip_dqi ;
}
// Nope. No way to get SDFF* of the right kind, so unmap it.
// For SDFFE, the enable has to be unmapped first.
if ( has_en ) {
ff_type = has_set ? FF_SDFF1 : FF_SDFF0 ;
goto unmap_enable ;
}
unmap_srst :
if ( has_ce )
ff_type = FF_DFFE ;
else
ff_type = FF_DFF ;
if ( ff_neg & NEG_R )
sig_d = cell - > module - > MuxGate ( NEW_ID , has_set ? State : : S1 : State : : S0 , sig_d [ 0 ] , sig_r [ 0 ] ) ;
else
sig_d = cell - > module - > MuxGate ( NEW_ID , sig_d [ 0 ] , has_set ? State : : S1 : State : : S0 , sig_r [ 0 ] ) ;
ff_neg & = ~ NEG_R ;
sig_r = SigSpec ( ) ;
kill_srst = false ;
continue ;
} else {
log_assert ( 0 ) ;
}
}
cell_ok :
if ( ! ( supported_cells_neg [ ff_type ] [ ff_neg ] & initmask ) ) {
// Cell is supported, but not with those polarities.
// Will need to add some inverters.
// Find the smallest value that xored with the neg mask
// results in a supported one — this results in preferentially
// inverting resets before clocks, etc.
int xneg ;
for ( xneg = 0 ; xneg < NUM_NEG ; xneg + + )
if ( supported_cells_neg [ ff_type ] [ ff_neg ^ xneg ] & initmask )
break ;
log_assert ( xneg < NUM_NEG ) ;
if ( xneg & NEG_R )
sig_r = cell - > module - > NotGate ( NEW_ID , sig_r [ 0 ] ) ;
if ( xneg & NEG_S )
sig_s = cell - > module - > NotGate ( NEW_ID , sig_s [ 0 ] ) ;
if ( xneg & NEG_E )
sig_e = cell - > module - > NotGate ( NEW_ID , sig_e [ 0 ] ) ;
if ( xneg & NEG_C )
sig_c = cell - > module - > NotGate ( NEW_ID , sig_c [ 0 ] ) ;
ff_neg ^ = xneg ;
}
cell - > unsetPort ( ID : : D ) ;
cell - > unsetPort ( ID : : Q ) ;
cell - > unsetPort ( ID : : C ) ;
cell - > unsetPort ( ID : : E ) ;
cell - > unsetPort ( ID : : S ) ;
cell - > unsetPort ( ID : : R ) ;
switch ( ff_type ) {
case FF_DFF :
cell - > type = IdString ( stringf ( " $_DFF_%c_ " ,
( ff_neg & NEG_C ) ? ' N ' : ' P '
) ) ;
cell - > setPort ( ID : : D , sig_d ) ;
cell - > setPort ( ID : : Q , sig_q ) ;
cell - > setPort ( ID : : C , sig_c ) ;
break ;
case FF_DFFE :
cell - > type = IdString ( stringf ( " $_DFFE_%c%c_ " ,
( ff_neg & NEG_C ) ? ' N ' : ' P ' ,
( ff_neg & NEG_E ) ? ' N ' : ' P '
) ) ;
cell - > setPort ( ID : : D , sig_d ) ;
cell - > setPort ( ID : : Q , sig_q ) ;
cell - > setPort ( ID : : C , sig_c ) ;
cell - > setPort ( ID : : E , sig_e ) ;
break ;
case FF_ADFF0 :
case FF_ADFF1 :
cell - > type = IdString ( stringf ( " $_DFF_%c%c%c_ " ,
( ff_neg & NEG_C ) ? ' N ' : ' P ' ,
( ff_neg & NEG_R ) ? ' N ' : ' P ' ,
( ff_type = = FF_ADFF1 ) ? ' 1 ' : ' 0 '
) ) ;
cell - > setPort ( ID : : D , sig_d ) ;
cell - > setPort ( ID : : Q , sig_q ) ;
cell - > setPort ( ID : : C , sig_c ) ;
cell - > setPort ( ID : : R , sig_r ) ;
break ;
case FF_ADFFE0 :
case FF_ADFFE1 :
cell - > type = IdString ( stringf ( " $_DFFE_%c%c%c%c_ " ,
( ff_neg & NEG_C ) ? ' N ' : ' P ' ,
( ff_neg & NEG_R ) ? ' N ' : ' P ' ,
( ff_type = = FF_ADFFE1 ) ? ' 1 ' : ' 0 ' ,
( ff_neg & NEG_E ) ? ' N ' : ' P '
) ) ;
cell - > setPort ( ID : : D , sig_d ) ;
cell - > setPort ( ID : : Q , sig_q ) ;
cell - > setPort ( ID : : C , sig_c ) ;
cell - > setPort ( ID : : E , sig_e ) ;
cell - > setPort ( ID : : R , sig_r ) ;
break ;
case FF_DFFSR :
cell - > type = IdString ( stringf ( " $_DFFSR_%c%c%c_ " ,
( ff_neg & NEG_C ) ? ' N ' : ' P ' ,
( ff_neg & NEG_S ) ? ' N ' : ' P ' ,
( ff_neg & NEG_R ) ? ' N ' : ' P '
) ) ;
cell - > setPort ( ID : : D , sig_d ) ;
cell - > setPort ( ID : : Q , sig_q ) ;
cell - > setPort ( ID : : C , sig_c ) ;
cell - > setPort ( ID : : S , sig_s ) ;
cell - > setPort ( ID : : R , sig_r ) ;
break ;
case FF_DFFSRE :
cell - > type = IdString ( stringf ( " $_DFFSRE_%c%c%c%c_ " ,
( ff_neg & NEG_C ) ? ' N ' : ' P ' ,
( ff_neg & NEG_S ) ? ' N ' : ' P ' ,
( ff_neg & NEG_R ) ? ' N ' : ' P ' ,
( ff_neg & NEG_E ) ? ' N ' : ' P '
) ) ;
cell - > setPort ( ID : : D , sig_d ) ;
cell - > setPort ( ID : : Q , sig_q ) ;
cell - > setPort ( ID : : C , sig_c ) ;
cell - > setPort ( ID : : E , sig_e ) ;
cell - > setPort ( ID : : S , sig_s ) ;
cell - > setPort ( ID : : R , sig_r ) ;
break ;
case FF_SDFF0 :
case FF_SDFF1 :
cell - > type = IdString ( stringf ( " $_SDFF_%c%c%c_ " ,
( ff_neg & NEG_C ) ? ' N ' : ' P ' ,
( ff_neg & NEG_R ) ? ' N ' : ' P ' ,
( ff_type = = FF_SDFF1 ) ? ' 1 ' : ' 0 '
) ) ;
cell - > setPort ( ID : : D , sig_d ) ;
cell - > setPort ( ID : : Q , sig_q ) ;
cell - > setPort ( ID : : C , sig_c ) ;
cell - > setPort ( ID : : R , sig_r ) ;
break ;
case FF_SDFFE0 :
case FF_SDFFE1 :
cell - > type = IdString ( stringf ( " $_SDFFE_%c%c%c%c_ " ,
( ff_neg & NEG_C ) ? ' N ' : ' P ' ,
( ff_neg & NEG_R ) ? ' N ' : ' P ' ,
( ff_type = = FF_SDFFE1 ) ? ' 1 ' : ' 0 ' ,
( ff_neg & NEG_E ) ? ' N ' : ' P '
) ) ;
cell - > setPort ( ID : : D , sig_d ) ;
cell - > setPort ( ID : : Q , sig_q ) ;
cell - > setPort ( ID : : C , sig_c ) ;
cell - > setPort ( ID : : E , sig_e ) ;
cell - > setPort ( ID : : R , sig_r ) ;
break ;
case FF_SDFFCE0 :
case FF_SDFFCE1 :
cell - > type = IdString ( stringf ( " $_SDFFCE_%c%c%c%c_ " ,
( ff_neg & NEG_C ) ? ' N ' : ' P ' ,
( ff_neg & NEG_R ) ? ' N ' : ' P ' ,
( ff_type = = FF_SDFFCE1 ) ? ' 1 ' : ' 0 ' ,
( ff_neg & NEG_E ) ? ' N ' : ' P '
) ) ;
cell - > setPort ( ID : : D , sig_d ) ;
cell - > setPort ( ID : : Q , sig_q ) ;
cell - > setPort ( ID : : C , sig_c ) ;
cell - > setPort ( ID : : E , sig_e ) ;
cell - > setPort ( ID : : R , sig_r ) ;
break ;
case FF_DLATCH :
cell - > type = IdString ( stringf ( " $_DLATCH_%c_ " ,
( ff_neg & NEG_E ) ? ' N ' : ' P '
) ) ;
cell - > setPort ( ID : : D , sig_d ) ;
cell - > setPort ( ID : : Q , sig_q ) ;
cell - > setPort ( ID : : E , sig_e ) ;
break ;
case FF_ADLATCH0 :
case FF_ADLATCH1 :
cell - > type = IdString ( stringf ( " $_DLATCH_%c%c%c_ " ,
( ff_neg & NEG_E ) ? ' N ' : ' P ' ,
( ff_neg & NEG_R ) ? ' N ' : ' P ' ,
( ff_type = = FF_ADLATCH1 ) ? ' 1 ' : ' 0 '
) ) ;
cell - > setPort ( ID : : D , sig_d ) ;
cell - > setPort ( ID : : Q , sig_q ) ;
cell - > setPort ( ID : : E , sig_e ) ;
cell - > setPort ( ID : : R , sig_r ) ;
break ;
case FF_DLATCHSR :
cell - > type = IdString ( stringf ( " $_DLATCHSR_%c%c%c_ " ,
( ff_neg & NEG_E ) ? ' N ' : ' P ' ,
( ff_neg & NEG_S ) ? ' N ' : ' P ' ,
( ff_neg & NEG_R ) ? ' N ' : ' P '
) ) ;
cell - > setPort ( ID : : D , sig_d ) ;
cell - > setPort ( ID : : Q , sig_q ) ;
cell - > setPort ( ID : : E , sig_e ) ;
cell - > setPort ( ID : : S , sig_s ) ;
cell - > setPort ( ID : : R , sig_r ) ;
break ;
case FF_SR :
cell - > type = IdString ( stringf ( " $_SR_%c%c_ " ,
( ff_neg & NEG_S ) ? ' N ' : ' P ' ,
( ff_neg & NEG_R ) ? ' N ' : ' P '
) ) ;
cell - > setPort ( ID : : Q , sig_q ) ;
cell - > setPort ( ID : : S , sig_s ) ;
cell - > setPort ( ID : : R , sig_r ) ;
break ;
default :
log_assert ( 0 ) ;
}
return ;
error :
log_error ( " FF %s.%s (type %s) cannot be legalized: %s \n " , log_id ( cell - > module - > name ) , log_id ( cell - > name ) , log_id ( cell - > type ) , reason ) ;
}
void execute ( std : : vector < std : : string > args , RTLIL : : Design * design ) override
{
log_header ( design , " Executing DFFLEGALIZE pass (convert FFs to types supported by the target). \n " ) ;
for ( int i = 0 ; i < NUM_FFTYPES ; i + + ) {
for ( int j = 0 ; j < NUM_NEG ; j + + )
supported_cells_neg [ i ] [ j ] = 0 ;
supported_cells [ i ] = 0 ;
}
mince = 0 ;
minsrst = 0 ;
size_t argidx ;
for ( argidx = 1 ; argidx < args . size ( ) ; argidx + + )
{
if ( args [ argidx ] = = " -cell " & & argidx + 2 < args . size ( ) ) {
std : : string celltype = args [ + + argidx ] ;
std : : string inittype = args [ + + argidx ] ;
enum FfType ff_type [ 2 ] = { NUM_FFTYPES , NUM_FFTYPES } ;
char pol_c = 0 ;
char pol_e = 0 ;
char pol_s = 0 ;
char pol_r = 0 ;
char srval = 0 ;
if ( celltype . substr ( 0 , 5 ) = = " $_SR_ " & & celltype . size ( ) = = 8 & & celltype [ 7 ] = = ' _ ' ) {
ff_type [ 0 ] = FF_SR ;
pol_s = celltype [ 5 ] ;
pol_r = celltype [ 6 ] ;
} else if ( celltype . substr ( 0 , 6 ) = = " $_DFF_ " & & celltype . size ( ) = = 8 & & celltype [ 7 ] = = ' _ ' ) {
ff_type [ 0 ] = FF_DFF ;
pol_c = celltype [ 6 ] ;
} else if ( celltype . substr ( 0 , 7 ) = = " $_DFFE_ " & & celltype . size ( ) = = 10 & & celltype [ 9 ] = = ' _ ' ) {
ff_type [ 0 ] = FF_DFFE ;
pol_c = celltype [ 7 ] ;
pol_e = celltype [ 8 ] ;
} else if ( celltype . substr ( 0 , 6 ) = = " $_DFF_ " & & celltype . size ( ) = = 10 & & celltype [ 9 ] = = ' _ ' ) {
ff_type [ 0 ] = FF_ADFF0 ;
ff_type [ 1 ] = FF_ADFF1 ;
pol_c = celltype [ 6 ] ;
pol_r = celltype [ 7 ] ;
srval = celltype [ 8 ] ;
} else if ( celltype . substr ( 0 , 7 ) = = " $_DFFE_ " & & celltype . size ( ) = = 12 & & celltype [ 11 ] = = ' _ ' ) {
ff_type [ 0 ] = FF_ADFFE0 ;
ff_type [ 1 ] = FF_ADFFE1 ;
pol_c = celltype [ 7 ] ;
pol_r = celltype [ 8 ] ;
srval = celltype [ 9 ] ;
pol_e = celltype [ 10 ] ;
} else if ( celltype . substr ( 0 , 8 ) = = " $_DFFSR_ " & & celltype . size ( ) = = 12 & & celltype [ 11 ] = = ' _ ' ) {
ff_type [ 0 ] = FF_DFFSR ;
pol_c = celltype [ 8 ] ;
pol_s = celltype [ 9 ] ;
pol_r = celltype [ 10 ] ;
} else if ( celltype . substr ( 0 , 9 ) = = " $_DFFSRE_ " & & celltype . size ( ) = = 14 & & celltype [ 13 ] = = ' _ ' ) {
ff_type [ 0 ] = FF_DFFSRE ;
pol_c = celltype [ 9 ] ;
pol_s = celltype [ 10 ] ;
pol_r = celltype [ 11 ] ;
pol_e = celltype [ 12 ] ;
} else if ( celltype . substr ( 0 , 7 ) = = " $_SDFF_ " & & celltype . size ( ) = = 11 & & celltype [ 10 ] = = ' _ ' ) {
ff_type [ 0 ] = FF_SDFF0 ;
ff_type [ 1 ] = FF_SDFF1 ;
pol_c = celltype [ 7 ] ;
pol_r = celltype [ 8 ] ;
srval = celltype [ 9 ] ;
} else if ( celltype . substr ( 0 , 8 ) = = " $_SDFFE_ " & & celltype . size ( ) = = 13 & & celltype [ 12 ] = = ' _ ' ) {
ff_type [ 0 ] = FF_SDFFE0 ;
ff_type [ 1 ] = FF_SDFFE1 ;
pol_c = celltype [ 8 ] ;
pol_r = celltype [ 9 ] ;
srval = celltype [ 10 ] ;
pol_e = celltype [ 11 ] ;
} else if ( celltype . substr ( 0 , 9 ) = = " $_SDFFCE_ " & & celltype . size ( ) = = 14 & & celltype [ 13 ] = = ' _ ' ) {
ff_type [ 0 ] = FF_SDFFCE0 ;
ff_type [ 1 ] = FF_SDFFCE1 ;
pol_c = celltype [ 9 ] ;
pol_r = celltype [ 10 ] ;
srval = celltype [ 11 ] ;
pol_e = celltype [ 12 ] ;
} else if ( celltype . substr ( 0 , 9 ) = = " $_DLATCH_ " & & celltype . size ( ) = = 11 & & celltype [ 10 ] = = ' _ ' ) {
ff_type [ 0 ] = FF_DLATCH ;
pol_e = celltype [ 9 ] ;
} else if ( celltype . substr ( 0 , 9 ) = = " $_DLATCH_ " & & celltype . size ( ) = = 13 & & celltype [ 12 ] = = ' _ ' ) {
ff_type [ 0 ] = FF_ADLATCH0 ;
ff_type [ 1 ] = FF_ADLATCH1 ;
pol_e = celltype [ 9 ] ;
pol_r = celltype [ 10 ] ;
srval = celltype [ 11 ] ;
} else if ( celltype . substr ( 0 , 11 ) = = " $_DLATCHSR_ " & & celltype . size ( ) = = 15 & & celltype [ 14 ] = = ' _ ' ) {
ff_type [ 0 ] = FF_DLATCHSR ;
pol_e = celltype [ 11 ] ;
pol_s = celltype [ 12 ] ;
pol_r = celltype [ 13 ] ;
} else {
unrecognized :
log_error ( " unrecognized cell type %s. \n " , celltype . c_str ( ) ) ;
}
int mask = 0 ;
int match = 0 ;
for ( auto pair : {
std : : make_pair ( pol_c , NEG_C ) ,
std : : make_pair ( pol_e , NEG_E ) ,
std : : make_pair ( pol_s , NEG_S ) ,
std : : make_pair ( pol_r , NEG_R ) ,
} ) {
if ( pair . first = = ' N ' ) {
mask | = pair . second ;
match | = pair . second ;
} else if ( pair . first = = ' P ' | | pair . first = = 0 ) {
mask | = pair . second ;
} else if ( pair . first ! = ' ? ' ) {
goto unrecognized ;
}
}
if ( srval = = ' 0 ' ) {
ff_type [ 1 ] = NUM_FFTYPES ;
} else if ( srval = = ' 1 ' ) {
ff_type [ 0 ] = NUM_FFTYPES ;
} else if ( srval ! = 0 & & srval ! = ' ? ' ) {
goto unrecognized ;
}
for ( int i = 0 ; i < 2 ; i + + ) {
if ( ff_type [ i ] = = NUM_FFTYPES )
continue ;
int initmask ;
if ( inittype = = " x " ) {
initmask = INIT_X ;
} else if ( inittype = = " 0 " ) {
initmask = INIT_X | INIT_0 ;
} else if ( inittype = = " 1 " ) {
initmask = INIT_X | INIT_1 ;
} else if ( inittype = = " r " ) {
if ( srval = = 0 )
log_error ( " init type r not valid for cell type %s. \n " , celltype . c_str ( ) ) ;
if ( i = = 0 )
initmask = INIT_X | INIT_0 ;
else
initmask = INIT_X | INIT_1 ;
} else if ( inittype = = " 01 " ) {
initmask = INIT_X | INIT_0 | INIT_1 ;
} else {
log_error ( " unrecognized init type %s for cell type %s. \n " , inittype . c_str ( ) , celltype . c_str ( ) ) ;
}
for ( int neg = 0 ; neg < NUM_NEG ; neg + + )
if ( ( neg & mask ) = = match )
supported_cells_neg [ ff_type [ i ] ] [ neg ] | = initmask ;
supported_cells [ ff_type [ i ] ] | = initmask ;
}
continue ;
} else if ( args [ argidx ] = = " -mince " & & argidx + 1 < args . size ( ) ) {
mince = atoi ( args [ + + argidx ] . c_str ( ) ) ;
continue ;
} else if ( args [ argidx ] = = " -minsrst " & & argidx + 1 < args . size ( ) ) {
minsrst = atoi ( args [ + + argidx ] . c_str ( ) ) ;
continue ;
}
break ;
}
extra_args ( args , argidx , design ) ;
supported_dffsr = supported_cells [ FF_DFFSR ] | supported_cells [ FF_DFFSRE ] ;
supported_adff0 = supported_cells [ FF_ADFF0 ] | supported_cells [ FF_ADFFE0 ] | supported_dffsr ;
supported_adff1 = supported_cells [ FF_ADFF1 ] | supported_cells [ FF_ADFFE1 ] | supported_dffsr ;
supported_sdff0 = supported_cells [ FF_SDFF0 ] | supported_cells [ FF_SDFFE0 ] | supported_cells [ FF_SDFFCE0 ] ;
supported_sdff1 = supported_cells [ FF_SDFF1 ] | supported_cells [ FF_SDFFE1 ] | supported_cells [ FF_SDFFCE1 ] ;
supported_dff = supported_cells [ FF_DFF ] | supported_cells [ FF_DFFE ] | supported_dffsr | supported_adff0 | supported_adff1 | supported_sdff0 | supported_sdff1 ;
supported_sr = supported_dffsr | supported_cells [ FF_DLATCHSR ] | supported_cells [ FF_SR ] | supported_cells [ FF_ADLATCH0 ] | flip_initmask ( supported_cells [ FF_ADLATCH1 ] ) ;
supported_dlatch = supported_cells [ FF_DLATCH ] | supported_cells [ FF_ADLATCH0 ] | supported_cells [ FF_ADLATCH1 ] | supported_cells [ FF_DLATCHSR ] ;
for ( auto module : design - > selected_modules ( ) )
{
sigmap . set ( module ) ;
initbits . clear ( ) ;
for ( auto wire : module - > selected_wires ( ) )
{
if ( wire - > attributes . count ( ID : : init ) = = 0 )
continue ;
SigSpec wirebits = sigmap ( wire ) ;
Const initval = wire - > attributes . at ( ID : : init ) ;
for ( int i = 0 ; i < GetSize ( wirebits ) & & i < GetSize ( initval ) ; i + + )
{
SigBit bit = wirebits [ i ] ;
State val = initval [ i ] ;
if ( val ! = State : : S0 & & val ! = State : : S1 & & bit . wire ! = nullptr )
continue ;
if ( initbits . count ( bit ) ) {
if ( initbits . at ( bit ) . first ! = val )
log_error ( " Conflicting init values for signal %s (%s = %s != %s). \n " ,
log_signal ( bit ) , log_signal ( SigBit ( wire , i ) ) ,
log_signal ( val ) , log_signal ( initbits . at ( bit ) . first ) ) ;
continue ;
}
initbits [ bit ] = std : : make_pair ( val , SigBit ( wire , i ) ) ;
}
}
if ( mince | | minsrst ) {
ce_used . clear ( ) ;
srst_used . clear ( ) ;
for ( auto cell : module - > cells ( ) ) {
if ( ! RTLIL : : builtin_ff_cell_types ( ) . count ( cell - > type ) )
continue ;
if ( cell - > hasPort ( ID : : C ) & & cell - > hasPort ( ID : : E ) ) {
SigSpec sig = cell - > getPort ( ID : : E ) ;
// Do not count const enable signals.
if ( GetSize ( sig ) = = 1 & & sig [ 0 ] . wire )
ce_used [ sig [ 0 ] ] + + ;
}
if ( cell - > type . str ( ) . substr ( 0 , 6 ) = = " $_SDFF " ) {
SigSpec sig = cell - > getPort ( ID : : R ) ;
// Do not count const srst signals.
if ( GetSize ( sig ) = = 1 & & sig [ 0 ] . wire )
srst_used [ sig [ 0 ] ] + + ;
}
}
}
// First gather FF cells, then iterate over them later.
// We may need to split an FF into several cells.
std : : vector < Cell * > ff_cells ;
for ( auto cell : module - > selected_cells ( ) )
{
// Early exit for non-FFs.
if ( ! RTLIL : : builtin_ff_cell_types ( ) . count ( cell - > type ) )
continue ;
ff_cells . push_back ( cell ) ;
}
for ( auto cell : ff_cells )
handle_ff ( cell ) ;
}
sigmap . clear ( ) ;
initbits . clear ( ) ;
ce_used . clear ( ) ;
srst_used . clear ( ) ;
}
} DffLegalizePass ;
PRIVATE_NAMESPACE_END