2020-06-23 14:36:34 +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/yosys.h"
# include "kernel/sigtools.h"
2020-07-19 02:04:38 +02:00
# include "kernel/ffinit.h"
2021-10-27 10:14:07 +02:00
# include "kernel/ff.h"
2020-06-23 14:36:34 +02:00
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
enum FfType {
FF_DFF ,
FF_DFFE ,
2021-10-27 10:14:07 +02:00
FF_ADFF ,
FF_ADFFE ,
FF_ALDFF ,
FF_ALDFFE ,
2020-06-23 14:36:34 +02:00
FF_DFFSR ,
FF_DFFSRE ,
2021-10-27 10:14:07 +02:00
FF_SDFF ,
FF_SDFFE ,
FF_SDFFCE ,
FF_RLATCH ,
2020-06-23 14:36:34 +02:00
FF_SR ,
FF_DLATCH ,
2021-10-27 10:14:07 +02:00
FF_ADLATCH ,
2020-06-23 14:36:34 +02:00
FF_DLATCHSR ,
NUM_FFTYPES ,
} ;
enum FfNeg {
2021-10-27 10:14:07 +02:00
NEG_CE = 0x1 ,
NEG_R = 0x2 ,
NEG_S = 0x4 ,
NEG_L = 0x8 ,
NEG_C = 0x10 ,
NUM_NEG = 0x20 ,
2020-06-23 14:36:34 +02:00
} ;
enum FfInit {
INIT_X = 0x1 ,
INIT_0 = 0x2 ,
INIT_1 = 0x4 ,
2021-10-27 10:14:07 +02:00
INIT_X_R0 = 0x10 ,
INIT_0_R0 = 0x20 ,
INIT_1_R0 = 0x40 ,
INIT_X_R1 = 0x100 ,
INIT_0_R1 = 0x200 ,
INIT_1_R1 = 0x400 ,
2020-06-23 14:36:34 +02:00
} ;
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 " ) ;
2021-10-27 10:14:07 +02:00
log ( " - $_ALDFF_[NP][NP]_ \n " ) ;
log ( " - $_ALDFFE_[NP][NP][NP]_ \n " ) ;
2020-06-23 14:36:34 +02:00
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 " ) ;
2022-08-24 00:28:27 +02:00
log ( " The following transformations are performed by this pass: \n " ) ;
2020-07-03 12:12:03 +02:00
log ( " \n " ) ;
2022-08-24 00:28:27 +02:00
log ( " - upconversion from a less capable cell to a more capable cell, if the less \n " ) ;
log ( " capable cell is not supported (eg. dff -> dffe, or adff -> dffsr) \n " ) ;
log ( " - unmapping FFs with clock enable (due to unsupported cell type or -mince) \n " ) ;
log ( " - unmapping FFs with sync reset (due to unsupported cell type or -minsrst) \n " ) ;
log ( " - adding inverters on the control pins (due to unsupported polarity) \n " ) ;
2020-06-23 14:36:34 +02:00
log ( " - adding inverters on the D and Q pins and inverting the init/reset values \n " ) ;
2022-08-24 00:28:27 +02:00
log ( " (due to unsupported init or reset value) \n " ) ;
log ( " - converting sr into adlatch (by tying D to 1 and using E as set input) \n " ) ;
log ( " - emulating unsupported dffsr cell by adff + adff + sr + mux \n " ) ;
log ( " - emulating unsupported dlatchsr cell by adlatch + adlatch + sr + mux \n " ) ;
2020-06-23 14:36:34 +02:00
log ( " - emulating adff when the (reset, init) value combination is unsupported by \n " ) ;
2022-08-24 00:28:27 +02:00
log ( " dff + adff + dlatch + mux \n " ) ;
2020-06-23 14:36:34 +02:00
log ( " - emulating adlatch when the (reset, init) value combination is unsupported by \n " ) ;
2022-08-24 00:28:27 +02:00
log ( " - dlatch + adlatch + dlatch + mux \n " ) ;
log ( " If the pass is unable to realize a given cell type (eg. adff when only plain dff \n " ) ;
log ( " is available), an error is raised. \n " ) ;
2020-06-23 14:36:34 +02:00
}
// 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 ;
2021-10-27 10:14:07 +02:00
// Aggregated for all *dffe* cells.
int supported_dffe ;
2020-06-23 14:36:34 +02:00
// Aggregated for all dffsr* cells.
int supported_dffsr ;
2021-10-27 10:14:07 +02:00
// Aggregated for all aldff cells.
int supported_aldff ;
// Aggregated for all aldffe cells.
int supported_aldffe ;
// Aggregated for all adff* cells and trivial emulations.
int supported_adff ;
// Aggregated for all adffe* cells and trivial emulations.
int supported_adffe ;
2020-06-23 14:36:34 +02:00
// Aggregated for all sdff* cells.
2021-10-27 10:14:07 +02:00
int supported_sdff ;
2020-06-23 14:36:34 +02:00
// Aggregated for all ways to obtain a SR latch.
int supported_sr ;
2021-10-27 10:14:07 +02:00
int supported_sr_plain ;
2020-06-23 14:36:34 +02:00
// Aggregated for all *dlatch* cells.
int supported_dlatch ;
2021-10-27 10:14:07 +02:00
int supported_dlatch_plain ;
// Aggregated for all ways to obtain an R latch.
int supported_rlatch ;
// Aggregated for all adlatch cells and trivial emulations.
int supported_adlatch ;
2020-06-23 14:36:34 +02:00
int mince ;
int minsrst ;
dict < SigBit , int > ce_used ;
dict < SigBit , int > srst_used ;
SigMap sigmap ;
2020-07-19 02:04:38 +02:00
FfInitVals initvals ;
2020-06-23 14:36:34 +02:00
int flip_initmask ( int mask ) {
int res = mask & INIT_X ;
if ( mask & INIT_0 )
res | = INIT_1 ;
if ( mask & INIT_1 )
res | = INIT_0 ;
2021-10-27 10:14:07 +02:00
if ( mask & INIT_X_R0 )
res | = INIT_X_R1 ;
if ( mask & INIT_0_R0 )
res | = INIT_1_R1 ;
if ( mask & INIT_1_R0 )
res | = INIT_0_R1 ;
if ( mask & INIT_X_R1 )
res | = INIT_X_R0 ;
if ( mask & INIT_0_R1 )
res | = INIT_1_R0 ;
if ( mask & INIT_1_R1 )
res | = INIT_0_R0 ;
2020-06-23 14:36:34 +02:00
return res ;
}
2021-10-27 10:14:07 +02:00
int get_ff_type ( const FfData & ff ) {
if ( ff . has_clk ) {
if ( ff . has_sr ) {
return ff . has_ce ? FF_DFFSRE : FF_DFFSR ;
} else if ( ff . has_arst ) {
return ff . has_ce ? FF_ADFFE : FF_ADFF ;
} else if ( ff . has_aload ) {
return ff . has_ce ? FF_ALDFFE : FF_ALDFF ;
} else if ( ff . has_srst ) {
if ( ff . has_ce )
return ff . ce_over_srst ? FF_SDFFCE : FF_SDFFE ;
else
return FF_SDFF ;
} else {
return ff . has_ce ? FF_DFFE : FF_DFF ;
}
2020-06-23 14:36:34 +02:00
} else {
2021-10-27 10:14:07 +02:00
if ( ff . has_aload ) {
if ( ff . has_sr )
return FF_DLATCHSR ;
else if ( ff . has_arst )
return FF_ADLATCH ;
else
return FF_DLATCH ;
} else {
if ( ff . has_sr ) {
return FF_SR ;
} else if ( ff . has_arst ) {
return FF_RLATCH ;
} else {
log_assert ( 0 ) ;
return 0 ;
}
}
2020-06-23 14:36:34 +02:00
}
2021-10-27 10:14:07 +02:00
}
2020-06-23 14:36:34 +02:00
2021-10-27 10:14:07 +02:00
int get_initmask ( FfData & ff ) {
int res = 0 ;
if ( ff . val_init [ 0 ] = = State : : S0 )
res = INIT_0 ;
else if ( ff . val_init [ 0 ] = = State : : S1 )
res = INIT_1 ;
else
res = INIT_X ;
if ( ff . has_arst ) {
if ( ff . val_arst [ 0 ] = = State : : S0 )
res < < = 4 ;
else if ( ff . val_arst [ 0 ] = = State : : S1 )
res < < = 8 ;
} else if ( ff . has_srst ) {
if ( ff . val_srst [ 0 ] = = State : : S0 )
res < < = 4 ;
else if ( ff . val_srst [ 0 ] = = State : : S1 )
res < < = 8 ;
}
return res ;
}
2020-06-23 14:36:34 +02:00
2021-10-27 10:14:07 +02:00
void fail_ff ( const FfData & ff , const char * reason ) {
2026-05-08 09:01:43 +02:00
log_error ( " FF %s.%s (type %s) cannot be legalized: %s \n " , ff . module - > name . unescape ( ) , ff . cell - > name . unescape ( ) , ff . cell - > type . unescape ( ) , reason ) ;
2021-10-27 10:14:07 +02:00
}
2020-06-23 14:36:34 +02:00
2021-10-27 10:14:07 +02:00
bool try_flip ( FfData & ff , int supported_mask ) {
int initmask = get_initmask ( ff ) ;
if ( supported_mask & initmask )
return true ;
if ( supported_mask & flip_initmask ( initmask ) ) {
ff . flip_bits ( { 0 } ) ;
return true ;
}
return false ;
}
2020-06-23 14:36:34 +02:00
2021-10-27 10:14:07 +02:00
void emulate_split_init_arst ( FfData & ff ) {
ff . remove ( ) ;
2020-06-23 14:36:34 +02:00
2021-10-27 10:14:07 +02:00
FfData ff_dff ( ff . module , & initvals , NEW_ID ) ;
ff_dff . width = ff . width ;
ff_dff . has_aload = ff . has_aload ;
ff_dff . sig_aload = ff . sig_aload ;
ff_dff . pol_aload = ff . pol_aload ;
ff_dff . sig_ad = ff . sig_ad ;
ff_dff . has_clk = ff . has_clk ;
ff_dff . sig_clk = ff . sig_clk ;
ff_dff . pol_clk = ff . pol_clk ;
ff_dff . sig_d = ff . sig_d ;
ff_dff . has_ce = ff . has_ce ;
ff_dff . sig_ce = ff . sig_ce ;
ff_dff . pol_ce = ff . pol_ce ;
ff_dff . sig_q = ff . module - > addWire ( NEW_ID , ff . width ) ;
ff_dff . val_init = ff . val_init ;
ff_dff . is_fine = ff . is_fine ;
FfData ff_adff ( ff . module , & initvals , NEW_ID ) ;
ff_adff . width = ff . width ;
ff_adff . has_aload = ff . has_aload ;
ff_adff . sig_aload = ff . sig_aload ;
ff_adff . pol_aload = ff . pol_aload ;
ff_adff . sig_ad = ff . sig_ad ;
ff_adff . has_clk = ff . has_clk ;
ff_adff . sig_clk = ff . sig_clk ;
ff_adff . pol_clk = ff . pol_clk ;
ff_adff . sig_d = ff . sig_d ;
ff_adff . has_ce = ff . has_ce ;
ff_adff . sig_ce = ff . sig_ce ;
ff_adff . pol_ce = ff . pol_ce ;
ff_adff . sig_q = ff . module - > addWire ( NEW_ID , ff . width ) ;
ff_adff . val_init = Const ( State : : Sx , ff . width ) ;
ff_adff . has_arst = true ;
ff_adff . sig_arst = ff . sig_arst ;
ff_adff . pol_arst = ff . pol_arst ;
ff_adff . val_arst = ff . val_arst ;
ff_adff . is_fine = ff . is_fine ;
FfData ff_sel ( ff . module , & initvals , NEW_ID ) ;
ff_sel . width = 1 ;
ff_sel . sig_q = ff . module - > addWire ( NEW_ID ) ;
ff_sel . has_arst = true ;
ff_sel . sig_arst = ff . sig_arst ;
ff_sel . pol_arst = ff . pol_arst ;
ff_sel . val_arst = State : : S1 ;
ff_sel . val_init = State : : S0 ;
ff_sel . is_fine = ff . is_fine ;
2020-06-23 14:36:34 +02:00
2021-10-27 10:14:07 +02:00
if ( ff . is_fine )
ff . module - > addMuxGate ( NEW_ID , ff_dff . sig_q , ff_adff . sig_q , ff_sel . sig_q , ff . sig_q ) ;
else
ff . module - > addMux ( NEW_ID , ff_dff . sig_q , ff_adff . sig_q , ff_sel . sig_q , ff . sig_q ) ;
legalize_ff ( ff_dff ) ;
legalize_ff ( ff_adff ) ;
legalize_ff ( ff_sel ) ;
}
void emulate_split_set_clr ( FfData & ff ) {
// No native DFFSR. However, if we can conjure
// a SR latch and ADFF, it can still be emulated.
int initmask = get_initmask ( ff ) ;
int flipmask = flip_initmask ( initmask ) ;
bool init_clr = true ;
bool init_set = true ;
State initsel = State : : Sx ;
int supported_arst = ff . has_clk ? supported_adff : supported_adlatch ;
bool init_clr_ok = ( supported_arst & initmask < < 4 ) | | ( supported_arst & flipmask < < 8 ) ;
bool init_set_ok = ( supported_arst & initmask < < 8 ) | | ( supported_arst & flipmask < < 4 ) ;
if ( init_clr_ok & & init_set_ok & & supported_sr ) {
// OK
} else if ( init_clr_ok & & ( supported_sr & INIT_0 ) ) {
init_set = false ;
initsel = State : : S0 ;
} else if ( init_set_ok & & ( supported_sr & INIT_1 ) ) {
init_clr = false ;
initsel = State : : S1 ;
} else if ( init_clr_ok & & ( supported_sr & INIT_1 ) ) {
init_set = false ;
initsel = State : : S0 ;
} else if ( init_set_ok & & ( supported_sr & INIT_0 ) ) {
init_clr = false ;
initsel = State : : S1 ;
} else {
if ( ff . has_clk ) {
if ( ! supported_dffsr )
fail_ff ( ff , " dffs with async set and reset are not supported " ) ;
2020-06-23 14:36:34 +02:00
else
2021-10-27 10:14:07 +02:00
fail_ff ( ff , " initialized dffs with async set and reset are not supported " ) ;
} else {
if ( ! supported_cells [ FF_DLATCHSR ] )
fail_ff ( ff , " dlatch with async set and reset are not supported " ) ;
else
fail_ff ( ff , " initialized dlatch with async set and reset are not supported " ) ;
}
}
2020-06-23 14:36:34 +02:00
2021-10-27 10:14:07 +02:00
// If we have to unmap enable anyway, do it before breakdown.
if ( ff . has_ce & & ! supported_cells [ FF_ADFFE ] )
ff . unmap_ce ( ) ;
2020-06-23 14:36:34 +02:00
2026-05-08 09:01:43 +02:00
log_warning ( " Emulating async set + reset with several FFs and a mux for %s.%s \n " , ff . module - > name . unescape ( ) , ff . cell - > name . unescape ( ) ) ;
2020-06-23 14:36:34 +02:00
2021-10-27 10:14:07 +02:00
log_assert ( ff . width = = 1 ) ;
ff . remove ( ) ;
2020-06-23 14:36:34 +02:00
2021-10-27 10:14:07 +02:00
FfData ff_clr ( ff . module , & initvals , NEW_ID ) ;
ff_clr . width = ff . width ;
ff_clr . has_aload = ff . has_aload ;
ff_clr . sig_aload = ff . sig_aload ;
ff_clr . pol_aload = ff . pol_aload ;
ff_clr . sig_ad = ff . sig_ad ;
ff_clr . has_clk = ff . has_clk ;
ff_clr . sig_clk = ff . sig_clk ;
ff_clr . pol_clk = ff . pol_clk ;
ff_clr . sig_d = ff . sig_d ;
ff_clr . has_ce = ff . has_ce ;
ff_clr . sig_ce = ff . sig_ce ;
ff_clr . pol_ce = ff . pol_ce ;
ff_clr . has_arst = true ;
ff_clr . sig_arst = ff . sig_clr ;
ff_clr . pol_arst = ff . pol_clr ;
ff_clr . val_arst = Const ( State : : S0 , ff . width ) ;
ff_clr . sig_q = ff . module - > addWire ( NEW_ID , ff . width ) ;
ff_clr . val_init = init_clr ? ff . val_init : Const ( State : : Sx , ff . width ) ;
ff_clr . is_fine = ff . is_fine ;
2020-06-23 14:36:34 +02:00
2021-10-27 10:14:07 +02:00
FfData ff_set ( ff . module , & initvals , NEW_ID ) ;
ff_set . width = ff . width ;
ff_set . has_aload = ff . has_aload ;
ff_set . sig_aload = ff . sig_aload ;
ff_set . pol_aload = ff . pol_aload ;
ff_set . sig_ad = ff . sig_ad ;
ff_set . has_clk = ff . has_clk ;
ff_set . sig_clk = ff . sig_clk ;
ff_set . pol_clk = ff . pol_clk ;
ff_set . sig_d = ff . sig_d ;
ff_set . has_ce = ff . has_ce ;
ff_set . sig_ce = ff . sig_ce ;
ff_set . pol_ce = ff . pol_ce ;
ff_set . has_arst = true ;
ff_set . sig_arst = ff . sig_set ;
ff_set . pol_arst = ff . pol_set ;
ff_set . val_arst = Const ( State : : S1 , ff . width ) ;
ff_set . sig_q = ff . module - > addWire ( NEW_ID , ff . width ) ;
ff_set . val_init = init_set ? ff . val_init : Const ( State : : Sx , ff . width ) ;
ff_set . is_fine = ff . is_fine ;
FfData ff_sel ( ff . module , & initvals , NEW_ID ) ;
ff_sel . width = ff . width ;
ff_sel . has_sr = true ;
ff_sel . pol_clr = ff . pol_clr ;
ff_sel . pol_set = ff . pol_set ;
ff_sel . sig_clr = ff . sig_clr ;
ff_sel . sig_set = ff . sig_set ;
ff_sel . sig_q = ff . module - > addWire ( NEW_ID , ff . width ) ;
ff_sel . val_init = Const ( initsel , ff . width ) ;
ff_sel . is_fine = ff . is_fine ;
if ( ! ff . is_fine )
ff . module - > addMux ( NEW_ID , ff_clr . sig_q , ff_set . sig_q , ff_sel . sig_q , ff . sig_q ) ;
else
ff . module - > addMuxGate ( NEW_ID , ff_clr . sig_q , ff_set . sig_q , ff_sel . sig_q , ff . sig_q ) ;
legalize_ff ( ff_clr ) ;
legalize_ff ( ff_set ) ;
legalize_ff ( ff_sel ) ;
}
void legalize_dff ( FfData & ff ) {
if ( ! try_flip ( ff , supported_dff ) ) {
if ( ! supported_dff )
fail_ff ( ff , " D flip-flops are not supported " ) ;
else
fail_ff ( ff , " initialized D flip-flops are not supported " ) ;
}
int initmask = get_initmask ( ff ) ;
// Some DFF is supported with this init val. Just pick a type.
if ( ff . has_ce & & ! ( supported_dffe & initmask ) ) {
ff . unmap_ce ( ) ;
}
if ( ! ff . has_ce ) {
if ( supported_cells [ FF_DFF ] & initmask ) {
legalize_finish ( ff ) ;
2020-06-23 14:36:34 +02:00
return ;
2021-10-27 10:14:07 +02:00
}
// Try adding a set or reset pin.
if ( supported_cells [ FF_SDFF ] & initmask ) {
ff . add_dummy_srst ( ) ;
legalize_finish ( ff ) ;
return ;
}
if ( supported_cells [ FF_ADFF ] & initmask ) {
ff . add_dummy_arst ( ) ;
legalize_finish ( ff ) ;
return ;
}
// Try adding async load.
if ( supported_cells [ FF_ALDFF ] & initmask ) {
ff . add_dummy_aload ( ) ;
legalize_finish ( ff ) ;
return ;
}
// Try adding both.
if ( supported_cells [ FF_DFFSR ] & initmask ) {
ff . add_dummy_sr ( ) ;
legalize_finish ( ff ) ;
return ;
}
// Nope. Will need to add enable and go the DFFE route.
ff . add_dummy_ce ( ) ;
}
if ( supported_cells [ FF_DFFE ] & initmask ) {
legalize_finish ( ff ) ;
return ;
}
// Try adding a set or reset pin.
if ( supported_cells [ FF_SDFFCE ] & initmask ) {
ff . add_dummy_srst ( ) ;
ff . ce_over_srst = true ;
legalize_finish ( ff ) ;
return ;
}
if ( supported_cells [ FF_SDFFE ] & initmask ) {
ff . add_dummy_srst ( ) ;
legalize_finish ( ff ) ;
return ;
}
if ( supported_cells [ FF_ADFFE ] & initmask ) {
ff . add_dummy_arst ( ) ;
legalize_finish ( ff ) ;
return ;
}
if ( supported_cells [ FF_ALDFFE ] & initmask ) {
ff . add_dummy_aload ( ) ;
legalize_finish ( ff ) ;
return ;
}
// Try adding both.
if ( supported_cells [ FF_DFFSRE ] & initmask ) {
ff . add_dummy_sr ( ) ;
legalize_finish ( ff ) ;
return ;
}
log_assert ( 0 ) ;
}
2020-07-06 22:52:05 +02:00
2021-10-27 10:14:07 +02:00
void legalize_sdffce ( FfData & ff ) {
if ( ! try_flip ( ff , supported_cells [ FF_SDFFCE ] | supported_cells [ FF_SDFFE ] ) ) {
ff . unmap_srst ( ) ;
legalize_dff ( ff ) ;
return ;
}
2020-06-23 14:36:34 +02:00
2021-10-27 10:14:07 +02:00
int initmask = get_initmask ( ff ) ;
if ( supported_cells [ FF_SDFFCE ] & initmask ) {
// OK
} else if ( supported_cells [ FF_SDFFE ] & initmask ) {
ff . convert_ce_over_srst ( false ) ;
} else {
log_assert ( 0 ) ;
}
legalize_finish ( ff ) ;
}
void legalize_sdff ( FfData & ff ) {
if ( ! try_flip ( ff , supported_sdff ) ) {
ff . unmap_srst ( ) ;
legalize_dff ( ff ) ;
return ;
}
int initmask = get_initmask ( ff ) ;
if ( ! ff . has_ce ) {
if ( supported_cells [ FF_SDFF ] & initmask ) {
// OK
} else if ( supported_cells [ FF_SDFFE ] & initmask ) {
ff . add_dummy_ce ( ) ;
} else if ( supported_cells [ FF_SDFFCE ] & initmask ) {
ff . add_dummy_ce ( ) ;
ff . ce_over_srst = true ;
} else {
2020-06-23 14:36:34 +02:00
log_assert ( 0 ) ;
2021-10-27 10:14:07 +02:00
}
} else {
log_assert ( ! ff . ce_over_srst ) ;
if ( supported_cells [ FF_SDFFE ] & initmask ) {
// OK
} else if ( supported_cells [ FF_SDFFCE ] & initmask ) {
ff . convert_ce_over_srst ( true ) ;
} else if ( supported_cells [ FF_SDFF ] & initmask ) {
ff . unmap_ce ( ) ;
} else {
log_assert ( 0 ) ;
}
}
legalize_finish ( ff ) ;
}
2020-06-23 14:36:34 +02:00
2021-10-27 10:14:07 +02:00
void legalize_adff ( FfData & ff ) {
if ( ! try_flip ( ff , supported_adff ) ) {
if ( ! supported_adff )
fail_ff ( ff , " dffs with async set or reset are not supported " ) ;
if ( ! ( supported_dff & ( INIT_0 | INIT_1 ) ) )
fail_ff ( ff , " initialized dffs are not supported " ) ;
// 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_rlatch ) & ( INIT_0_R1 | INIT_1_R0 ) ) )
fail_ff ( ff , " unsupported initial value and async reset value combination " ) ;
// If we have to unmap enable anyway, do it before breakdown.
if ( ff . has_ce & & ! supported_cells [ FF_ADFFE ] )
ff . unmap_ce ( ) ;
if ( ff . cell )
2026-05-08 09:01:43 +02:00
log_warning ( " Emulating mismatched async reset and init with several FFs and a mux for %s.%s \n " , ff . module - > name . unescape ( ) , ff . cell - > name . unescape ( ) ) ;
2021-10-27 10:14:07 +02:00
emulate_split_init_arst ( ff ) ;
return ;
}
2020-06-23 14:36:34 +02:00
2021-10-27 10:14:07 +02:00
int initmask = get_initmask ( ff ) ;
if ( ff . has_ce & & ! ( supported_adffe & initmask ) ) {
ff . unmap_ce ( ) ;
}
if ( ! ff . has_ce ) {
if ( supported_cells [ FF_ADFF ] & initmask ) {
legalize_finish ( ff ) ;
2020-06-23 14:36:34 +02:00
return ;
2021-10-27 10:14:07 +02:00
}
// Try converting to async load.
if ( supported_cells [ FF_ALDFF ] & initmask ) {
ff . arst_to_aload ( ) ;
legalize_finish ( ff ) ;
return ;
}
// Try convertint to SR.
if ( supported_cells [ FF_DFFSR ] & initmask ) {
ff . arst_to_sr ( ) ;
legalize_finish ( ff ) ;
return ;
}
ff . add_dummy_ce ( ) ;
}
if ( supported_cells [ FF_ADFFE ] & initmask ) {
legalize_finish ( ff ) ;
return ;
}
// Try converting to async load.
if ( supported_cells [ FF_ALDFFE ] & initmask ) {
ff . arst_to_aload ( ) ;
legalize_finish ( ff ) ;
return ;
}
// Try convertint to SR.
if ( supported_cells [ FF_DFFSRE ] & initmask ) {
ff . arst_to_sr ( ) ;
legalize_finish ( ff ) ;
return ;
}
log_assert ( 0 ) ;
}
void legalize_aldff ( FfData & ff ) {
if ( ! try_flip ( ff , supported_aldff ) ) {
ff . aload_to_sr ( ) ;
emulate_split_set_clr ( ff ) ;
return ;
}
int initmask = get_initmask ( ff ) ;
if ( ff . has_ce & & ! ( supported_aldffe & initmask ) ) {
ff . unmap_ce ( ) ;
}
2020-06-23 14:36:34 +02:00
2021-10-27 10:14:07 +02:00
if ( ! ff . has_ce ) {
if ( supported_cells [ FF_ALDFF ] & initmask ) {
legalize_finish ( ff ) ;
2020-06-23 14:36:34 +02:00
return ;
2021-10-27 10:14:07 +02:00
}
if ( supported_cells [ FF_DFFSR ] & initmask ) {
ff . aload_to_sr ( ) ;
legalize_finish ( ff ) ;
return ;
}
ff . add_dummy_ce ( ) ;
}
if ( supported_cells [ FF_ALDFFE ] & initmask ) {
legalize_finish ( ff ) ;
return ;
}
if ( supported_cells [ FF_DFFSRE ] & initmask ) {
ff . aload_to_sr ( ) ;
legalize_finish ( ff ) ;
return ;
}
log_assert ( 0 ) ;
}
2020-06-23 14:36:34 +02:00
2021-10-27 10:14:07 +02:00
void legalize_dffsr ( FfData & ff ) {
if ( ! try_flip ( ff , supported_dffsr ) ) {
emulate_split_set_clr ( ff ) ;
return ;
}
int initmask = get_initmask ( ff ) ;
if ( ff . has_ce & & ! ( supported_cells [ FF_DFFSRE ] & initmask ) ) {
ff . unmap_ce ( ) ;
}
if ( ! ff . has_ce ) {
if ( supported_cells [ FF_DFFSR ] & initmask ) {
legalize_finish ( ff ) ;
return ;
}
ff . add_dummy_ce ( ) ;
}
log_assert ( supported_cells [ FF_DFFSRE ] & initmask ) ;
legalize_finish ( ff ) ;
}
void legalize_dlatch ( FfData & ff ) {
if ( ! try_flip ( ff , supported_dlatch ) ) {
if ( ! supported_dlatch )
fail_ff ( ff , " D latches are not supported " ) ;
else
fail_ff ( ff , " initialized D latches are not supported " ) ;
}
int initmask = get_initmask ( ff ) ;
// Some DLATCH is supported with this init val. Just pick a type.
if ( supported_cells [ FF_DLATCH ] & initmask ) {
legalize_finish ( ff ) ;
} else if ( supported_cells [ FF_ADLATCH ] & initmask ) {
ff . add_dummy_arst ( ) ;
legalize_finish ( ff ) ;
} else if ( supported_cells [ FF_DLATCHSR ] & initmask ) {
ff . add_dummy_sr ( ) ;
legalize_finish ( ff ) ;
} else if ( supported_cells [ FF_ALDFF ] & initmask ) {
ff . add_dummy_clk ( ) ;
legalize_finish ( ff ) ;
} else if ( supported_cells [ FF_ALDFFE ] & initmask ) {
ff . add_dummy_clk ( ) ;
ff . add_dummy_ce ( ) ;
legalize_finish ( ff ) ;
} else if ( supported_sr & initmask ) {
ff . aload_to_sr ( ) ;
legalize_sr ( ff ) ;
} else {
log_assert ( 0 ) ;
}
}
void legalize_adlatch ( FfData & ff ) {
if ( ! try_flip ( ff , supported_adlatch ) ) {
if ( ! supported_adlatch )
fail_ff ( ff , " D latches with async set or reset are not supported " ) ;
if ( ! ( supported_dlatch & ( INIT_0 | INIT_1 ) ) )
fail_ff ( ff , " initialized D latches are not supported " ) ;
// 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 adlatch + dlatch + dlatch + mux.
if ( ff . cell )
2026-05-08 09:01:43 +02:00
log_warning ( " Emulating mismatched async reset and init with several latches and a mux for %s.%s \n " , ff . module - > name . unescape ( ) , ff . cell - > name . unescape ( ) ) ;
2021-10-27 10:14:07 +02:00
ff . remove ( ) ;
emulate_split_init_arst ( ff ) ;
return ;
}
int initmask = get_initmask ( ff ) ;
if ( supported_cells [ FF_ADLATCH ] & initmask ) {
// OK
} else if ( supported_cells [ FF_DLATCHSR ] & initmask ) {
ff . arst_to_sr ( ) ;
} else {
log_assert ( 0 ) ;
}
legalize_finish ( ff ) ;
}
void legalize_dlatchsr ( FfData & ff ) {
if ( ! try_flip ( ff , supported_cells [ FF_DLATCHSR ] ) ) {
emulate_split_set_clr ( ff ) ;
return ;
}
legalize_finish ( ff ) ;
}
void legalize_rlatch ( FfData & ff ) {
if ( ! try_flip ( ff , supported_rlatch ) ) {
if ( ! supported_dlatch )
fail_ff ( ff , " D latches are not supported " ) ;
else
fail_ff ( ff , " initialized D latches are not supported " ) ;
}
int initmask = get_initmask ( ff ) ;
if ( ( ( supported_dlatch_plain & 7 ) * 0x111 ) & initmask ) {
ff . arst_to_aload ( ) ;
legalize_dlatch ( ff ) ;
} else if ( supported_sr & initmask ) {
ff . arst_to_sr ( ) ;
legalize_sr ( ff ) ;
} else if ( supported_adff & initmask ) {
ff . add_dummy_clk ( ) ;
legalize_adff ( ff ) ;
} else {
log_assert ( 0 ) ;
}
}
void legalize_sr ( FfData & ff ) {
if ( ! try_flip ( ff , supported_sr ) ) {
if ( ! supported_sr )
fail_ff ( ff , " sr latches are not supported " ) ;
else
fail_ff ( ff , " initialized sr latches are not supported " ) ;
}
int initmask = get_initmask ( ff ) ;
if ( supported_cells [ FF_SR ] & initmask ) {
// OK
} else if ( supported_cells [ FF_DLATCHSR ] & initmask ) {
// Upgrade to DLATCHSR.
ff . add_dummy_aload ( ) ;
} else if ( supported_cells [ FF_DFFSR ] & initmask ) {
// Upgrade to DFFSR.
ff . add_dummy_clk ( ) ;
} else if ( supported_cells [ FF_DFFSRE ] & initmask ) {
// Upgrade to DFFSRE.
ff . add_dummy_clk ( ) ;
ff . add_dummy_ce ( ) ;
} else if ( supported_cells [ FF_ADLATCH ] & ( initmask < < 4 ) ) {
ff . has_sr = false ;
ff . has_aload = true ;
ff . has_arst = true ;
ff . pol_arst = ff . pol_clr ;
ff . sig_arst = ff . sig_clr ;
ff . sig_aload = ff . sig_set ;
ff . pol_aload = ff . pol_set ;
ff . sig_ad = State : : S1 ;
ff . val_arst = State : : S0 ;
} else if ( supported_cells [ FF_ADLATCH ] & ( flip_initmask ( initmask ) < < 8 ) ) {
ff . has_sr = false ;
ff . has_aload = true ;
ff . has_arst = true ;
ff . pol_arst = ff . pol_clr ;
ff . sig_arst = ff . sig_clr ;
ff . sig_aload = ff . sig_set ;
ff . pol_aload = ff . pol_set ;
ff . sig_ad = State : : S0 ;
ff . val_arst = State : : S1 ;
ff . remove_init ( ) ;
Wire * new_q = ff . module - > addWire ( NEW_ID ) ;
if ( ff . is_fine )
ff . module - > addNotGate ( NEW_ID , new_q , ff . sig_q ) ;
else
ff . module - > addNot ( NEW_ID , new_q , ff . sig_q ) ;
ff . sig_q = new_q ;
if ( ff . val_init = = State : : S0 )
ff . val_init = State : : S1 ;
else if ( ff . val_init = = State : : S1 )
ff . val_init = State : : S0 ;
} else {
log_assert ( 0 ) ;
}
legalize_finish ( ff ) ;
}
void fixup_reset_x ( FfData & ff , int supported ) {
for ( int i = 0 ; i < ff . width ; i + + ) {
int mask ;
if ( ff . val_init [ i ] = = State : : S0 )
mask = INIT_0 ;
else if ( ff . val_init [ i ] = = State : : S1 )
mask = INIT_1 ;
else
mask = INIT_X ;
if ( ff . has_arst ) {
if ( ff . val_arst [ i ] = = State : : Sx ) {
if ( ! ( supported & ( mask < < 8 ) ) )
2025-08-28 05:53:51 +02:00
ff . val_arst . set ( i , State : : S0 ) ;
2021-10-27 10:14:07 +02:00
if ( ! ( supported & ( mask < < 4 ) ) )
2025-08-28 05:53:51 +02:00
ff . val_arst . set ( i , State : : S1 ) ;
2020-06-23 14:36:34 +02:00
}
2021-10-27 10:14:07 +02:00
}
if ( ff . has_srst ) {
if ( ff . val_srst [ i ] = = State : : Sx ) {
if ( ! ( supported & ( mask < < 8 ) ) )
2025-08-28 05:53:51 +02:00
ff . val_srst . set ( i , State : : S0 ) ;
2021-10-27 10:14:07 +02:00
if ( ! ( supported & ( mask < < 4 ) ) )
2025-08-28 05:53:51 +02:00
ff . val_srst . set ( i , State : : S1 ) ;
2020-06-23 14:36:34 +02:00
}
2021-10-27 10:14:07 +02:00
}
}
}
2020-06-23 14:36:34 +02:00
2021-10-27 10:14:07 +02:00
void legalize_ff ( FfData & ff ) {
if ( ff . has_gclk )
return ;
// TODO: consider supporting coarse as well.
if ( ! ff . is_fine )
return ;
if ( mince & & ff . has_ce & & ff . sig_ce [ 0 ] . wire & & ce_used [ ff . sig_ce [ 0 ] ] < mince )
ff . unmap_ce ( ) ;
if ( minsrst & & ff . has_srst & & ff . sig_srst [ 0 ] . wire & & srst_used [ ff . sig_srst [ 0 ] ] < minsrst )
ff . unmap_srst ( ) ;
if ( ff . has_clk ) {
if ( ff . has_sr ) {
legalize_dffsr ( ff ) ;
} else if ( ff . has_aload ) {
legalize_aldff ( ff ) ;
} else if ( ff . has_arst ) {
legalize_adff ( ff ) ;
} else if ( ff . has_srst ) {
if ( ff . has_ce & & ff . ce_over_srst )
legalize_sdffce ( ff ) ;
2020-06-23 14:36:34 +02:00
else
2021-10-27 10:14:07 +02:00
legalize_sdff ( ff ) ;
} else {
legalize_dff ( ff ) ;
}
} else if ( ff . has_aload ) {
if ( ff . has_sr ) {
legalize_dlatchsr ( ff ) ;
} else if ( ff . has_arst ) {
legalize_adlatch ( ff ) ;
} else {
legalize_dlatch ( ff ) ;
}
} else {
if ( ff . has_sr ) {
legalize_sr ( ff ) ;
} else if ( ff . has_arst ) {
legalize_rlatch ( ff ) ;
2020-06-23 14:36:34 +02:00
} else {
log_assert ( 0 ) ;
}
}
2021-10-27 10:14:07 +02:00
}
void flip_pol ( FfData & ff , SigSpec & sig , bool & pol ) {
if ( sig = = State : : S0 ) {
sig = State : : S1 ;
} else if ( sig = = State : : S1 ) {
sig = State : : S0 ;
} else if ( ff . is_fine ) {
sig = ff . module - > NotGate ( NEW_ID , sig ) ;
} else {
sig = ff . module - > Not ( NEW_ID , sig ) ;
}
pol = ! pol ;
}
2020-06-23 14:36:34 +02:00
2021-10-27 10:14:07 +02:00
void legalize_finish ( FfData & ff ) {
int ff_type = get_ff_type ( ff ) ;
int initmask = get_initmask ( ff ) ;
log_assert ( supported_cells [ ff_type ] & initmask ) ;
int ff_neg = 0 ;
if ( ff . has_sr ) {
if ( ! ff . pol_clr )
ff_neg | = NEG_R ;
if ( ! ff . pol_set )
ff_neg | = NEG_S ;
}
if ( ff . has_arst ) {
if ( ! ff . pol_arst )
ff_neg | = NEG_R ;
}
if ( ff . has_srst ) {
if ( ! ff . pol_srst )
ff_neg | = NEG_R ;
}
if ( ff . has_aload ) {
if ( ! ff . pol_aload )
ff_neg | = NEG_L ;
}
if ( ff . has_clk ) {
if ( ! ff . pol_clk )
ff_neg | = NEG_C ;
}
if ( ff . has_ce ) {
if ( ! ff . pol_ce )
ff_neg | = NEG_CE ;
}
2020-06-23 14:36:34 +02:00
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 ) ;
2021-10-27 10:14:07 +02:00
if ( xneg & NEG_CE )
flip_pol ( ff , ff . sig_ce , ff . pol_ce ) ;
if ( ff . has_sr ) {
if ( xneg & NEG_R )
flip_pol ( ff , ff . sig_clr , ff . pol_clr ) ;
if ( xneg & NEG_S )
flip_pol ( ff , ff . sig_set , ff . pol_set ) ;
}
if ( ff . has_arst & & xneg & NEG_R )
flip_pol ( ff , ff . sig_arst , ff . pol_arst ) ;
if ( ff . has_srst & & xneg & NEG_R )
flip_pol ( ff , ff . sig_srst , ff . pol_srst ) ;
if ( xneg & NEG_L )
flip_pol ( ff , ff . sig_aload , ff . pol_aload ) ;
2020-06-23 14:36:34 +02:00
if ( xneg & NEG_C )
2021-10-27 10:14:07 +02:00
flip_pol ( ff , ff . sig_clk , ff . pol_clk ) ;
2020-06-23 14:36:34 +02:00
ff_neg ^ = xneg ;
}
2021-10-27 10:14:07 +02:00
fixup_reset_x ( ff , supported_cells_neg [ ff_type ] [ ff_neg ] ) ;
ff . emit ( ) ;
2020-06-23 14:36:34 +02:00
}
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 ;
}
2023-02-15 12:53:46 +01:00
mince = design - > scratchpad_get_int ( " dfflegalize.mince " , 0 ) ;
minsrst = design - > scratchpad_get_int ( " dfflegalize.minsrst " , 0 ) ;
2020-06-23 14:36:34 +02:00
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 ] ;
2021-10-27 10:14:07 +02:00
enum FfType ff_type ;
2020-06-23 14:36:34 +02:00
char pol_c = 0 ;
2021-10-27 10:14:07 +02:00
char pol_l = 0 ;
2020-06-23 14:36:34 +02:00
char pol_s = 0 ;
char pol_r = 0 ;
2021-10-27 10:14:07 +02:00
char pol_ce = 0 ;
2020-06-23 14:36:34 +02:00
char srval = 0 ;
if ( celltype . substr ( 0 , 5 ) = = " $_SR_ " & & celltype . size ( ) = = 8 & & celltype [ 7 ] = = ' _ ' ) {
2021-10-27 10:14:07 +02:00
ff_type = FF_SR ;
2020-06-23 14:36:34 +02:00
pol_s = celltype [ 5 ] ;
pol_r = celltype [ 6 ] ;
} else if ( celltype . substr ( 0 , 6 ) = = " $_DFF_ " & & celltype . size ( ) = = 8 & & celltype [ 7 ] = = ' _ ' ) {
2021-10-27 10:14:07 +02:00
ff_type = FF_DFF ;
2020-06-23 14:36:34 +02:00
pol_c = celltype [ 6 ] ;
} else if ( celltype . substr ( 0 , 7 ) = = " $_DFFE_ " & & celltype . size ( ) = = 10 & & celltype [ 9 ] = = ' _ ' ) {
2021-10-27 10:14:07 +02:00
ff_type = FF_DFFE ;
2020-06-23 14:36:34 +02:00
pol_c = celltype [ 7 ] ;
2021-10-27 10:14:07 +02:00
pol_ce = celltype [ 8 ] ;
2020-06-23 14:36:34 +02:00
} else if ( celltype . substr ( 0 , 6 ) = = " $_DFF_ " & & celltype . size ( ) = = 10 & & celltype [ 9 ] = = ' _ ' ) {
2021-10-27 10:14:07 +02:00
ff_type = FF_ADFF ;
2020-06-23 14:36:34 +02:00
pol_c = celltype [ 6 ] ;
pol_r = celltype [ 7 ] ;
srval = celltype [ 8 ] ;
} else if ( celltype . substr ( 0 , 7 ) = = " $_DFFE_ " & & celltype . size ( ) = = 12 & & celltype [ 11 ] = = ' _ ' ) {
2021-10-27 10:14:07 +02:00
ff_type = FF_ADFFE ;
2020-06-23 14:36:34 +02:00
pol_c = celltype [ 7 ] ;
pol_r = celltype [ 8 ] ;
srval = celltype [ 9 ] ;
2021-10-27 10:14:07 +02:00
pol_ce = celltype [ 10 ] ;
} else if ( celltype . substr ( 0 , 8 ) = = " $_ALDFF_ " & & celltype . size ( ) = = 11 & & celltype [ 10 ] = = ' _ ' ) {
ff_type = FF_ALDFF ;
pol_c = celltype [ 8 ] ;
pol_l = celltype [ 9 ] ;
} else if ( celltype . substr ( 0 , 9 ) = = " $_ALDFFE_ " & & celltype . size ( ) = = 13 & & celltype [ 12 ] = = ' _ ' ) {
ff_type = FF_ALDFFE ;
pol_c = celltype [ 9 ] ;
pol_l = celltype [ 10 ] ;
pol_ce = celltype [ 11 ] ;
2020-06-23 14:36:34 +02:00
} else if ( celltype . substr ( 0 , 8 ) = = " $_DFFSR_ " & & celltype . size ( ) = = 12 & & celltype [ 11 ] = = ' _ ' ) {
2021-10-27 10:14:07 +02:00
ff_type = FF_DFFSR ;
2020-06-23 14:36:34 +02:00
pol_c = celltype [ 8 ] ;
pol_s = celltype [ 9 ] ;
pol_r = celltype [ 10 ] ;
} else if ( celltype . substr ( 0 , 9 ) = = " $_DFFSRE_ " & & celltype . size ( ) = = 14 & & celltype [ 13 ] = = ' _ ' ) {
2021-10-27 10:14:07 +02:00
ff_type = FF_DFFSRE ;
2020-06-23 14:36:34 +02:00
pol_c = celltype [ 9 ] ;
pol_s = celltype [ 10 ] ;
pol_r = celltype [ 11 ] ;
2021-10-27 10:14:07 +02:00
pol_ce = celltype [ 12 ] ;
2020-06-23 14:36:34 +02:00
} else if ( celltype . substr ( 0 , 7 ) = = " $_SDFF_ " & & celltype . size ( ) = = 11 & & celltype [ 10 ] = = ' _ ' ) {
2021-10-27 10:14:07 +02:00
ff_type = FF_SDFF ;
2020-06-23 14:36:34 +02:00
pol_c = celltype [ 7 ] ;
pol_r = celltype [ 8 ] ;
srval = celltype [ 9 ] ;
} else if ( celltype . substr ( 0 , 8 ) = = " $_SDFFE_ " & & celltype . size ( ) = = 13 & & celltype [ 12 ] = = ' _ ' ) {
2021-10-27 10:14:07 +02:00
ff_type = FF_SDFFE ;
2020-06-23 14:36:34 +02:00
pol_c = celltype [ 8 ] ;
pol_r = celltype [ 9 ] ;
srval = celltype [ 10 ] ;
2021-10-27 10:14:07 +02:00
pol_ce = celltype [ 11 ] ;
2020-06-23 14:36:34 +02:00
} else if ( celltype . substr ( 0 , 9 ) = = " $_SDFFCE_ " & & celltype . size ( ) = = 14 & & celltype [ 13 ] = = ' _ ' ) {
2021-10-27 10:14:07 +02:00
ff_type = FF_SDFFCE ;
2020-06-23 14:36:34 +02:00
pol_c = celltype [ 9 ] ;
pol_r = celltype [ 10 ] ;
srval = celltype [ 11 ] ;
2021-10-27 10:14:07 +02:00
pol_ce = celltype [ 12 ] ;
2020-06-23 14:36:34 +02:00
} else if ( celltype . substr ( 0 , 9 ) = = " $_DLATCH_ " & & celltype . size ( ) = = 11 & & celltype [ 10 ] = = ' _ ' ) {
2021-10-27 10:14:07 +02:00
ff_type = FF_DLATCH ;
pol_l = celltype [ 9 ] ;
2020-06-23 14:36:34 +02:00
} else if ( celltype . substr ( 0 , 9 ) = = " $_DLATCH_ " & & celltype . size ( ) = = 13 & & celltype [ 12 ] = = ' _ ' ) {
2021-10-27 10:14:07 +02:00
ff_type = FF_ADLATCH ;
pol_l = celltype [ 9 ] ;
2020-06-23 14:36:34 +02:00
pol_r = celltype [ 10 ] ;
srval = celltype [ 11 ] ;
} else if ( celltype . substr ( 0 , 11 ) = = " $_DLATCHSR_ " & & celltype . size ( ) = = 15 & & celltype [ 14 ] = = ' _ ' ) {
2021-10-27 10:14:07 +02:00
ff_type = FF_DLATCHSR ;
pol_l = celltype [ 11 ] ;
2020-06-23 14:36:34 +02:00
pol_s = celltype [ 12 ] ;
pol_r = celltype [ 13 ] ;
} else {
unrecognized :
2025-09-11 07:25:26 +02:00
log_error ( " unrecognized cell type %s. \n " , celltype ) ;
2020-06-23 14:36:34 +02:00
}
int mask = 0 ;
int match = 0 ;
for ( auto pair : {
std : : make_pair ( pol_c , NEG_C ) ,
2021-10-27 10:14:07 +02:00
std : : make_pair ( pol_l , NEG_L ) ,
2020-06-23 14:36:34 +02:00
std : : make_pair ( pol_s , NEG_S ) ,
std : : make_pair ( pol_r , NEG_R ) ,
2021-10-27 10:14:07 +02:00
std : : make_pair ( pol_ce , NEG_CE ) ,
2020-06-23 14:36:34 +02:00
} ) {
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 ;
}
}
2021-10-27 10:14:07 +02:00
int initmask ;
if ( inittype = = " x " ) {
initmask = 0x111 ;
} else if ( inittype = = " 0 " ) {
initmask = 0x333 ;
} else if ( inittype = = " 1 " ) {
initmask = 0x555 ;
} else if ( inittype = = " r " ) {
if ( srval = = 0 )
2025-09-11 07:25:26 +02:00
log_error ( " init type r not valid for cell type %s. \n " , celltype ) ;
2021-10-27 10:14:07 +02:00
initmask = 0x537 ;
} else if ( inittype = = " 01 " ) {
initmask = 0x777 ;
} else {
2025-09-11 07:25:26 +02:00
log_error ( " unrecognized init type %s for cell type %s. \n " , inittype , celltype ) ;
2021-10-27 10:14:07 +02:00
}
2020-06-23 14:36:34 +02:00
if ( srval = = ' 0 ' ) {
2021-10-27 10:14:07 +02:00
initmask & = 0x0ff ;
2020-06-23 14:36:34 +02:00
} else if ( srval = = ' 1 ' ) {
2021-10-27 10:14:07 +02:00
initmask & = 0xf0f ;
2020-06-23 14:36:34 +02:00
} else if ( srval ! = 0 & & srval ! = ' ? ' ) {
goto unrecognized ;
}
2021-10-27 10:14:07 +02:00
for ( int neg = 0 ; neg < NUM_NEG ; neg + + )
if ( ( neg & mask ) = = match )
supported_cells_neg [ ff_type ] [ neg ] | = initmask ;
supported_cells [ ff_type ] | = initmask ;
2020-06-23 14:36:34 +02:00
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 ] ;
2021-10-27 10:14:07 +02:00
supported_aldff = supported_cells [ FF_ALDFF ] | supported_cells [ FF_ALDFFE ] | supported_dffsr ;
supported_aldffe = supported_cells [ FF_ALDFFE ] | supported_cells [ FF_DFFSRE ] ;
supported_adff = supported_cells [ FF_ADFF ] | supported_cells [ FF_ADFFE ] | supported_dffsr | supported_aldff ;
supported_adffe = supported_cells [ FF_ADFFE ] | supported_cells [ FF_ALDFFE ] | supported_cells [ FF_DFFSRE ] ;
supported_sdff = supported_cells [ FF_SDFF ] | supported_cells [ FF_SDFFE ] | supported_cells [ FF_SDFFCE ] ;
supported_dff = supported_cells [ FF_DFF ] | supported_cells [ FF_DFFE ] | supported_adff | supported_sdff ;
supported_dffe = supported_cells [ FF_DFFE ] | supported_cells [ FF_DFFSRE ] | supported_cells [ FF_ALDFFE ] | supported_cells [ FF_ADFFE ] | supported_cells [ FF_SDFFE ] | supported_cells [ FF_SDFFCE ] ;
supported_sr_plain = supported_dffsr | supported_cells [ FF_DLATCHSR ] | supported_cells [ FF_SR ] ;
supported_sr = supported_sr_plain ;
supported_sr | = ( supported_cells [ FF_ADLATCH ] > > 4 & 7 ) * 0x111 ;
supported_sr | = ( flip_initmask ( supported_cells [ FF_ADLATCH ] ) > > 4 & 7 ) * 0x111 ;
supported_dlatch_plain = supported_cells [ FF_DLATCH ] | supported_cells [ FF_ADLATCH ] | supported_cells [ FF_DLATCHSR ] | supported_cells [ FF_ALDFF ] | supported_cells [ FF_ALDFFE ] ;
supported_dlatch = supported_dlatch_plain | supported_sr_plain ;
supported_rlatch = supported_adff | ( supported_dlatch & 7 ) * 0x111 ;
supported_adlatch = supported_cells [ FF_ADLATCH ] | supported_cells [ FF_DLATCHSR ] ;
2020-06-23 14:36:34 +02:00
for ( auto module : design - > selected_modules ( ) )
{
sigmap . set ( module ) ;
2020-07-19 02:04:38 +02:00
initvals . set ( & sigmap , module ) ;
2020-06-23 14:36:34 +02:00
if ( mince | | minsrst ) {
ce_used . clear ( ) ;
srst_used . clear ( ) ;
for ( auto cell : module - > cells ( ) ) {
2025-09-17 05:23:52 +02:00
if ( ! cell - > is_builtin_ff ( ) )
2020-06-23 14:36:34 +02:00
continue ;
2021-10-27 10:14:07 +02:00
FfData ff ( & initvals , cell ) ;
if ( ff . has_ce & & ff . sig_ce [ 0 ] . wire )
ce_used [ ff . sig_ce [ 0 ] ] + = ff . width ;
if ( ff . has_srst & & ff . sig_srst [ 0 ] . wire )
srst_used [ ff . sig_srst [ 0 ] ] + = ff . width ;
2020-06-23 14:36:34 +02:00
}
}
for ( auto cell : module - > selected_cells ( ) )
{
2025-09-17 05:23:52 +02:00
if ( ! cell - > is_builtin_ff ( ) )
2020-06-23 14:36:34 +02:00
continue ;
2021-10-27 10:14:07 +02:00
FfData ff ( & initvals , cell ) ;
legalize_ff ( ff ) ;
2020-06-23 14:36:34 +02:00
}
}
sigmap . clear ( ) ;
2020-07-19 02:04:38 +02:00
initvals . clear ( ) ;
2020-06-23 14:36:34 +02:00
ce_used . clear ( ) ;
srst_used . clear ( ) ;
}
} DffLegalizePass ;
PRIVATE_NAMESPACE_END