mirror of https://github.com/YosysHQ/abc.git
Merge pull request #283 from aletempiac/acd66
Boolean decomposition into LUT structures
This commit is contained in:
commit
4f0d09261b
2
Makefile
2
Makefile
|
|
@ -151,7 +151,7 @@ ifdef ABC_USE_LIBSTDCXX
|
|||
endif
|
||||
|
||||
$(info $(MSG_PREFIX)Using CFLAGS=$(CFLAGS))
|
||||
CXXFLAGS += $(CFLAGS) -std=c++17
|
||||
CXXFLAGS += $(CFLAGS) -std=c++11
|
||||
|
||||
SRC :=
|
||||
GARBAGE := core core.* *.stackdump ./tags $(PROG) arch_flags
|
||||
|
|
|
|||
|
|
@ -19514,7 +19514,7 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv )
|
|||
If_ManSetDefaultPars( pPars );
|
||||
pPars->pLutLib = (If_LibLut_t *)Abc_FrameReadLibLut();
|
||||
Extra_UtilGetoptReset();
|
||||
while ( ( c = Extra_UtilGetopt( argc, argv, "KCFAGRNTXYZDEWSqaflepmrsdbgxyzuojiktncvh" ) ) != EOF )
|
||||
while ( ( c = Extra_UtilGetopt( argc, argv, "KCFAGRNTXYZDEWSJqaflepmrsdbgxyuojiktncvh" ) ) != EOF )
|
||||
{
|
||||
switch ( c )
|
||||
{
|
||||
|
|
@ -19637,6 +19637,7 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv )
|
|||
goto usage;
|
||||
}
|
||||
pPars->nLutDecSize = atoi(argv[globalUtilOptind]);
|
||||
pPars->fUserLutDec = 1;
|
||||
globalUtilOptind++;
|
||||
if ( pPars->nLutDecSize < 3 || pPars->nLutDecSize > 6 )
|
||||
goto usage;
|
||||
|
|
@ -19688,6 +19689,21 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv )
|
|||
goto usage;
|
||||
}
|
||||
break;
|
||||
case 'J':
|
||||
if ( globalUtilOptind >= argc )
|
||||
{
|
||||
Abc_Print( -1, "Command line switch \"-J\" should be followed by string.\n" );
|
||||
goto usage;
|
||||
}
|
||||
pPars->pLutStruct = argv[globalUtilOptind];
|
||||
pPars->fEnableStructN = 1;
|
||||
globalUtilOptind++;
|
||||
if ( strlen(pPars->pLutStruct) != 2 && strlen(pPars->pLutStruct) != 3 )
|
||||
{
|
||||
Abc_Print( -1, "Command line switch \"-J\" should be followed by a 2- or 3-char string (e.g. \"66\" or \"666\").\n" );
|
||||
goto usage;
|
||||
}
|
||||
break;
|
||||
case 'q':
|
||||
pPars->fPreprocess ^= 1;
|
||||
break;
|
||||
|
|
@ -19730,9 +19746,6 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv )
|
|||
case 'y':
|
||||
pPars->fUserRecLib ^= 1;
|
||||
break;
|
||||
case 'z':
|
||||
pPars->fUserLutDec ^= 1;
|
||||
break;
|
||||
case 'u':
|
||||
pPars->fUserSesLib ^= 1;
|
||||
break;
|
||||
|
|
@ -19868,7 +19881,14 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv )
|
|||
Abc_Print( -1, "This feature only works for [6;16]-LUTs.\n" );
|
||||
return 1;
|
||||
}
|
||||
pPars->pFuncCell = pPars->fDelayOptLut ? NULL : If_CutPerformCheck16;
|
||||
if ( pPars->fEnableStructN )
|
||||
{
|
||||
pPars->pFuncCell = pPars->fDelayOptLut ? NULL : If_CutPerformCheck66;
|
||||
}
|
||||
else
|
||||
{
|
||||
pPars->pFuncCell = pPars->fDelayOptLut ? NULL : If_CutPerformCheck16;
|
||||
}
|
||||
pPars->fCutMin = 1;
|
||||
}
|
||||
|
||||
|
|
@ -19884,9 +19904,9 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv )
|
|||
Abc_Print( -1, "LUT size (%d) must be greater than the LUT decomposition size (%d).\n", pPars->nLutSize, pPars->nLutDecSize );
|
||||
return 1;
|
||||
}
|
||||
if ( pPars->nLutSize < 4 || pPars->nLutSize > 10 )
|
||||
if ( pPars->nLutSize < 4 || pPars->nLutSize > 11 )
|
||||
{
|
||||
Abc_Print( -1, "This feature only works for [4;10]-LUTs.\n" );
|
||||
Abc_Print( -1, "This feature only works for [4;11]-LUTs.\n" );
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -20053,7 +20073,7 @@ usage:
|
|||
sprintf(LutSize, "library" );
|
||||
else
|
||||
sprintf(LutSize, "%d", pPars->nLutSize );
|
||||
Abc_Print( -2, "usage: if [-KCFAGRNTXYZ num] [-DEW float] [-S str] [-qarlepmsdbgxyzuojiktncvh]\n" );
|
||||
Abc_Print( -2, "usage: if [-KCFAGRNTXYZ num] [-DEW float] [-S str] [-qarlepmsdbgxyuojiktncvh]\n" );
|
||||
Abc_Print( -2, "\t performs FPGA technology mapping of the network\n" );
|
||||
Abc_Print( -2, "\t-K num : the number of LUT inputs (2 < num < %d) [default = %s]\n", IF_MAX_LUTSIZE+1, LutSize );
|
||||
Abc_Print( -2, "\t-C num : the max number of priority cuts (0 < num < 2^12) [default = %d]\n", pPars->nCutsMax );
|
||||
|
|
@ -20065,11 +20085,12 @@ usage:
|
|||
Abc_Print( -2, "\t-T num : the type of LUT structures [default = any]\n" );
|
||||
Abc_Print( -2, "\t-X num : delay of AND-gate in LUT library units [default = %d]\n", pPars->nAndDelay );
|
||||
Abc_Print( -2, "\t-Y num : area of AND-gate in LUT library units [default = %d]\n", pPars->nAndArea );
|
||||
Abc_Print( -2, "\t-Z num : the number of LUT inputs for LUT decomposition [default = %d]\n", pPars->nLutDecSize );
|
||||
Abc_Print( -2, "\t-Z num : the number of LUT inputs for delay-driven LUT decomposition [default = not used]\n" );
|
||||
Abc_Print( -2, "\t-D float : sets the delay constraint for the mapping [default = %s]\n", Buffer );
|
||||
Abc_Print( -2, "\t-E float : sets epsilon used for tie-breaking [default = %f]\n", pPars->Epsilon );
|
||||
Abc_Print( -2, "\t-W float : sets wire delay between adjects LUTs [default = %f]\n", pPars->WireDelay );
|
||||
Abc_Print( -2, "\t-S str : string representing the LUT structure [default = %s]\n", pPars->pLutStruct ? pPars->pLutStruct : "not used" );
|
||||
Abc_Print( -2, "\t-J str : string representing the LUT structure (new method) [default = %s]\n", pPars->pLutStruct ? pPars->pLutStruct : "not used" );
|
||||
Abc_Print( -2, "\t-q : toggles preprocessing using several starting points [default = %s]\n", pPars->fPreprocess? "yes": "no" );
|
||||
Abc_Print( -2, "\t-a : toggles area-oriented mapping [default = %s]\n", pPars->fArea? "yes": "no" );
|
||||
Abc_Print( -2, "\t-r : enables expansion/reduction of the best cuts [default = %s]\n", pPars->fExpRed? "yes": "no" );
|
||||
|
|
@ -20083,7 +20104,6 @@ usage:
|
|||
Abc_Print( -2, "\t-g : toggles delay optimization by SOP balancing [default = %s]\n", pPars->fDelayOpt? "yes": "no" );
|
||||
Abc_Print( -2, "\t-x : toggles delay optimization by DSD balancing [default = %s]\n", pPars->fDsdBalance? "yes": "no" );
|
||||
Abc_Print( -2, "\t-y : toggles delay optimization with recorded library [default = %s]\n", pPars->fUserRecLib? "yes": "no" );
|
||||
Abc_Print( -2, "\t-z : toggles delay optimization with LUT decomposition [default = %s]\n", pPars->fUserLutDec? "yes": "no" );
|
||||
Abc_Print( -2, "\t-u : toggles delay optimization with SAT-based library [default = %s]\n", pPars->fUserSesLib? "yes": "no" );
|
||||
Abc_Print( -2, "\t-o : toggles using buffers to decouple combinational outputs [default = %s]\n", pPars->fUseBuffs? "yes": "no" );
|
||||
Abc_Print( -2, "\t-j : toggles enabling additional check [default = %s]\n", pPars->fEnableCheck07? "yes": "no" );
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ struct ac_decomposition_params
|
|||
bool support_reducing_only{ true };
|
||||
|
||||
/*! \brief Use the first feasible decomposition found. */
|
||||
bool use_first{ true };
|
||||
bool use_first{ false };
|
||||
|
||||
/*! \brief If decomposition with delay profile fails, try without. */
|
||||
bool try_no_late_arrival{ false };
|
||||
|
|
@ -90,7 +90,7 @@ private:
|
|||
};
|
||||
|
||||
private:
|
||||
static constexpr uint32_t max_num_vars = 10;
|
||||
static constexpr uint32_t max_num_vars = 11;
|
||||
using STT = kitty::static_truth_table<max_num_vars>;
|
||||
|
||||
public:
|
||||
|
|
@ -111,6 +111,16 @@ public:
|
|||
|
||||
uint32_t late_arriving = __builtin_popcount( delay_profile );
|
||||
|
||||
/* relax maximum number of free set variables if a function has more variables */
|
||||
if ( num_vars > ps.max_free_set_vars + ps.lut_size )
|
||||
{
|
||||
ps.max_free_set_vars = num_vars - ps.lut_size;
|
||||
}
|
||||
if ( late_arriving > ps.max_free_set_vars )
|
||||
{
|
||||
ps.max_free_set_vars = late_arriving;
|
||||
}
|
||||
|
||||
/* return a high cost if too many late arriving variables */
|
||||
if ( late_arriving > ps.lut_size - 1 || late_arriving > ps.max_free_set_vars )
|
||||
{
|
||||
|
|
@ -203,9 +213,11 @@ private:
|
|||
[this]( STT const& tt ) { return column_multiplicity5<5u>( tt ); } };
|
||||
|
||||
/* find a feasible AC decomposition */
|
||||
// for ( uint32_t i = std::min( ps.lut_size - 1, ps.max_free_set_vars); i >= start; --i )
|
||||
for ( uint32_t i = start; i <= ps.lut_size - 1 && i <= ps.max_free_set_vars; ++i )
|
||||
{
|
||||
auto [tt_p, perm, multiplicity] = enumerate_iset_combinations_offset( i, offset, column_multiplicity_fn[i - 1] );
|
||||
auto ret_tuple = enumerate_iset_combinations( i, offset, column_multiplicity_fn[i - 1] );
|
||||
uint32_t multiplicity = std::get<2>( ret_tuple );
|
||||
|
||||
/* additional cost if not support reducing */
|
||||
uint32_t additional_cost = ( num_vars - i > ps.lut_size ) ? 128 : 0;
|
||||
|
|
@ -213,24 +225,26 @@ private:
|
|||
/* check for feasible solution that improves the cost */
|
||||
if ( multiplicity <= ( 1 << ( ps.lut_size - i ) ) && multiplicity + additional_cost < best_cost && multiplicity <= 16 )
|
||||
{
|
||||
best_tt = tt_p;
|
||||
permutations = perm;
|
||||
best_tt = std::get<0>( ret_tuple );
|
||||
permutations = std::get<1>( ret_tuple );
|
||||
best_multiplicity = multiplicity;
|
||||
best_cost = multiplicity + additional_cost;
|
||||
best_free_set = i;
|
||||
|
||||
if ( ps.use_first )
|
||||
if ( !ps.use_first )
|
||||
{
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ( best_multiplicity == UINT32_MAX && ( !ps.try_no_late_arrival || late_arriving == 0 ) )
|
||||
return false;
|
||||
|
||||
/* try without the delay profile */
|
||||
if ( best_multiplicity == UINT32_MAX && ps.try_no_late_arrival )
|
||||
if ( best_multiplicity == UINT32_MAX )
|
||||
{
|
||||
delay_profile = 0;
|
||||
if ( ps.support_reducing_only )
|
||||
|
|
@ -240,7 +254,8 @@ private:
|
|||
|
||||
for ( uint32_t i = start; i <= ps.lut_size - 1 && i <= ps.max_free_set_vars; ++i )
|
||||
{
|
||||
auto [tt_p, perm, multiplicity] = enumerate_iset_combinations_offset( i, 0, column_multiplicity_fn[i - 1] );
|
||||
auto ret_tuple = enumerate_iset_combinations( i, 0, column_multiplicity_fn[i - 1] );
|
||||
uint32_t multiplicity = std::get<2>( ret_tuple );
|
||||
|
||||
/* additional cost if not support reducing */
|
||||
uint32_t additional_cost = ( num_vars - i > ps.lut_size ) ? 128 : 0;
|
||||
|
|
@ -248,17 +263,19 @@ private:
|
|||
/* check for feasible solution that improves the cost */
|
||||
if ( multiplicity <= ( 1 << ( ps.lut_size - i ) ) && multiplicity + additional_cost < best_cost && multiplicity <= 16 )
|
||||
{
|
||||
best_tt = tt_p;
|
||||
permutations = perm;
|
||||
best_tt = std::get<0>( ret_tuple );
|
||||
permutations = std::get<1>( ret_tuple );
|
||||
best_multiplicity = multiplicity;
|
||||
best_cost = multiplicity + additional_cost;
|
||||
best_free_set = i;
|
||||
|
||||
if ( ps.use_first )
|
||||
if ( !ps.use_first )
|
||||
{
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -285,11 +302,11 @@ private:
|
|||
best_tt._bits[i] = ptt[i];
|
||||
}
|
||||
|
||||
local_extend_to( best_tt, num_vars );
|
||||
// local_extend_to( best_tt, num_vars );
|
||||
}
|
||||
|
||||
template<uint32_t free_set_size>
|
||||
uint32_t column_multiplicity( STT tt )
|
||||
uint32_t column_multiplicity( STT const& tt )
|
||||
{
|
||||
uint64_t multiplicity_set[4] = { 0u, 0u, 0u, 0u };
|
||||
uint32_t multiplicity = 0;
|
||||
|
|
@ -298,23 +315,22 @@ private:
|
|||
uint64_t constexpr masks_idx[] = { 0x0, 0x0, 0x0, 0x3 };
|
||||
|
||||
/* supports up to 64 values of free set (256 for |FS| == 3)*/
|
||||
static_assert( free_set_size <= 3 );
|
||||
static_assert( free_set_size <= 3, "Wrong free set size for method used, expected le 3" );
|
||||
|
||||
/* extract iset functions */
|
||||
auto it = std::begin( tt );
|
||||
for ( auto i = 0u; i < num_blocks; ++i )
|
||||
{
|
||||
uint64_t cof = tt._bits[i];
|
||||
for ( auto j = 0; j < ( 64 >> free_set_size ); ++j )
|
||||
{
|
||||
multiplicity_set[( *it >> 6 ) & masks_idx[free_set_size]] |= UINT64_C( 1 ) << ( *it & masks_bits[free_set_size] );
|
||||
*it >>= ( 1u << free_set_size );
|
||||
multiplicity_set[( cof >> 6 ) & masks_idx[free_set_size]] |= UINT64_C( 1 ) << ( cof & masks_bits[free_set_size] );
|
||||
cof >>= ( 1u << free_set_size );
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
multiplicity = __builtin_popcountl( multiplicity_set[0] );
|
||||
|
||||
if constexpr ( free_set_size == 3 )
|
||||
if ( free_set_size == 3 )
|
||||
{
|
||||
multiplicity += __builtin_popcountl( multiplicity_set[1] );
|
||||
multiplicity += __builtin_popcountl( multiplicity_set[2] );
|
||||
|
|
@ -325,32 +341,31 @@ private:
|
|||
}
|
||||
|
||||
template<uint32_t free_set_size>
|
||||
uint32_t column_multiplicity5( STT tt )
|
||||
uint32_t column_multiplicity5( STT const& tt )
|
||||
{
|
||||
uint32_t const num_blocks = ( num_vars > 6 ) ? ( 1u << ( num_vars - 6 ) ) : 1;
|
||||
uint64_t constexpr masks[] = { 0x0, 0x3, 0xF, 0xFF, 0xFFFF, 0xFFFFFFFF };
|
||||
|
||||
static_assert( free_set_size == 5 || free_set_size == 4 );
|
||||
static_assert( free_set_size == 5 || free_set_size == 4, "Wrong free set size for method used, expected of 4 or 5" );
|
||||
|
||||
uint32_t size = 0;
|
||||
uint64_t prev = -1;
|
||||
std::array<uint32_t, 64> multiplicity_set;
|
||||
|
||||
/* extract iset functions */
|
||||
auto it = std::begin( tt );
|
||||
for ( auto i = 0u; i < num_blocks; ++i )
|
||||
{
|
||||
uint64_t cof = tt._bits[i];
|
||||
for ( auto j = 0; j < ( 64 >> free_set_size ); ++j )
|
||||
{
|
||||
uint64_t fs_fn = *it & masks[free_set_size];
|
||||
uint64_t fs_fn = cof & masks[free_set_size];
|
||||
if ( fs_fn != prev )
|
||||
{
|
||||
multiplicity_set[size++] = static_cast<uint32_t>( fs_fn );
|
||||
prev = fs_fn;
|
||||
}
|
||||
*it >>= ( 1u << free_set_size );
|
||||
cof >>= ( 1u << free_set_size );
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
std::sort( multiplicity_set.begin(), multiplicity_set.begin() + size );
|
||||
|
|
@ -365,6 +380,40 @@ private:
|
|||
return multiplicity;
|
||||
}
|
||||
|
||||
uint32_t column_multiplicity2( STT const& tt, uint32_t free_set_size )
|
||||
{
|
||||
assert( free_set_size <= 5 );
|
||||
|
||||
uint32_t const num_blocks = ( num_vars > 6 ) ? ( 1u << ( num_vars - 6 ) ) : 1;
|
||||
uint64_t const shift = UINT64_C( 1 ) << free_set_size;
|
||||
uint64_t const mask = ( UINT64_C( 1 ) << shift ) - 1;
|
||||
uint32_t cofactors[4];
|
||||
uint32_t size = 0;
|
||||
|
||||
/* extract iset functions */
|
||||
for ( auto i = 0u; i < num_blocks; ++i )
|
||||
{
|
||||
uint64_t sub = tt._bits[i];
|
||||
for ( auto j = 0; j < ( 64 >> free_set_size ); ++j )
|
||||
{
|
||||
uint32_t fs_fn = static_cast<uint32_t>( sub & mask );
|
||||
uint32_t k;
|
||||
for ( k = 0; k < size; ++k )
|
||||
{
|
||||
if ( fs_fn == cofactors[k] )
|
||||
break;
|
||||
}
|
||||
if ( k == 2 )
|
||||
return 3;
|
||||
if ( k == size )
|
||||
cofactors[size++] = fs_fn;
|
||||
sub >>= shift;
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
inline bool combinations_offset_next( uint32_t k, uint32_t offset, uint32_t* pComb, uint32_t* pInvPerm, STT& tt )
|
||||
{
|
||||
uint32_t i;
|
||||
|
|
@ -380,7 +429,7 @@ private:
|
|||
uint32_t pos_new = pInvPerm[var_old + 1];
|
||||
std::swap( pInvPerm[var_old + 1], pInvPerm[var_old] );
|
||||
std::swap( pComb[i], pComb[pos_new] );
|
||||
kitty::swap_inplace( tt, i, pos_new );
|
||||
swap_inplace_local( tt, i, pos_new );
|
||||
|
||||
for ( uint32_t j = i + 1; j < k; j++ )
|
||||
{
|
||||
|
|
@ -388,20 +437,20 @@ private:
|
|||
pos_new = pInvPerm[pComb[j - 1] + 1];
|
||||
std::swap( pInvPerm[pComb[j - 1] + 1], pInvPerm[var_old] );
|
||||
std::swap( pComb[j], pComb[pos_new] );
|
||||
kitty::swap_inplace( tt, j, pos_new );
|
||||
swap_inplace_local( tt, j, pos_new );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Fn>
|
||||
std::tuple<STT, std::array<uint32_t, max_num_vars>, uint32_t> enumerate_iset_combinations_offset( uint32_t free_set_size, uint32_t offset, Fn&& fn )
|
||||
std::tuple<STT, std::array<uint32_t, max_num_vars>, uint32_t> enumerate_iset_combinations( uint32_t free_set_size, uint32_t offset, Fn&& fn )
|
||||
{
|
||||
STT tt = best_tt;
|
||||
|
||||
/* TT with best cost */
|
||||
STT best_tt = tt;
|
||||
uint32_t best_cost = UINT32_MAX;
|
||||
STT local_best_tt = tt;
|
||||
uint32_t best_cost = ( 1 << ( ps.lut_size - free_set_size ) ) + 1;
|
||||
|
||||
assert( free_set_size >= offset );
|
||||
|
||||
|
|
@ -415,6 +464,12 @@ private:
|
|||
/* works up to 16 input truth tables */
|
||||
assert( num_vars <= 16 );
|
||||
|
||||
/* Search for column multiplicity of 2 */
|
||||
if ( free_set_size == ps.lut_size - 1 )
|
||||
{
|
||||
return enumerate_iset_combinations2( free_set_size, offset );
|
||||
}
|
||||
|
||||
/* init combinations */
|
||||
uint32_t pComb[16], pInvPerm[16], bestPerm[16];
|
||||
for ( uint32_t i = 0; i < num_vars; ++i )
|
||||
|
|
@ -428,7 +483,7 @@ private:
|
|||
uint32_t cost = fn( tt );
|
||||
if ( cost < best_cost )
|
||||
{
|
||||
best_tt = tt;
|
||||
local_best_tt = tt;
|
||||
best_cost = cost;
|
||||
for ( uint32_t i = 0; i < num_vars; ++i )
|
||||
{
|
||||
|
|
@ -438,12 +493,56 @@ private:
|
|||
} while ( combinations_offset_next( free_set_size, offset, pComb, pInvPerm, tt ) );
|
||||
|
||||
std::array<uint32_t, max_num_vars> res_perm;
|
||||
|
||||
if ( best_cost > ( 1 << ( ps.lut_size - free_set_size ) ) )
|
||||
{
|
||||
return std::make_tuple( local_best_tt, res_perm, UINT32_MAX );
|
||||
}
|
||||
|
||||
for ( uint32_t i = 0; i < num_vars; ++i )
|
||||
{
|
||||
res_perm[i] = permutations[bestPerm[i]];
|
||||
}
|
||||
|
||||
return std::make_tuple( best_tt, res_perm, best_cost );
|
||||
return std::make_tuple( local_best_tt, res_perm, best_cost );
|
||||
}
|
||||
|
||||
inline std::tuple<STT, std::array<uint32_t, max_num_vars>, uint32_t> enumerate_iset_combinations2( uint32_t free_set_size, uint32_t offset )
|
||||
{
|
||||
STT tt = best_tt;
|
||||
|
||||
/* TT with best cost */
|
||||
STT local_best_tt = tt;
|
||||
uint32_t best_cost = ( 1 << ( ps.lut_size - free_set_size ) ) + 1;
|
||||
|
||||
assert( free_set_size >= offset );
|
||||
|
||||
/* init combinations */
|
||||
uint32_t pComb[16], pInvPerm[16];
|
||||
for ( uint32_t i = 0; i < num_vars; ++i )
|
||||
{
|
||||
pComb[i] = pInvPerm[i] = i;
|
||||
}
|
||||
|
||||
/* enumerate combinations */
|
||||
std::array<uint32_t, max_num_vars> res_perm;
|
||||
|
||||
do
|
||||
{
|
||||
uint32_t cost = column_multiplicity2( tt, free_set_size );
|
||||
if ( cost <= 2 )
|
||||
{
|
||||
local_best_tt = tt;
|
||||
best_cost = cost;
|
||||
for ( uint32_t i = 0; i < num_vars; ++i )
|
||||
{
|
||||
res_perm[i] = permutations[pComb[i]];
|
||||
}
|
||||
return std::make_tuple( local_best_tt, res_perm, best_cost );
|
||||
}
|
||||
} while ( combinations_offset_next( free_set_size, offset, pComb, pInvPerm, tt ) );
|
||||
|
||||
return std::make_tuple( local_best_tt, res_perm, UINT32_MAX );
|
||||
}
|
||||
|
||||
std::vector<STT> compute_isets( bool verbose = false )
|
||||
|
|
@ -466,7 +565,8 @@ private:
|
|||
{
|
||||
uint64_t val = *it & masks[best_free_set];
|
||||
|
||||
if ( auto el = column_to_iset.find( val ); el != column_to_iset.end() )
|
||||
auto el = column_to_iset.find( val );
|
||||
if ( el != column_to_iset.end() )
|
||||
{
|
||||
isets[el->second]._bits[i / ( 1u << best_free_set )] |= UINT64_C( 1 ) << ( j + offset );
|
||||
}
|
||||
|
|
@ -479,7 +579,7 @@ private:
|
|||
*it >>= ( 1u << best_free_set );
|
||||
}
|
||||
|
||||
offset = ( offset + ( 64 >> best_free_set ) ) % 64;
|
||||
offset = ( offset + ( 64 >> best_free_set ) ) & 0x3F;
|
||||
++it;
|
||||
}
|
||||
|
||||
|
|
@ -650,7 +750,7 @@ private:
|
|||
}
|
||||
|
||||
std::swap( permutations[i], permutations[k] );
|
||||
kitty::swap_inplace( best_tt, i, k );
|
||||
swap_inplace_local( best_tt, i, k );
|
||||
++k;
|
||||
}
|
||||
}
|
||||
|
|
@ -709,7 +809,7 @@ private:
|
|||
{
|
||||
if ( var == best_multiplicity )
|
||||
{
|
||||
if constexpr ( !enable_dcset )
|
||||
if ( !enable_dcset )
|
||||
{
|
||||
/* sets must be equally populated */
|
||||
if ( __builtin_popcount( onset ) != __builtin_popcount( offset ) )
|
||||
|
|
@ -725,7 +825,7 @@ private:
|
|||
}
|
||||
|
||||
/* var in DCSET */
|
||||
if constexpr ( enable_dcset )
|
||||
if ( enable_dcset )
|
||||
{
|
||||
generate_support_minimization_encodings_rec<enable_dcset>( onset, offset, var + 1, count );
|
||||
}
|
||||
|
|
@ -953,7 +1053,7 @@ private:
|
|||
cost = 0;
|
||||
|
||||
float sort_cost = 0;
|
||||
if constexpr ( UseHeuristic )
|
||||
if ( UseHeuristic )
|
||||
{
|
||||
sort_cost = 1.0f / ( __builtin_popcountl( column[0] ) + __builtin_popcountl( column[1] ) );
|
||||
}
|
||||
|
|
@ -971,15 +1071,15 @@ private:
|
|||
return true;
|
||||
}
|
||||
|
||||
if constexpr ( UseHeuristic )
|
||||
if ( UseHeuristic )
|
||||
{
|
||||
std::sort( matrix.begin(), matrix.end(), [&]( auto const& a, auto const& b ) {
|
||||
std::sort( matrix.begin(), matrix.end(), [&]( encoding_column const& a, encoding_column const& b ) {
|
||||
return a.cost < b.cost;
|
||||
} );
|
||||
}
|
||||
else
|
||||
{
|
||||
std::sort( matrix.begin(), matrix.end(), [&]( auto const& a, auto const& b ) {
|
||||
std::sort( matrix.begin(), matrix.end(), [&]( encoding_column const& a, encoding_column const& b ) {
|
||||
return a.sort_cost < b.sort_cost;
|
||||
} );
|
||||
}
|
||||
|
|
@ -1231,6 +1331,66 @@ private:
|
|||
return false;
|
||||
}
|
||||
|
||||
void swap_inplace_local( STT& tt, uint8_t var_index1, uint8_t var_index2 )
|
||||
{
|
||||
if ( var_index1 == var_index2 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( var_index1 > var_index2 )
|
||||
{
|
||||
std::swap( var_index1, var_index2 );
|
||||
}
|
||||
|
||||
assert( num_vars > 6 );
|
||||
const uint32_t num_blocks = 1 << ( num_vars - 6 );
|
||||
|
||||
if ( var_index2 <= 5 )
|
||||
{
|
||||
const auto& pmask = kitty::detail::ppermutation_masks[var_index1][var_index2];
|
||||
const auto shift = ( 1 << var_index2 ) - ( 1 << var_index1 );
|
||||
std::transform( std::begin( tt._bits ), std::begin( tt._bits ) + num_blocks, std::begin( tt._bits ),
|
||||
[shift, &pmask]( uint64_t word ) {
|
||||
return ( word & pmask[0] ) | ( ( word & pmask[1] ) << shift ) | ( ( word & pmask[2] ) >> shift );
|
||||
} );
|
||||
}
|
||||
else if ( var_index1 <= 5 ) /* in this case, var_index2 > 5 */
|
||||
{
|
||||
const auto step = 1 << ( var_index2 - 6 );
|
||||
const auto shift = 1 << var_index1;
|
||||
auto it = std::begin( tt._bits );
|
||||
while ( it != std::begin( tt._bits ) + num_blocks )
|
||||
{
|
||||
for ( auto i = decltype( step ){ 0 }; i < step; ++i )
|
||||
{
|
||||
const auto low_to_high = ( *( it + i ) & kitty::detail::projections[var_index1] ) >> shift;
|
||||
const auto high_to_low = ( *( it + i + step ) << shift ) & kitty::detail::projections[var_index1];
|
||||
*( it + i ) = ( *( it + i ) & ~kitty::detail::projections[var_index1] ) | high_to_low;
|
||||
*( it + i + step ) = ( *( it + i + step ) & kitty::detail::projections[var_index1] ) | low_to_high;
|
||||
}
|
||||
it += 2 * step;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto step1 = 1 << ( var_index1 - 6 );
|
||||
const auto step2 = 1 << ( var_index2 - 6 );
|
||||
auto it = std::begin( tt._bits );
|
||||
while ( it != std::begin( tt._bits ) + num_blocks )
|
||||
{
|
||||
for ( auto i = 0; i < step2; i += 2 * step1 )
|
||||
{
|
||||
for ( auto j = 0; j < step1; ++j )
|
||||
{
|
||||
std::swap( *( it + i + j + step1 ), *( it + i + j + step2 ) );
|
||||
}
|
||||
}
|
||||
it += 2 * step2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Decomposition format for ABC
|
||||
*
|
||||
* The record is an array of unsigned chars where:
|
||||
|
|
@ -1298,7 +1458,7 @@ private:
|
|||
std::vector<std::array<uint32_t, 2>> support_minimization_encodings;
|
||||
|
||||
uint32_t num_vars;
|
||||
ac_decomposition_params const& ps;
|
||||
ac_decomposition_params ps;
|
||||
ac_decomposition_stats* pst;
|
||||
std::array<uint32_t, max_num_vars> permutations;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -18,55 +18,158 @@
|
|||
|
||||
#include "ac_wrapper.h"
|
||||
#include "ac_decomposition.hpp"
|
||||
#include "acd66.hpp"
|
||||
#include "acd666.hpp"
|
||||
|
||||
ABC_NAMESPACE_IMPL_START
|
||||
|
||||
static constexpr bool use_generic_acd = true;
|
||||
|
||||
int acd_evaluate( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned *cost, int try_no_late_arrival )
|
||||
{
|
||||
using namespace acd;
|
||||
|
||||
ac_decomposition_params ps;
|
||||
ps.lut_size = lutSize;
|
||||
ps.try_no_late_arrival = static_cast<bool>( try_no_late_arrival ); /* TODO: additional tests */
|
||||
ac_decomposition_stats st;
|
||||
|
||||
ac_decomposition_impl acd( nVars, ps, &st );
|
||||
int val = acd.run( pTruth, *pdelay );
|
||||
|
||||
if ( val < 0 )
|
||||
if ( use_generic_acd )
|
||||
{
|
||||
*pdelay = 0;
|
||||
return -1;
|
||||
ac_decomposition_params ps;
|
||||
ps.lut_size = lutSize;
|
||||
ps.use_first = false;
|
||||
ps.try_no_late_arrival = static_cast<bool>( try_no_late_arrival );
|
||||
ac_decomposition_stats st;
|
||||
|
||||
ac_decomposition_impl acd( nVars, ps, &st );
|
||||
int val = acd.run( pTruth, *pdelay );
|
||||
|
||||
if ( val < 0 )
|
||||
{
|
||||
*pdelay = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*pdelay = acd.get_profile();
|
||||
*cost = st.num_luts;
|
||||
|
||||
return val;
|
||||
}
|
||||
else
|
||||
{
|
||||
acd66_impl acd( nVars );
|
||||
int val = acd.run( pTruth, *pdelay );
|
||||
|
||||
*pdelay = acd.get_profile();
|
||||
*cost = st.num_luts;
|
||||
if ( val == 0 )
|
||||
{
|
||||
*pdelay = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return val;
|
||||
*pdelay = acd.get_profile();
|
||||
*cost = 2;
|
||||
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
int acd_decompose( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned char *decomposition )
|
||||
{
|
||||
using namespace acd;
|
||||
|
||||
ac_decomposition_params ps;
|
||||
ps.lut_size = lutSize;
|
||||
ac_decomposition_stats st;
|
||||
|
||||
ac_decomposition_impl acd( nVars, ps, &st );
|
||||
acd.run( pTruth, *pdelay );
|
||||
int val = acd.compute_decomposition();
|
||||
|
||||
if ( val < 0 )
|
||||
if ( use_generic_acd )
|
||||
{
|
||||
*pdelay = 0;
|
||||
return -1;
|
||||
ac_decomposition_params ps;
|
||||
ps.lut_size = lutSize;
|
||||
ps.use_first = true;
|
||||
ac_decomposition_stats st;
|
||||
|
||||
ac_decomposition_impl acd( nVars, ps, &st );
|
||||
acd.run( pTruth, *pdelay );
|
||||
int val = acd.compute_decomposition();
|
||||
|
||||
if ( val < 0 )
|
||||
{
|
||||
*pdelay = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*pdelay = acd.get_profile();
|
||||
acd.get_decomposition( decomposition );
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
acd66_impl acd( nVars );
|
||||
acd.run( pTruth, *pdelay );
|
||||
int val = acd.compute_decomposition();
|
||||
|
||||
if ( val != 0 )
|
||||
{
|
||||
*pdelay = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*pdelay = acd.get_profile();
|
||||
|
||||
acd.get_decomposition( decomposition );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int acd66_evaluate( word * pTruth, unsigned nVars, int compute_decomposition )
|
||||
{
|
||||
using namespace acd;
|
||||
|
||||
acd66_impl acd( nVars, true, false );
|
||||
|
||||
if ( acd.run( pTruth ) == 0 )
|
||||
return 0;
|
||||
|
||||
if ( !compute_decomposition )
|
||||
return 1;
|
||||
|
||||
int val = acd.compute_decomposition();
|
||||
if ( val != 0 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
*pdelay = acd.get_profile();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int acd66_decompose( word * pTruth, unsigned nVars, unsigned char *decomposition )
|
||||
{
|
||||
using namespace acd;
|
||||
|
||||
acd66_impl acd( nVars, true, false );
|
||||
acd.run( pTruth );
|
||||
|
||||
int val = acd.compute_decomposition();
|
||||
if ( val != 0 )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
acd.get_decomposition( decomposition );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int acd666_evaluate( word * pTruth, unsigned nVars, int compute_decomposition )
|
||||
{
|
||||
using namespace acd;
|
||||
|
||||
acd666_impl acd( nVars, false );
|
||||
|
||||
if ( acd.run( pTruth ) == 0 )
|
||||
return 0;
|
||||
|
||||
if ( !compute_decomposition )
|
||||
return 1;
|
||||
|
||||
int val = acd.compute_decomposition();
|
||||
if ( val != 0 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
|
|
|||
|
|
@ -28,6 +28,11 @@ ABC_NAMESPACE_HEADER_START
|
|||
int acd_evaluate( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned *cost, int try_no_late_arrival );
|
||||
int acd_decompose( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned char *decomposition );
|
||||
|
||||
int acd66_evaluate( word * pTruth, unsigned nVars, int compute_decomposition );
|
||||
int acd66_decompose( word * pTruth, unsigned nVars, unsigned char *decomposition );
|
||||
|
||||
int acd666_evaluate( word * pTruth, unsigned nVars, int compute_decomposition );
|
||||
|
||||
ABC_NAMESPACE_HEADER_END
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -22,9 +22,9 @@ namespace kitty
|
|||
\return new constructed truth table of same type and dimensions
|
||||
*/
|
||||
template<typename TT, typename Fn>
|
||||
auto unary_operation( const TT& tt, Fn&& op )
|
||||
TT unary_operation( const TT& tt, Fn&& op )
|
||||
{
|
||||
auto result = tt.construct();
|
||||
TT result = tt.construct();
|
||||
std::transform( tt.cbegin(), tt.cend(), result.begin(), op );
|
||||
result.mask_bits();
|
||||
return result;
|
||||
|
|
@ -43,11 +43,11 @@ auto unary_operation( const TT& tt, Fn&& op )
|
|||
\return new constructed truth table of same type and dimensions
|
||||
*/
|
||||
template<typename TT, typename Fn>
|
||||
auto binary_operation( const TT& first, const TT& second, Fn&& op )
|
||||
TT binary_operation( const TT& first, const TT& second, Fn&& op )
|
||||
{
|
||||
assert( first.num_vars() == second.num_vars() );
|
||||
|
||||
auto result = first.construct();
|
||||
TT result = first.construct();
|
||||
std::transform( first.cbegin(), first.cend(), second.cbegin(), result.begin(), op );
|
||||
result.mask_bits();
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -51,55 +51,55 @@ struct dynamic_truth_table
|
|||
|
||||
/*! Returns number of variables.
|
||||
*/
|
||||
inline auto num_vars() const noexcept { return _num_vars; }
|
||||
inline uint32_t num_vars() const noexcept { return _num_vars; }
|
||||
|
||||
/*! Returns number of blocks.
|
||||
*/
|
||||
inline auto num_blocks() const noexcept { return _bits.size(); }
|
||||
inline uint32_t num_blocks() const noexcept { return _bits.size(); }
|
||||
|
||||
/*! Returns number of bits.
|
||||
*/
|
||||
inline auto num_bits() const noexcept { return uint64_t( 1 ) << _num_vars; }
|
||||
inline uint32_t num_bits() const noexcept { return uint64_t( 1 ) << _num_vars; }
|
||||
|
||||
/*! \brief Begin iterator to bits.
|
||||
*/
|
||||
inline auto begin() noexcept { return _bits.begin(); }
|
||||
inline std::vector<uint64_t>::iterator begin() noexcept { return _bits.begin(); }
|
||||
|
||||
/*! \brief End iterator to bits.
|
||||
*/
|
||||
inline auto end() noexcept { return _bits.end(); }
|
||||
inline std::vector<uint64_t>::iterator end() noexcept { return _bits.end(); }
|
||||
|
||||
/*! \brief Begin iterator to bits.
|
||||
*/
|
||||
inline auto begin() const noexcept { return _bits.begin(); }
|
||||
inline std::vector<uint64_t>::const_iterator begin() const noexcept { return _bits.begin(); }
|
||||
|
||||
/*! \brief End iterator to bits.
|
||||
*/
|
||||
inline auto end() const noexcept { return _bits.end(); }
|
||||
inline std::vector<uint64_t>::const_iterator end() const noexcept { return _bits.end(); }
|
||||
|
||||
/*! \brief Reverse begin iterator to bits.
|
||||
*/
|
||||
inline auto rbegin() noexcept { return _bits.rbegin(); }
|
||||
inline std::vector<uint64_t>::reverse_iterator rbegin() noexcept { return _bits.rbegin(); }
|
||||
|
||||
/*! \brief Reverse end iterator to bits.
|
||||
*/
|
||||
inline auto rend() noexcept { return _bits.rend(); }
|
||||
inline std::vector<uint64_t>::reverse_iterator rend() noexcept { return _bits.rend(); }
|
||||
|
||||
/*! \brief Constant begin iterator to bits.
|
||||
*/
|
||||
inline auto cbegin() const noexcept { return _bits.cbegin(); }
|
||||
inline std::vector<uint64_t>::const_iterator cbegin() const noexcept { return _bits.cbegin(); }
|
||||
|
||||
/*! \brief Constant end iterator to bits.
|
||||
*/
|
||||
inline auto cend() const noexcept { return _bits.cend(); }
|
||||
inline std::vector<uint64_t>::const_iterator cend() const noexcept { return _bits.cend(); }
|
||||
|
||||
/*! \brief Constant reverse begin iterator to bits.
|
||||
*/
|
||||
inline auto crbegin() const noexcept { return _bits.crbegin(); }
|
||||
inline std::vector<uint64_t>::const_reverse_iterator crbegin() const noexcept { return _bits.crbegin(); }
|
||||
|
||||
/*! \brief Constant teverse end iterator to bits.
|
||||
*/
|
||||
inline auto crend() const noexcept { return _bits.crend(); }
|
||||
inline std::vector<uint64_t>::const_reverse_iterator crend() const noexcept { return _bits.crend(); }
|
||||
|
||||
/*! \brief Assign other truth table.
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ inline TT unary_not_if( const TT& tt, bool cond )
|
|||
#ifdef _MSC_VER
|
||||
#pragma warning( pop )
|
||||
#endif
|
||||
return unary_operation( tt, [mask]( auto a )
|
||||
return unary_operation( tt, [mask]( uint64_t a )
|
||||
{ return a ^ mask; } );
|
||||
}
|
||||
|
||||
|
|
@ -39,7 +39,7 @@ inline TT unary_not_if( const TT& tt, bool cond )
|
|||
template<typename TT>
|
||||
inline TT unary_not( const TT& tt )
|
||||
{
|
||||
return unary_operation( tt, []( auto a )
|
||||
return unary_operation( tt, []( uint64_t a )
|
||||
{ return ~a; } );
|
||||
}
|
||||
|
||||
|
|
@ -48,14 +48,14 @@ template<typename TT>
|
|||
|
||||
inline TT binary_and( const TT& first, const TT& second )
|
||||
{
|
||||
return binary_operation( first, second, std::bit_and<>() );
|
||||
return binary_operation( first, second, std::bit_and<uint64_t>() );
|
||||
}
|
||||
|
||||
/*! \brief Bitwise OR of two truth tables */
|
||||
template<typename TT>
|
||||
inline TT binary_or( const TT& first, const TT& second )
|
||||
{
|
||||
return binary_operation( first, second, std::bit_or<>() );
|
||||
return binary_operation( first, second, std::bit_or<uint64_t>() );
|
||||
}
|
||||
|
||||
/*! \brief Swaps two variables in a truth table
|
||||
|
|
@ -133,6 +133,24 @@ void swap_inplace( TT& tt, uint8_t var_index1, uint8_t var_index2 )
|
|||
}
|
||||
}
|
||||
|
||||
template<uint32_t NumVars>
|
||||
inline void swap_inplace( static_truth_table<NumVars, true>& tt, uint8_t var_index1, uint8_t var_index2 )
|
||||
{
|
||||
if ( var_index1 == var_index2 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( var_index1 > var_index2 )
|
||||
{
|
||||
std::swap( var_index1, var_index2 );
|
||||
}
|
||||
|
||||
const auto& pmask = detail::ppermutation_masks[var_index1][var_index2];
|
||||
const auto shift = ( 1 << var_index2 ) - ( 1 << var_index1 );
|
||||
tt._bits = ( tt._bits & pmask[0] ) | ( ( tt._bits & pmask[1] ) << shift ) | ( ( tt._bits & pmask[2] ) >> shift );
|
||||
}
|
||||
|
||||
/*! \brief Extends smaller truth table to larger one
|
||||
|
||||
The most significant variables will not be in the functional support of the
|
||||
|
|
@ -312,7 +330,7 @@ void print_hex( const TT& tt, std::ostream& os = std::cout )
|
|||
auto const chunk_size =
|
||||
std::min<uint64_t>( tt.num_vars() <= 1 ? 1 : ( tt.num_bits() >> 2 ), 16 );
|
||||
|
||||
for_each_block_reversed( tt, [&os, chunk_size]( auto word )
|
||||
for_each_block_reversed( tt, [&os, chunk_size]( uint64_t word )
|
||||
{
|
||||
std::string chunk( chunk_size, '0' );
|
||||
|
||||
|
|
|
|||
|
|
@ -78,28 +78,33 @@ inline void operator|=( dynamic_truth_table& first, const dynamic_truth_table& s
|
|||
|
||||
/*! \brief Operator for binary_or and assign */
|
||||
template<uint32_t NumVars>
|
||||
inline void operator|=( static_truth_table<NumVars>& first, const static_truth_table<NumVars>& second )
|
||||
inline void operator|=( static_truth_table<NumVars, true>& first, const static_truth_table<NumVars, true>& second )
|
||||
{
|
||||
// first = binary_or( first, second );
|
||||
/* runtime improved version */
|
||||
if constexpr ( NumVars <= 6 )
|
||||
{
|
||||
first._bits |= second._bits;
|
||||
first.mask_bits();
|
||||
}
|
||||
else if constexpr ( NumVars == 7 )
|
||||
first._bits |= second._bits;
|
||||
first.mask_bits();
|
||||
}
|
||||
|
||||
/*! \brief Operator for binary_or and assign */
|
||||
template<uint32_t NumVars>
|
||||
inline void operator|=( static_truth_table<NumVars, false>& first, const static_truth_table<NumVars, false>& second )
|
||||
{
|
||||
// first = binary_or( first, second );
|
||||
/* runtime improved version */
|
||||
if ( NumVars == 7 )
|
||||
{
|
||||
first._bits[0] |= second._bits[0];
|
||||
first._bits[1] |= second._bits[1];
|
||||
}
|
||||
else if constexpr ( NumVars == 8 )
|
||||
else if ( NumVars == 8 )
|
||||
{
|
||||
first._bits[0] |= second._bits[0];
|
||||
first._bits[1] |= second._bits[1];
|
||||
first._bits[2] |= second._bits[2];
|
||||
first._bits[3] |= second._bits[3];
|
||||
}
|
||||
else if constexpr ( NumVars == 9 )
|
||||
else if ( NumVars == 9 )
|
||||
{
|
||||
first._bits[0] |= second._bits[0];
|
||||
first._bits[1] |= second._bits[1];
|
||||
|
|
|
|||
|
|
@ -12,8 +12,116 @@ ABC_NAMESPACE_CXX_HEADER_START
|
|||
namespace kitty
|
||||
{
|
||||
|
||||
template<uint32_t NumVars, bool = ( NumVars <= 6 )>
|
||||
struct static_truth_table;
|
||||
|
||||
/*! Truth table (for up to 6 variables) in which number of variables is known at compile time.
|
||||
*/
|
||||
template<uint32_t NumVars>
|
||||
struct static_truth_table
|
||||
struct static_truth_table<NumVars, true>
|
||||
{
|
||||
/*! \cond PRIVATE */
|
||||
enum
|
||||
{
|
||||
NumBits = uint64_t( 1 ) << NumVars
|
||||
};
|
||||
/*! \endcond */
|
||||
|
||||
/*! Constructs a new static truth table instance with the same number of variables. */
|
||||
inline static_truth_table<NumVars> construct() const
|
||||
{
|
||||
return static_truth_table<NumVars>();
|
||||
}
|
||||
|
||||
/*! Returns number of variables.
|
||||
*/
|
||||
inline uint32_t num_vars() const noexcept { return NumVars; }
|
||||
|
||||
/*! Returns number of blocks.
|
||||
*/
|
||||
inline uint32_t num_blocks() const noexcept { return 1u; }
|
||||
|
||||
/*! Returns number of bits.
|
||||
*/
|
||||
inline uint32_t num_bits() const noexcept { return NumBits; }
|
||||
|
||||
/*! \brief Begin iterator to bits.
|
||||
*/
|
||||
inline uint64_t * begin() noexcept { return &_bits; }
|
||||
|
||||
/*! \brief End iterator to bits.
|
||||
*/
|
||||
inline uint64_t * end() noexcept { return ( &_bits ) + 1; }
|
||||
|
||||
/*! \brief Begin iterator to bits.
|
||||
*/
|
||||
inline const uint64_t * begin() const noexcept { return &_bits; }
|
||||
|
||||
/*! \brief End iterator to bits.
|
||||
*/
|
||||
inline const uint64_t * end() const noexcept { return ( &_bits ) + 1; }
|
||||
|
||||
/*! \brief Reverse begin iterator to bits.
|
||||
*/
|
||||
inline uint64_t * rbegin() noexcept { return &_bits; }
|
||||
|
||||
/*! \brief Reverse end iterator to bits.
|
||||
*/
|
||||
inline uint64_t * rend() noexcept { return ( &_bits ) + 1; }
|
||||
|
||||
/*! \brief Constant begin iterator to bits.
|
||||
*/
|
||||
inline const uint64_t * cbegin() const noexcept { return &_bits; }
|
||||
|
||||
/*! \brief Constant end iterator to bits.
|
||||
*/
|
||||
inline const uint64_t * cend() const noexcept { return ( &_bits ) + 1; }
|
||||
|
||||
/*! \brief Constant reverse begin iterator to bits.
|
||||
*/
|
||||
inline const uint64_t * crbegin() const noexcept { return &_bits; }
|
||||
|
||||
/*! \brief Constant everse end iterator to bits.
|
||||
*/
|
||||
inline const uint64_t * crend() const noexcept { return ( &_bits ) + 1; }
|
||||
|
||||
/*! \brief Assign other truth table if number of variables match.
|
||||
|
||||
This replaces the current truth table with another truth table, if `other`
|
||||
has the same number of variables. Otherwise, the truth table is not
|
||||
changed.
|
||||
|
||||
\param other Other truth table
|
||||
*/
|
||||
template<class TT>
|
||||
static_truth_table<NumVars>& operator=( const TT& other )
|
||||
{
|
||||
if ( other.num_vars() == num_vars() )
|
||||
{
|
||||
std::copy( other.begin(), other.end(), begin() );
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*! Masks the number of valid truth table bits.
|
||||
|
||||
If the truth table has less than 6 variables, it may not use all
|
||||
the bits. This operation makes sure to zero out all non-valid
|
||||
bits.
|
||||
*/
|
||||
inline void mask_bits() noexcept { _bits &= detail::masks[NumVars]; }
|
||||
|
||||
/*! \cond PRIVATE */
|
||||
public: /* fields */
|
||||
uint64_t _bits = 0;
|
||||
/*! \endcond */
|
||||
};
|
||||
|
||||
/*! Truth table (more than 6 variables) in which number of variables is known at compile time.
|
||||
*/
|
||||
template<uint32_t NumVars>
|
||||
struct static_truth_table<NumVars, false>
|
||||
{
|
||||
/*! \cond PRIVATE */
|
||||
enum
|
||||
|
|
@ -46,55 +154,55 @@ struct static_truth_table
|
|||
|
||||
/*! Returns number of variables.
|
||||
*/
|
||||
inline auto num_vars() const noexcept { return NumVars; }
|
||||
inline uint32_t num_vars() const noexcept { return NumVars; }
|
||||
|
||||
/*! Returns number of blocks.
|
||||
*/
|
||||
inline auto num_blocks() const noexcept { return NumBlocks; }
|
||||
inline uint32_t num_blocks() const noexcept { return NumBlocks; }
|
||||
|
||||
/*! Returns number of bits.
|
||||
*/
|
||||
inline auto num_bits() const noexcept { return NumBits; }
|
||||
inline uint32_t num_bits() const noexcept { return NumBits; }
|
||||
|
||||
/*! \brief Begin iterator to bits.
|
||||
*/
|
||||
inline auto begin() noexcept { return _bits.begin(); }
|
||||
inline typename std::array<uint64_t, NumBlocks>::iterator begin() noexcept { return _bits.begin(); }
|
||||
|
||||
/*! \brief End iterator to bits.
|
||||
*/
|
||||
inline auto end() noexcept { return _bits.end(); }
|
||||
inline typename std::array<uint64_t, NumBlocks>::iterator end() noexcept { return _bits.end(); }
|
||||
|
||||
/*! \brief Begin iterator to bits.
|
||||
*/
|
||||
inline auto begin() const noexcept { return _bits.begin(); }
|
||||
inline typename std::array<uint64_t, NumBlocks>::const_iterator begin() const noexcept { return _bits.begin(); }
|
||||
|
||||
/*! \brief End iterator to bits.
|
||||
*/
|
||||
inline auto end() const noexcept { return _bits.end(); }
|
||||
inline typename std::array<uint64_t, NumBlocks>::const_iterator end() const noexcept { return _bits.end(); }
|
||||
|
||||
/*! \brief Reverse begin iterator to bits.
|
||||
*/
|
||||
inline auto rbegin() noexcept { return _bits.rbegin(); }
|
||||
inline typename std::array<uint64_t, NumBlocks>::reverse_iterator rbegin() noexcept { return _bits.rbegin(); }
|
||||
|
||||
/*! \brief Reverse end iterator to bits.
|
||||
*/
|
||||
inline auto rend() noexcept { return _bits.rend(); }
|
||||
inline typename std::array<uint64_t, NumBlocks>::reverse_iterator rend() noexcept { return _bits.rend(); }
|
||||
|
||||
/*! \brief Constant begin iterator to bits.
|
||||
*/
|
||||
inline auto cbegin() const noexcept { return _bits.cbegin(); }
|
||||
inline typename std::array<uint64_t, NumBlocks>::const_iterator cbegin() const noexcept { return _bits.cbegin(); }
|
||||
|
||||
/*! \brief Constant end iterator to bits.
|
||||
*/
|
||||
inline auto cend() const noexcept { return _bits.cend(); }
|
||||
inline typename std::array<uint64_t, NumBlocks>::const_iterator cend() const noexcept { return _bits.cend(); }
|
||||
|
||||
/*! \brief Constant reverse begin iterator to bits.
|
||||
*/
|
||||
inline auto crbegin() const noexcept { return _bits.crbegin(); }
|
||||
inline typename std::array<uint64_t, NumBlocks>::const_reverse_iterator crbegin() const noexcept { return _bits.crbegin(); }
|
||||
|
||||
/*! \brief Constant teverse end iterator to bits.
|
||||
*/
|
||||
inline auto crend() const noexcept { return _bits.crend(); }
|
||||
inline typename std::array<uint64_t, NumBlocks>::const_reverse_iterator crend() const noexcept { return _bits.crend(); }
|
||||
|
||||
/*! \brief Assign other truth table if number of variables match.
|
||||
|
||||
|
|
|
|||
|
|
@ -151,6 +151,7 @@ struct If_Par_t_
|
|||
int fVerbose; // the verbosity flag
|
||||
int fVerboseTrace; // the verbosity flag
|
||||
char * pLutStruct; // LUT structure
|
||||
int fEnableStructN;// LUT structure using a new method
|
||||
float WireDelay; // wire delay
|
||||
// internal parameters
|
||||
int fSkipCutFilter;// skip cut filter
|
||||
|
|
@ -551,6 +552,7 @@ extern int If_CutPerformCheck07( If_Man_t * p, unsigned * pTruth, in
|
|||
extern int If_CutPerformCheck08( If_Man_t * p, unsigned * pTruth, int nVars, int nLeaves, char * pStr );
|
||||
extern int If_CutPerformCheck10( If_Man_t * p, unsigned * pTruth, int nVars, int nLeaves, char * pStr );
|
||||
extern int If_CutPerformCheck16( If_Man_t * p, unsigned * pTruth, int nVars, int nLeaves, char * pStr );
|
||||
extern int If_CutPerformCheck66( If_Man_t * p, unsigned * pTruth, int nVars, int nLeaves, char * pStr );
|
||||
extern int If_CutPerformCheck45( If_Man_t * p, unsigned * pTruth, int nVars, int nLeaves, char * pStr );
|
||||
extern int If_CutPerformCheck54( If_Man_t * p, unsigned * pTruth, int nVars, int nLeaves, char * pStr );
|
||||
extern int If_CutPerformCheck75( If_Man_t * p, unsigned * pTruth, int nVars, int nLeaves, char * pStr );
|
||||
|
|
|
|||
|
|
@ -0,0 +1,366 @@
|
|||
/**CFile****************************************************************
|
||||
|
||||
FileName [ifDec66.c]
|
||||
|
||||
SystemName [ABC: Logic synthesis and verification system.]
|
||||
|
||||
PackageName [FPGA mapping based on priority cuts.]
|
||||
|
||||
Synopsis [Fast checking procedures.]
|
||||
|
||||
Author [Alessandro Tempia Calvino]
|
||||
|
||||
Affiliation [EPFL]
|
||||
|
||||
Date [Ver. 1.0. Started - Feb 8, 2024.]
|
||||
|
||||
Revision [$Id: ifDec66.c,v 1.00 2008/02/08 00:00:00 tempia Exp $]
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#include "if.h"
|
||||
#include "bool/kit/kit.h"
|
||||
#include "misc/vec/vecMem.h"
|
||||
|
||||
ABC_NAMESPACE_IMPL_START
|
||||
|
||||
#define CLU_VAR_MAX 16
|
||||
#define CLU_MEM_MAX 1000 // 1 GB
|
||||
#define CLU_UNUSED 0xff
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
/// DECLARATIONS ///
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// decomposition
|
||||
typedef struct If_Grp_t_ If_Grp_t;
|
||||
struct If_Grp_t_
|
||||
{
|
||||
char nVars;
|
||||
char nMyu;
|
||||
char pVars[CLU_VAR_MAX];
|
||||
};
|
||||
|
||||
// hash table entry
|
||||
typedef struct If_Hte_t_ If_Hte_t;
|
||||
struct If_Hte_t_
|
||||
{
|
||||
If_Hte_t * pNext;
|
||||
unsigned Group;
|
||||
unsigned Counter;
|
||||
word pTruth[1];
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
/// FUNCTION DEFINITIONS ///
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline unsigned If_CluGrp2Uns2( If_Grp_t * pG )
|
||||
{
|
||||
char * pChar = (char *)pG;
|
||||
unsigned Res = 0;
|
||||
int i;
|
||||
for ( i = 0; i < 8; i++ )
|
||||
Res |= ((pChar[i] & 15) << (i << 2));
|
||||
return Res;
|
||||
}
|
||||
|
||||
static inline void If_CluUns2Grp2( unsigned Group, If_Grp_t * pG )
|
||||
{
|
||||
char * pChar = (char *)pG;
|
||||
int i;
|
||||
for ( i = 0; i < 8; i++ )
|
||||
pChar[i] = ((Group >> (i << 2)) & 15);
|
||||
}
|
||||
|
||||
unsigned int If_CluPrimeCudd2( unsigned int p )
|
||||
{
|
||||
int i,pn;
|
||||
|
||||
p--;
|
||||
do {
|
||||
p++;
|
||||
if (p&1) {
|
||||
pn = 1;
|
||||
i = 3;
|
||||
while ((unsigned) (i * i) <= p) {
|
||||
if (p % i == 0) {
|
||||
pn = 0;
|
||||
break;
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
} else {
|
||||
pn = 0;
|
||||
}
|
||||
} while (!pn);
|
||||
return(p);
|
||||
|
||||
} /* end of Cudd_Prime */
|
||||
|
||||
// hash table
|
||||
static inline int If_CluWordNum2( int nVars )
|
||||
{
|
||||
return nVars <= 6 ? 1 : 1 << (nVars-6);
|
||||
}
|
||||
|
||||
int If_CluHashFindMedian2( If_Man_t * p, int t )
|
||||
{
|
||||
If_Hte_t * pEntry;
|
||||
Vec_Int_t * vCounters;
|
||||
int i, Max = 0, Total = 0, Half = 0;
|
||||
vCounters = Vec_IntStart( 1000 );
|
||||
for ( i = 0; i < p->nTableSize[t]; i++ )
|
||||
{
|
||||
for ( pEntry = ((If_Hte_t **)p->pHashTable[t])[i]; pEntry; pEntry = pEntry->pNext )
|
||||
{
|
||||
if ( Max < (int)pEntry->Counter )
|
||||
{
|
||||
Max = pEntry->Counter;
|
||||
Vec_IntSetEntry( vCounters, pEntry->Counter, 0 );
|
||||
}
|
||||
Vec_IntAddToEntry( vCounters, pEntry->Counter, 1 );
|
||||
Total++;
|
||||
}
|
||||
}
|
||||
for ( i = Max; i > 0; i-- )
|
||||
{
|
||||
Half += Vec_IntEntry( vCounters, i );
|
||||
if ( Half > Total/2 )
|
||||
break;
|
||||
}
|
||||
/*
|
||||
printf( "total = %d ", Total );
|
||||
printf( "half = %d ", Half );
|
||||
printf( "i = %d ", i );
|
||||
printf( "Max = %d.\n", Max );
|
||||
*/
|
||||
Vec_IntFree( vCounters );
|
||||
return Abc_MaxInt( i, 1 );
|
||||
}
|
||||
|
||||
int If_CluHashKey2( word * pTruth, int nWords, int Size )
|
||||
{
|
||||
static unsigned BigPrimes[8] = {12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741};
|
||||
unsigned Value = 0;
|
||||
int i;
|
||||
if ( nWords < 4 )
|
||||
{
|
||||
unsigned char * s = (unsigned char *)pTruth;
|
||||
for ( i = 0; i < 8 * nWords; i++ )
|
||||
Value ^= BigPrimes[i % 7] * s[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned * s = (unsigned *)pTruth;
|
||||
for ( i = 0; i < 2 * nWords; i++ )
|
||||
Value ^= BigPrimes[i % 7] * s[i];
|
||||
}
|
||||
return Value % Size;
|
||||
}
|
||||
|
||||
unsigned * If_CluHashLookup2( If_Man_t * p, word * pTruth, int t )
|
||||
{
|
||||
If_Hte_t * pEntry, * pPrev;
|
||||
int nWords, HashKey;
|
||||
if ( p == NULL )
|
||||
return NULL;
|
||||
nWords = If_CluWordNum2(p->pPars->nLutSize);
|
||||
if ( p->pMemEntries == NULL )
|
||||
p->pMemEntries = Mem_FixedStart( sizeof(If_Hte_t) + sizeof(word) * (If_CluWordNum2(p->pPars->nLutSize) - 1) );
|
||||
if ( p->pHashTable[t] == NULL )
|
||||
{
|
||||
// decide how large should be the table
|
||||
int nEntriesMax1 = 4 * If_CluPrimeCudd2( Vec_PtrSize(p->vObjs) * p->pPars->nCutsMax );
|
||||
int nEntriesMax2 = (int)(((double)CLU_MEM_MAX * (1 << 20)) / If_CluWordNum2(p->pPars->nLutSize) / 8);
|
||||
// int nEntriesMax2 = 10000;
|
||||
// create table
|
||||
p->nTableSize[t] = If_CluPrimeCudd2( Abc_MinInt(nEntriesMax1, nEntriesMax2)/2 );
|
||||
p->pHashTable[t] = ABC_CALLOC( void *, p->nTableSize[t] );
|
||||
}
|
||||
// check if this entry exists
|
||||
HashKey = If_CluHashKey2( pTruth, nWords, p->nTableSize[t] );
|
||||
for ( pEntry = ((If_Hte_t **)p->pHashTable[t])[HashKey]; pEntry; pEntry = pEntry->pNext )
|
||||
if ( memcmp(pEntry->pTruth, pTruth, sizeof(word) * nWords) == 0 )
|
||||
{
|
||||
pEntry->Counter++;
|
||||
return &pEntry->Group;
|
||||
}
|
||||
// resize the hash table
|
||||
if ( p->nTableEntries[t] >= 2 * p->nTableSize[t] )
|
||||
{
|
||||
// collect useful entries
|
||||
If_Hte_t * pPrev;
|
||||
Vec_Ptr_t * vUseful = Vec_PtrAlloc( p->nTableEntries[t] );
|
||||
int i, Median = If_CluHashFindMedian2( p, t );
|
||||
for ( i = 0; i < p->nTableSize[t]; i++ )
|
||||
{
|
||||
for ( pEntry = ((If_Hte_t **)p->pHashTable[t])[i]; pEntry; )
|
||||
{
|
||||
if ( (int)pEntry->Counter > Median )
|
||||
{
|
||||
Vec_PtrPush( vUseful, pEntry );
|
||||
pEntry = pEntry->pNext;
|
||||
}
|
||||
else
|
||||
{
|
||||
pPrev = pEntry->pNext;
|
||||
Mem_FixedEntryRecycle( p->pMemEntries, (char *)pEntry );
|
||||
pEntry = pPrev;
|
||||
}
|
||||
}
|
||||
}
|
||||
// add useful entries
|
||||
memset( p->pHashTable[t], 0, sizeof(void *) * p->nTableSize[t] );
|
||||
Vec_PtrForEachEntry( If_Hte_t *, vUseful, pEntry, i )
|
||||
{
|
||||
HashKey = If_CluHashKey2( pEntry->pTruth, nWords, p->nTableSize[t] );
|
||||
pPrev = ((If_Hte_t **)p->pHashTable[t])[HashKey];
|
||||
if ( pPrev == NULL || pEntry->Counter >= pPrev->Counter )
|
||||
{
|
||||
pEntry->pNext = pPrev;
|
||||
((If_Hte_t **)p->pHashTable[t])[HashKey] = pEntry;
|
||||
}
|
||||
else
|
||||
{
|
||||
while ( pPrev->pNext && pEntry->Counter < pPrev->pNext->Counter )
|
||||
pPrev = pPrev->pNext;
|
||||
pEntry->pNext = pPrev->pNext;
|
||||
pPrev->pNext = pEntry;
|
||||
}
|
||||
}
|
||||
p->nTableEntries[t] = Vec_PtrSize( vUseful );
|
||||
Vec_PtrFree( vUseful );
|
||||
}
|
||||
// create entry
|
||||
p->nTableEntries[t]++;
|
||||
pEntry = (If_Hte_t *)Mem_FixedEntryFetch( p->pMemEntries );
|
||||
memcpy( pEntry->pTruth, pTruth, sizeof(word) * nWords );
|
||||
pEntry->Group = CLU_UNUSED;
|
||||
pEntry->Counter = 1;
|
||||
// insert at the beginning
|
||||
// pEntry->pNext = ((If_Hte_t **)p->pHashTable[t])[HashKey];
|
||||
// ((If_Hte_t **)p->pHashTable[t])[HashKey] = pEntry;
|
||||
// insert at the end
|
||||
pEntry->pNext = NULL;
|
||||
for ( pPrev = ((If_Hte_t **)p->pHashTable[t])[HashKey]; pPrev && pPrev->pNext; pPrev = pPrev->pNext );
|
||||
if ( pPrev == NULL )
|
||||
((If_Hte_t **)p->pHashTable[t])[HashKey] = pEntry;
|
||||
else
|
||||
pPrev->pNext = pEntry;
|
||||
return &pEntry->Group;
|
||||
}
|
||||
|
||||
// returns if successful
|
||||
int If_CluCheck66( If_Man_t * p, word * pTruth0, int nVars, int fHashing )
|
||||
{
|
||||
If_Grp_t G1 = {0};
|
||||
unsigned * pHashed = NULL;
|
||||
|
||||
if ( p && fHashing )
|
||||
{
|
||||
pHashed = If_CluHashLookup2( p, pTruth0, 0 );
|
||||
if ( pHashed && *pHashed != CLU_UNUSED )
|
||||
If_CluUns2Grp2( *pHashed, &G1 );
|
||||
}
|
||||
|
||||
/* new entry */
|
||||
if ( G1.nVars == 0 )
|
||||
{
|
||||
G1.nVars = acd66_evaluate( pTruth0, nVars, 0 );
|
||||
}
|
||||
|
||||
if ( pHashed )
|
||||
*pHashed = If_CluGrp2Uns2( &G1 );
|
||||
|
||||
return G1.nVars;
|
||||
}
|
||||
|
||||
// returns if successful
|
||||
int If_CluCheck666( If_Man_t * p, word * pTruth0, int nVars, int fHashing )
|
||||
{
|
||||
If_Grp_t G1 = {0};
|
||||
unsigned * pHashed = NULL;
|
||||
|
||||
if ( p && fHashing )
|
||||
{
|
||||
pHashed = If_CluHashLookup2( p, pTruth0, 0 );
|
||||
if ( pHashed && *pHashed != CLU_UNUSED )
|
||||
If_CluUns2Grp2( *pHashed, &G1 );
|
||||
}
|
||||
|
||||
/* new entry */
|
||||
if ( G1.nVars == 0 )
|
||||
{
|
||||
G1.nVars = acd666_evaluate( pTruth0, nVars, 0 );
|
||||
}
|
||||
|
||||
if ( pHashed )
|
||||
*pHashed = If_CluGrp2Uns2( &G1 );
|
||||
|
||||
return G1.nVars;
|
||||
}
|
||||
|
||||
/**Function*************************************************************
|
||||
|
||||
Synopsis [Performs ACD into 66 cascade.]
|
||||
|
||||
Description []
|
||||
|
||||
SideEffects []
|
||||
|
||||
SeeAlso []
|
||||
|
||||
***********************************************************************/
|
||||
int If_CutPerformCheck66( If_Man_t * p, unsigned * pTruth0, int nVars, int nLeaves, char * pStr )
|
||||
{
|
||||
unsigned pTruth[IF_MAX_FUNC_LUTSIZE > 5 ? 1 << (IF_MAX_FUNC_LUTSIZE - 5) : 1];
|
||||
int i, Length;
|
||||
// stretch the truth table
|
||||
assert( nVars >= 6 );
|
||||
memcpy( pTruth, pTruth0, sizeof(word) * Abc_TtWordNum(nVars) );
|
||||
Abc_TtStretch6( (word *)pTruth, nLeaves, p->pPars->nLutSize );
|
||||
|
||||
// if cutmin is disabled, minimize the function
|
||||
if ( !p->pPars->fCutMin )
|
||||
nLeaves = Abc_TtMinBase( (word *)pTruth, NULL, nLeaves, nVars );
|
||||
|
||||
// quit if parameters are wrong
|
||||
Length = strlen(pStr);
|
||||
if ( Length != 2 && Length != 3 )
|
||||
{
|
||||
printf( "Wrong LUT struct (%s)\n", pStr );
|
||||
return 0;
|
||||
}
|
||||
for ( i = 0; i < Length; i++ )
|
||||
{
|
||||
if ( pStr[i] != '6' )
|
||||
{
|
||||
printf( "The LUT size (%d) should belong to {6}.\n", pStr[i] - '0' );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ( Length == 2 && nLeaves > 11 ) || ( Length == 3 && nLeaves > 16 ) )
|
||||
{
|
||||
printf( "The cut size (%d) is too large for the LUT structure %s.\n", nLeaves, pStr );
|
||||
return 0;
|
||||
}
|
||||
|
||||
// consider easy case
|
||||
if ( nLeaves <= 6 )
|
||||
return 1;
|
||||
|
||||
// derive the decomposition
|
||||
if ( Length == 2 )
|
||||
return If_CluCheck66(p, (word*)pTruth, nVars, 1);
|
||||
else
|
||||
return If_CluCheck666(p, (word*)pTruth, nVars, 1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
/// END OF FILE ///
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
|
@ -7,6 +7,7 @@ SRC += src/map/if/ifCom.c \
|
|||
src/map/if/ifDec08.c \
|
||||
src/map/if/ifDec10.c \
|
||||
src/map/if/ifDec16.c \
|
||||
src/map/if/ifDec66.c \
|
||||
src/map/if/ifDec75.c \
|
||||
src/map/if/ifDelay.c \
|
||||
src/map/if/ifDsd.c \
|
||||
|
|
|
|||
Loading…
Reference in New Issue