First version of ACD

This commit is contained in:
aletempiac 2023-11-15 18:38:00 +01:00
parent 6ca7eab466
commit 1632dc0d4e
20 changed files with 2918 additions and 69 deletions

View File

@ -17,6 +17,7 @@ OS := $(shell uname -s)
MODULES := \
$(wildcard src/ext*) \
src/acd \
src/base/abc src/base/abci src/base/cmd src/base/io src/base/main src/base/exor \
src/base/ver src/base/wlc src/base/wln src/base/acb src/base/bac src/base/cba src/base/pla src/base/test \
src/map/mapper src/map/mio src/map/super src/map/if \
@ -56,7 +57,7 @@ ARCHFLAGS := $(ARCHFLAGS)
OPTFLAGS ?= -g -O
CFLAGS += -Wall -Wno-unused-function -Wno-write-strings -Wno-sign-compare $(ARCHFLAGS)
CFLAGS += -std=c17 -Wall -Wno-unused-function -Wno-write-strings -Wno-sign-compare $(ARCHFLAGS)
ifneq ($(findstring arm,$(shell uname -m)),)
CFLAGS += -DABC_MEMALIGN=4
endif
@ -151,7 +152,7 @@ ifdef ABC_USE_LIBSTDCXX
endif
$(info $(MSG_PREFIX)Using CFLAGS=$(CFLAGS))
CXXFLAGS += $(CFLAGS)
CXXFLAGS += $(CFLAGS) -std=c++17
SRC :=
GARBAGE := core core.* *.stackdump ./tags $(PROG) arch_flags

1500
src/acd/ac_decomposition.hpp Normal file

File diff suppressed because it is too large Load Diff

69
src/acd/ac_wrapper.cpp Normal file
View File

@ -0,0 +1,69 @@
// #include "base/main/main.h"
#include "ac_wrapper.h"
#include "ac_decomposition.hpp"
// ABC_NAMESPACE_IMPL_START
int acd_evaluate( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned *cost )
{
using namespace mockturtle;
int num_blocks = ( nVars <= 6 ) ? 1 : ( 1 << ( nVars - 6 ) );
/* translate truth table into static table */
kitty::dynamic_truth_table tt( nVars );
for ( int i = 0; i < num_blocks; ++i )
tt._bits[i] = pTruth[i];
ac_decomposition_params ps;
ps.lut_size = lutSize;
ac_decomposition_stats st;
ac_decomposition_impl acd( tt, nVars, ps, &st );
acd.run( *pdelay );
int val = acd.compute_decomposition();
if ( val < 0 )
{
*pdelay = 0;
return -1;
}
*pdelay = acd.get_profile();
*cost = st.num_luts;
return 0;
}
int acd_decompose( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned char *decomposition )
{
using namespace mockturtle;
int num_blocks = ( nVars <= 6 ) ? 1 : ( 1 << ( nVars - 6 ) );
/* translate truth table into static table */
kitty::dynamic_truth_table tt( nVars );
for ( int i = 0; i < num_blocks; ++i )
tt._bits[i] = pTruth[i];
ac_decomposition_params ps;
ps.lut_size = lutSize;
ac_decomposition_stats st;
ac_decomposition_impl acd( tt, nVars, ps, &st );
acd.run( *pdelay );
int val = acd.compute_decomposition();
if ( val < 0 )
{
*pdelay = 0;
return -1;
}
*pdelay = acd.get_profile();
acd.get_decomposition( decomposition );
return 0;
}
// ABC_NAMESPACE_IMPL_END

23
src/acd/ac_wrapper.h Normal file
View File

@ -0,0 +1,23 @@
// #pragma once
#ifndef __ACD_WRAPPER_H_
#define __ACD_WRAPPER_H_
// #include "base/main/main.h"
#include "misc/util/abc_global.h"
// ABC_NAMESPACE_HEADER_START
#ifdef __cplusplus
extern "C" {
#endif
int acd_evaluate( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned *cost );
int acd_decompose( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned char *decomposition );
#ifdef __cplusplus
}
#endif
// ABC_NAMESPACE_HEADER_END
#endif

119
src/acd/kitty_algorithm.hpp Normal file
View File

@ -0,0 +1,119 @@
#ifndef _KITTY_ALGORITHM_H_
#define _KITTY_ALGORITHM_H_
#pragma once
#include <algorithm>
#include <cassert>
#include "kitty_constants.hpp"
#include "kitty_dynamic_tt.hpp"
#include "kitty_static_tt.hpp"
namespace kitty
{
/*! \brief Perform bitwise unary operation on truth table
\param tt Truth table
\param op Unary operation that takes as input a word (`uint64_t`) and returns a word
\return new constructed truth table of same type and dimensions
*/
template<typename TT, typename Fn>
auto unary_operation( const TT& tt, Fn&& op )
{
auto result = tt.construct();
std::transform( tt.cbegin(), tt.cend(), result.begin(), op );
result.mask_bits();
return result;
}
/*! \brief Perform bitwise binary operation on two truth tables
The dimensions of `first` and `second` must match. This is ensured
at compile-time for static truth tables, but at run-time for dynamic
truth tables.
\param first First truth table
\param second Second truth table
\param op Binary operation that takes as input two words (`uint64_t`) and returns a word
\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 )
{
assert( first.num_vars() == second.num_vars() );
auto result = first.construct();
std::transform( first.cbegin(), first.cend(), second.cbegin(), result.begin(), op );
result.mask_bits();
return result;
}
/*! \brief Computes a predicate based on two truth tables
The dimensions of `first` and `second` must match. This is ensured
at compile-time for static truth tables, but at run-time for dynamic
truth tables.
\param first First truth table
\param second Second truth table
\param op Binary operation that takes as input two words (`uint64_t`) and returns a Boolean
\return true or false based on the predicate
*/
template<typename TT, typename Fn>
bool binary_predicate( const TT& first, const TT& second, Fn&& op )
{
assert( first.num_vars() == second.num_vars() );
return std::equal( first.begin(), first.end(), second.begin(), op );
}
/*! \brief Assign computed values to bits
The functor `op` computes bits which are assigned to the bits of the
truth table.
\param tt Truth table
\param op Unary operation that takes no input and returns a word (`uint64_t`)
*/
template<typename TT, typename Fn>
void assign_operation( TT& tt, Fn&& op )
{
std::generate( tt.begin(), tt.end(), op );
tt.mask_bits();
}
/*! \brief Iterates through each block of a truth table
The functor `op` is called for every block of the truth table.
\param tt Truth table
\param op Unary operation that takes as input a word (`uint64_t`) and returns void
*/
template<typename TT, typename Fn>
void for_each_block( const TT& tt, Fn&& op )
{
std::for_each( tt.cbegin(), tt.cend(), op );
}
/*! \brief Iterates through each block of a truth table in reverse
order
The functor `op` is called for every block of the truth table in
reverse order.
\param tt Truth table
\param op Unary operation that takes as input a word (`uint64_t`) and returns void
*/
template<typename TT, typename Fn>
void for_each_block_reversed( const TT& tt, Fn&& op )
{
std::for_each( tt.crbegin(), tt.crend(), op );
}
} // namespace kitty
#endif // _KITTY_ALGORITHM_H_

View File

@ -0,0 +1,91 @@
#ifndef _KITTY_CONSTANTS_H_
#define _KITTY_CONSTANTS_H_
#pragma once
#include <cstdint>
#include <vector>
namespace kitty
{
namespace detail
{
static constexpr uint64_t projections[] = {
UINT64_C( 0xaaaaaaaaaaaaaaaa ),
UINT64_C( 0xcccccccccccccccc ),
UINT64_C( 0xf0f0f0f0f0f0f0f0 ),
UINT64_C( 0xff00ff00ff00ff00 ),
UINT64_C( 0xffff0000ffff0000 ),
UINT64_C( 0xffffffff00000000 ) };
static constexpr uint64_t projections_neg[] = {
UINT64_C( 0x5555555555555555 ),
UINT64_C( 0x3333333333333333 ),
UINT64_C( 0x0f0f0f0f0f0f0f0f ),
UINT64_C( 0x00ff00ff00ff00ff ),
UINT64_C( 0x0000ffff0000ffff ),
UINT64_C( 0x00000000ffffffff ) };
static constexpr uint64_t masks[] = {
UINT64_C( 0x0000000000000001 ),
UINT64_C( 0x0000000000000003 ),
UINT64_C( 0x000000000000000f ),
UINT64_C( 0x00000000000000ff ),
UINT64_C( 0x000000000000ffff ),
UINT64_C( 0x00000000ffffffff ),
UINT64_C( 0xffffffffffffffff ) };
static constexpr uint64_t permutation_masks[][3] = {
{ UINT64_C( 0x9999999999999999 ), UINT64_C( 0x2222222222222222 ), UINT64_C( 0x4444444444444444 ) },
{ UINT64_C( 0xc3c3c3c3c3c3c3c3 ), UINT64_C( 0x0c0c0c0c0c0c0c0c ), UINT64_C( 0x3030303030303030 ) },
{ UINT64_C( 0xf00ff00ff00ff00f ), UINT64_C( 0x00f000f000f000f0 ), UINT64_C( 0x0f000f000f000f00 ) },
{ UINT64_C( 0xff0000ffff0000ff ), UINT64_C( 0x0000ff000000ff00 ), UINT64_C( 0x00ff000000ff0000 ) },
{ UINT64_C( 0xffff00000000ffff ), UINT64_C( 0x00000000ffff0000 ), UINT64_C( 0x0000ffff00000000 ) } };
static constexpr uint64_t ppermutation_masks[][6][3] = {
{ { UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) },
{ UINT64_C( 0x9999999999999999 ), UINT64_C( 0x2222222222222222 ), UINT64_C( 0x4444444444444444 ) },
{ UINT64_C( 0xa5a5a5a5a5a5a5a5 ), UINT64_C( 0x0a0a0a0a0a0a0a0a ), UINT64_C( 0x5050505050505050 ) },
{ UINT64_C( 0xaa55aa55aa55aa55 ), UINT64_C( 0x00aa00aa00aa00aa ), UINT64_C( 0x5500550055005500 ) },
{ UINT64_C( 0xaaaa5555aaaa5555 ), UINT64_C( 0x0000aaaa0000aaaa ), UINT64_C( 0x5555000055550000 ) },
{ UINT64_C( 0xaaaaaaaa55555555 ), UINT64_C( 0x00000000aaaaaaaa ), UINT64_C( 0x5555555500000000 ) } },
{ { UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) },
{ UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) },
{ UINT64_C( 0xc3c3c3c3c3c3c3c3 ), UINT64_C( 0x0c0c0c0c0c0c0c0c ), UINT64_C( 0x3030303030303030 ) },
{ UINT64_C( 0xcc33cc33cc33cc33 ), UINT64_C( 0x00cc00cc00cc00cc ), UINT64_C( 0x3300330033003300 ) },
{ UINT64_C( 0xcccc3333cccc3333 ), UINT64_C( 0x0000cccc0000cccc ), UINT64_C( 0x3333000033330000 ) },
{ UINT64_C( 0xcccccccc33333333 ), UINT64_C( 0x00000000cccccccc ), UINT64_C( 0x3333333300000000 ) } },
{ { UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) },
{ UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) },
{ UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) },
{ UINT64_C( 0xf00ff00ff00ff00f ), UINT64_C( 0x00f000f000f000f0 ), UINT64_C( 0x0f000f000f000f00 ) },
{ UINT64_C( 0xf0f00f0ff0f00f0f ), UINT64_C( 0x0000f0f00000f0f0 ), UINT64_C( 0x0f0f00000f0f0000 ) },
{ UINT64_C( 0xf0f0f0f00f0f0f0f ), UINT64_C( 0x00000000f0f0f0f0 ), UINT64_C( 0x0f0f0f0f00000000 ) } },
{ { UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) },
{ UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) },
{ UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) },
{ UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) },
{ UINT64_C( 0xff0000ffff0000ff ), UINT64_C( 0x0000ff000000ff00 ), UINT64_C( 0x00ff000000ff0000 ) },
{ UINT64_C( 0xff00ff0000ff00ff ), UINT64_C( 0x00000000ff00ff00 ), UINT64_C( 0x00ff00ff00000000 ) } },
{ { UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) },
{ UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) },
{ UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) },
{ UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) },
{ UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) },
{ UINT64_C( 0xffff00000000ffff ), UINT64_C( 0x00000000ffff0000 ), UINT64_C( 0x0000ffff00000000 ) } } };
static constexpr int32_t hex_to_int[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
} // namespace detail
} // namespace kitty
#endif //_KITTY_CONSTANTS_H_

View File

@ -0,0 +1,92 @@
#ifndef _KITTY_CONSTRUCT_TT_H_
#define _KITTY_CONSTRUCT_TT_H_
#pragma once
#include <cctype>
#include <chrono>
#include <istream>
#include <random>
#include <stack>
#include "kitty_constants.hpp"
#include "kitty_dynamic_tt.hpp"
#include "kitty_static_tt.hpp"
namespace kitty
{
/*! \brief Creates truth table with number of variables
If some truth table instance is given, one can create a truth table with the
same type by calling the `construct()` method on it. This function helps if
only the number of variables is known and the base type and uniforms the
creation of static and dynamic truth tables. Note, however, that for static
truth tables `num_vars` must be consistent to the number of variables in the
truth table type.
\param num_vars Number of variables
*/
template<typename TT>
inline TT create( unsigned num_vars )
{
(void)num_vars;
TT tt;
assert( tt.num_vars() == num_vars );
return tt;
}
/*! \cond PRIVATE */
template<>
inline dynamic_truth_table create<dynamic_truth_table>( unsigned num_vars )
{
return dynamic_truth_table( num_vars );
}
/*! \endcond */
/*! \brief Constructs projections (single-variable functions)
\param tt Truth table
\param var_index Index of the variable, must be smaller than the truth table's number of variables
\param complement If true, realize inverse projection
*/
template<typename TT>
void create_nth_var( TT& tt, uint8_t var_index, bool complement = false )
{
if ( tt.num_vars() <= 6 )
{
/* assign from precomputed table */
tt._bits[0] = complement ? ~detail::projections[var_index] : detail::projections[var_index];
/* mask if truth table does not require all bits */
tt.mask_bits();
return;
}
if ( var_index < 6 )
{
std::fill( std::begin( tt._bits ), std::end( tt._bits ), complement ? ~detail::projections[var_index] : detail::projections[var_index] );
}
else
{
const auto c = 1 << ( var_index - 6 );
const auto zero = uint64_t( 0 );
const auto one = ~zero;
auto block = uint64_t( 0u );
while ( block < tt.num_blocks() )
{
for ( auto i = 0; i < c; ++i )
{
tt._bits[block++] = complement ? one : zero;
}
for ( auto i = 0; i < c; ++i )
{
tt._bits[block++] = complement ? zero : one;
}
}
}
}
} // namespace kitty
#endif // _KITTY_CONSTRUCT_TT_H_

View File

@ -0,0 +1,147 @@
#ifndef _KITTY_DYNAMIC_TT_H_
#define _KITTY_DYNAMIC_TT_H_
#pragma once
#include <vector>
#include <cstdint>
#include <type_traits>
#include "kitty_constants.hpp"
namespace kitty
{
/*! Truth table in which number of variables is known at runtime.
*/
struct dynamic_truth_table
{
/*! Standard constructor.
The number of variables provided to the truth table can be
computed at runtime. However, once the truth table is constructed
its number of variables cannot change anymore.
The constructor computes the number of blocks and resizes the
vector accordingly.
\param num_vars Number of variables
*/
explicit dynamic_truth_table( uint32_t num_vars )
: _bits( ( num_vars <= 6 ) ? 1u : ( 1u << ( num_vars - 6 ) ) ),
_num_vars( num_vars )
{
}
/*! Empty constructor.
Creates an empty truth table. It has 0 variables, but no bits, i.e., it is
different from a truth table for the constant function. This constructor is
only used for convenience, if algorithms require the existence of default
constructable classes.
*/
dynamic_truth_table() : _num_vars( 0 ) {}
/*! Constructs a new dynamic truth table instance with the same number of variables. */
inline dynamic_truth_table construct() const
{
return dynamic_truth_table( _num_vars );
}
/*! Returns number of variables.
*/
inline auto num_vars() const noexcept { return _num_vars; }
/*! Returns number of blocks.
*/
inline auto num_blocks() const noexcept { return _bits.size(); }
/*! Returns number of bits.
*/
inline auto num_bits() const noexcept { return uint64_t( 1 ) << _num_vars; }
/*! \brief Begin iterator to bits.
*/
inline auto begin() noexcept { return _bits.begin(); }
/*! \brief End iterator to bits.
*/
inline auto end() noexcept { return _bits.end(); }
/*! \brief Begin iterator to bits.
*/
inline auto begin() const noexcept { return _bits.begin(); }
/*! \brief End iterator to bits.
*/
inline auto end() const noexcept { return _bits.end(); }
/*! \brief Reverse begin iterator to bits.
*/
inline auto rbegin() noexcept { return _bits.rbegin(); }
/*! \brief Reverse end iterator to bits.
*/
inline auto rend() noexcept { return _bits.rend(); }
/*! \brief Constant begin iterator to bits.
*/
inline auto cbegin() const noexcept { return _bits.cbegin(); }
/*! \brief Constant end iterator to bits.
*/
inline auto cend() const noexcept { return _bits.cend(); }
/*! \brief Constant reverse begin iterator to bits.
*/
inline auto crbegin() const noexcept { return _bits.crbegin(); }
/*! \brief Constant teverse end iterator to bits.
*/
inline auto crend() const noexcept { return _bits.crend(); }
/*! \brief Assign other truth table.
This replaces the current truth table with another truth table. The truth
table type has to be complete. The vector of bits is resized accordingly.
\param other Other truth table
*/
template<class TT>
dynamic_truth_table& operator=( const TT& other )
{
_bits.resize( other.num_blocks() );
std::copy( other.begin(), other.end(), begin() );
_num_vars = other.num_vars();
if ( _num_vars < 6 )
{
mask_bits();
}
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
{
if ( _num_vars < 6 )
{
_bits[0u] &= detail::masks[_num_vars];
}
}
/*! \cond PRIVATE */
public: /* fields */
std::vector<uint64_t> _bits;
uint32_t _num_vars;
/*! \endcond */
};
} //namespace kitty
#endif // _KITTY_DYNAMIC_TT_H_

View File

@ -0,0 +1,333 @@
#ifndef _KITTY_OPERATIONS_TT_H_
#define _KITTY_OPERATIONS_TT_H_
#pragma once
#include <algorithm>
#include <cassert>
#include <functional>
#include <iterator>
#include <optional>
#include <iostream>
#include "kitty_algorithm.hpp"
#include "kitty_constants.hpp"
#include "kitty_dynamic_tt.hpp"
#include "kitty_static_tt.hpp"
namespace kitty
{
/*! Inverts all bits in a truth table, based on a condition */
template<typename TT>
inline TT unary_not_if( const TT& tt, bool cond )
{
#ifdef _MSC_VER
#pragma warning( push )
#pragma warning( disable : 4146 )
#endif
const auto mask = -static_cast<uint64_t>( cond );
#ifdef _MSC_VER
#pragma warning( pop )
#endif
return unary_operation( tt, [mask]( auto a )
{ return a ^ mask; } );
}
/*! \brief Inverts all bits in a truth table */
template<typename TT>
inline TT unary_not( const TT& tt )
{
return unary_operation( tt, []( auto a )
{ return ~a; } );
}
/*! \brief Bitwise AND of two truth tables */
template<typename TT>
inline TT binary_and( const TT& first, const TT& second )
{
return binary_operation( first, second, std::bit_and<>() );
}
/*! \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<>() );
}
/*! \brief Swaps two variables in a truth table
The function swaps variable `var_index1` with `var_index2`. The
function will change `tt` in-place. If `tt` should not be changed,
one can use `swap` instead.
\param tt Truth table
\param var_index1 First variable
\param var_index2 Second variable
*/
template<typename TT>
void swap_inplace( TT& 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 );
}
if ( tt.num_vars() <= 6 )
{
const auto& pmask = detail::ppermutation_masks[var_index1][var_index2];
const auto shift = ( 1 << var_index2 ) - ( 1 << var_index1 );
tt._bits[0] = ( tt._bits[0] & pmask[0] ) | ( ( tt._bits[0] & pmask[1] ) << shift ) | ( ( tt._bits[0] & pmask[2] ) >> shift );
}
else if ( var_index2 <= 5 )
{
const auto& pmask = detail::ppermutation_masks[var_index1][var_index2];
const auto shift = ( 1 << var_index2 ) - ( 1 << var_index1 );
std::transform( std::begin( tt._bits ), std::end( tt._bits ), 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::end( tt._bits ) )
{
for ( auto i = decltype( step ){ 0 }; i < step; ++i )
{
const auto low_to_high = ( *( it + i ) & detail::projections[var_index1] ) >> shift;
const auto high_to_low = ( *( it + i + step ) << shift ) & detail::projections[var_index1];
*( it + i ) = ( *( it + i ) & ~detail::projections[var_index1] ) | high_to_low;
*( it + i + step ) = ( *( it + i + step ) & 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::end( tt._bits ) )
{
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;
}
}
}
/*! \brief Extends smaller truth table to larger one
The most significant variables will not be in the functional support of the
resulting truth table, but the method is helpful to align a truth table when
being used with another one.
\param tt Larger truth table to create
\param from Smaller truth table to copy from
*/
template<typename TT, typename TTFrom>
void extend_to_inplace( TT& tt, const TTFrom& from )
{
assert( tt.num_vars() >= from.num_vars() );
if ( from.num_vars() < 6 )
{
auto mask = *from.begin();
for ( auto i = from.num_vars(); i < std::min<uint8_t>( 6, tt.num_vars() ); ++i )
{
mask |= ( mask << ( 1 << i ) );
}
std::fill( tt.begin(), tt.end(), mask );
}
else
{
auto it = tt.begin();
while ( it != tt.end() )
{
it = std::copy( from.cbegin(), from.cend(), it );
}
}
}
/*! \brief Extends smaller truth table to larger static one
This is an out-of-place version of `extend_to_inplace` that has the truth
table as a return value. It only works for creating static truth tables. The
template parameter `NumVars` must be equal or larger to the number of
variables in `from`.
\param from Smaller truth table to copy from
*/
template<uint32_t NumVars, typename TTFrom>
inline static_truth_table<NumVars> extend_to( const TTFrom& from )
{
static_truth_table<NumVars> tt;
extend_to_inplace( tt, from );
return tt;
}
/*! \brief Checks whether truth table depends on given variable index
\param tt Truth table
\param var_index Variable index
*/
template<typename TT>
bool has_var( const TT& tt, uint8_t var_index )
{
assert( var_index < tt.num_vars() );
if ( tt.num_vars() <= 6 || var_index < 6 )
{
return std::any_of( std::begin( tt._bits ), std::end( tt._bits ),
[var_index]( uint64_t word )
{ return ( ( word >> ( uint64_t( 1 ) << var_index ) ) & detail::projections_neg[var_index] ) !=
( word & detail::projections_neg[var_index] ); } );
}
const auto step = 1 << ( var_index - 6 );
for ( auto i = 0u; i < static_cast<uint32_t>( tt.num_blocks() ); i += 2 * step )
{
for ( auto j = 0; j < step; ++j )
{
if ( tt._bits[i + j] != tt._bits[i + j + step] )
{
return true;
}
}
}
return false;
}
/*! \brief Checks whether truth table depends on given variable index
\param tt Truth table
\param care Care set
\param var_index Variable index
*/
template<typename TT>
bool has_var( const TT& tt, const TT& care, uint8_t var_index )
{
assert( var_index < tt.num_vars() );
assert( tt.num_vars() == care.num_vars() );
if ( tt.num_vars() <= 6 || var_index < 6 )
{
auto it_tt = std::begin( tt._bits );
auto it_care = std::begin( care._bits );
while ( it_tt != std::end( tt._bits ) )
{
if ( ( ( ( *it_tt >> ( uint64_t( 1 ) << var_index ) ) ^ *it_tt ) & detail::projections_neg[var_index]
& ( *it_care >> ( uint64_t( 1 ) << var_index ) ) & *it_care ) != 0 )
{
return true;
}
++it_tt;
++it_care;
}
return false;
}
const auto step = 1 << ( var_index - 6 );
for ( auto i = 0u; i < static_cast<uint32_t>( tt.num_blocks() ); i += 2 * step )
{
for ( auto j = 0; j < step; ++j )
{
if ( ( ( tt._bits[i + j] ^ tt._bits[i + j + step] ) & care._bits[i + j] & care._bits[i + j + step] ) != 0 )
{
return true;
}
}
}
return false;
}
/*! \brief Shrinks larger truth table to smaller one
The function expects that the most significant bits, which are cut off, are
not in the functional support of the original function. Only then it is
ensured that the resulting function is equivalent.
\param tt Smaller truth table to create
\param from Larger truth table to copy from
*/
template<typename TT, typename TTFrom>
void shrink_to_inplace( TT& tt, const TTFrom& from )
{
assert( tt.num_vars() <= from.num_vars() );
std::copy( from.begin(), from.begin() + tt.num_blocks(), tt.begin() );
if ( tt.num_vars() < 6 )
{
tt.mask_bits();
}
}
/*! \brief Shrinks larger truth table to smaller dynamic one
This is an out-of-place version of `shrink_to` that has the truth table as a
return value. It only works for creating dynamic tables. The parameter
`num_vars` must be equal or smaller to the number of variables in `from`.
\param from Smaller truth table to copy from
*/
template<typename TTFrom>
inline dynamic_truth_table shrink_to( const TTFrom& from, unsigned num_vars )
{
auto tt = create<dynamic_truth_table>( num_vars );
shrink_to_inplace( tt, from );
return tt;
}
/*! \brief Prints truth table in hexadecimal representation
The most-significant bit will be the first character of the string.
\param tt Truth table
\param os Output stream
*/
template<typename TT>
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 )
{
std::string chunk( chunk_size, '0' );
auto it = chunk.rbegin();
while (word && it != chunk.rend()) {
auto hex = word & 0xf;
if (hex < 10) {
*it = '0' + static_cast<char>(hex);
} else {
*it = 'a' + static_cast<char>(hex - 10);
}
++it;
word >>= 4;
}
os << chunk; } );
}
} //namespace kitty
#endif // _KITTY_OPERATIONS_TT_H_

View File

@ -0,0 +1,86 @@
#ifndef _KITTY_OPERATORS_TT_H_
#define _KITTY_OPERATORS_TT_H_
#pragma once
#include <algorithm>
#include <cassert>
#include <functional>
#include <iterator>
#include <optional>
#include "kitty_constants.hpp"
#include "kitty_dynamic_tt.hpp"
#include "kitty_static_tt.hpp"
#include "kitty_operations.hpp"
namespace kitty
{
/*! \brief Operator for unary_not */
inline dynamic_truth_table operator~( const dynamic_truth_table& tt )
{
return unary_not( tt );
}
/*! \brief Operator for unary_not */
template<uint32_t NumVars>
inline static_truth_table<NumVars> operator~( const static_truth_table<NumVars>& tt )
{
return unary_not( tt );
}
/*! \brief Operator for binary_and */
inline dynamic_truth_table operator&( const dynamic_truth_table& first, const dynamic_truth_table& second )
{
return binary_and( first, second );
}
/*! \brief Operator for binary_and */
template<uint32_t NumVars>
inline static_truth_table<NumVars> operator&( const static_truth_table<NumVars>& first, const static_truth_table<NumVars>& second )
{
return binary_and( first, second );
}
/*! \brief Operator for binary_and and assign */
inline void operator&=( dynamic_truth_table& first, const dynamic_truth_table& second )
{
first = binary_and( first, second );
}
/*! \brief Operator for binary_and and assign */
template<uint32_t NumVars>
inline void operator&=( static_truth_table<NumVars>& first, const static_truth_table<NumVars>& second )
{
first = binary_and( first, second );
}
/*! \brief Operator for binary_or */
inline dynamic_truth_table operator|( const dynamic_truth_table& first, const dynamic_truth_table& second )
{
return binary_or( first, second );
}
/*! \brief Operator for binary_or */
template<uint32_t NumVars>
inline static_truth_table<NumVars> operator|( const static_truth_table<NumVars>& first, const static_truth_table<NumVars>& second )
{
return binary_or( first, second );
}
/*! \brief Operator for binary_or and assign */
inline void operator|=( dynamic_truth_table& first, const dynamic_truth_table& second )
{
first = binary_or( first, second );
}
/*! \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 )
{
first = binary_or( first, second );
}
} // namespace kitty
#endif // _KITTY_OPERATORS_TT_H_

131
src/acd/kitty_static_tt.hpp Normal file
View File

@ -0,0 +1,131 @@
#ifndef _KITTY_STATIC_TT_H_
#define _KITTY_STATIC_TT_H_
#pragma once
#include <array>
#include <cstdint>
#include "kitty_constants.hpp"
namespace kitty
{
template<uint32_t NumVars>
struct static_truth_table
{
/*! \cond PRIVATE */
enum
{
NumBlocks = ( NumVars <= 6 ) ? 1u : ( 1u << ( NumVars - 6 ) )
};
enum
{
NumBits = uint64_t( 1 ) << NumVars
};
/*! \endcond */
/*! Standard constructor.
The number of variables provided to the truth table must be known
at runtime. The number of blocks will be computed as a compile
time constant.
*/
static_truth_table()
{
_bits.fill( 0 );
}
/*! 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 auto num_vars() const noexcept { return NumVars; }
/*! Returns number of blocks.
*/
inline auto num_blocks() const noexcept { return NumBlocks; }
/*! Returns number of bits.
*/
inline auto num_bits() const noexcept { return NumBits; }
/*! \brief Begin iterator to bits.
*/
inline auto begin() noexcept { return _bits.begin(); }
/*! \brief End iterator to bits.
*/
inline auto end() noexcept { return _bits.end(); }
/*! \brief Begin iterator to bits.
*/
inline auto begin() const noexcept { return _bits.begin(); }
/*! \brief End iterator to bits.
*/
inline auto end() const noexcept { return _bits.end(); }
/*! \brief Reverse begin iterator to bits.
*/
inline auto rbegin() noexcept { return _bits.rbegin(); }
/*! \brief Reverse end iterator to bits.
*/
inline auto rend() noexcept { return _bits.rend(); }
/*! \brief Constant begin iterator to bits.
*/
inline auto cbegin() const noexcept { return _bits.cbegin(); }
/*! \brief Constant end iterator to bits.
*/
inline auto cend() const noexcept { return _bits.cend(); }
/*! \brief Constant reverse begin iterator to bits.
*/
inline auto crbegin() const noexcept { return _bits.crbegin(); }
/*! \brief Constant teverse end iterator to bits.
*/
inline auto crend() const noexcept { return _bits.crend(); }
/*! \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_bits() == num_bits() )
{
std::copy( other.begin(), other.end(), begin() );
}
return *this;
}
/*! Masks the number of valid truth table bits.
We know that we will have at least 7 variables in this data
structure.
*/
inline void mask_bits() noexcept {}
/*! \cond PRIVATE */
public: /* fields */
std::array<uint64_t, NumBlocks> _bits;
/*! \endcond */
};
} //namespace kitty
#endif // _KITTY_STATIC_TT_H_

1
src/acd/module.make Normal file
View File

@ -0,0 +1 @@
SRC += src/acd/ac_wrapper.cpp

View File

@ -19447,7 +19447,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, "KCFAGRNTXYDEWSqaflepmrsdbgxyzuojiktncvh" ) ) != EOF )
while ( ( c = Extra_UtilGetopt( argc, argv, "KCFAGRNTXYDEWSqaflepmrsdbgxyuojiktnczvh" ) ) != EOF )
{
switch ( c )
{
@ -19652,9 +19652,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;
@ -19679,6 +19676,9 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv )
case 'c':
pPars->fUseTtPerm ^= 1;
break;
case 'z':
pPars->fAcd ^= 1;
break;
case 'v':
pPars->fVerbose ^= 1;
break;
@ -19810,7 +19810,7 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv )
pPars->pLutLib = NULL;
}
// modify for delay optimization
if ( pPars->fDelayOpt || pPars->fDsdBalance || pPars->fDelayOptLut || pPars->fUserLutDec )
if ( pPars->fDelayOpt || pPars->fDsdBalance || pPars->fDelayOptLut || pPars->fAcd )
{
pPars->fTruth = 1;
pPars->fCutMin = 1;
@ -19956,7 +19956,7 @@ usage:
sprintf(LutSize, "library" );
else
sprintf(LutSize, "%d", pPars->nLutSize );
Abc_Print( -2, "usage: if [-KCFAGRNTXY num] [-DEW float] [-S str] [-qarlepmsdbgxyzuojiktncvh]\n" );
Abc_Print( -2, "usage: if [-KCFAGRNTXY 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 );
@ -19985,7 +19985,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" );
@ -19994,6 +19993,7 @@ usage:
Abc_Print( -2, "\t-t : toggles optimizing average rather than maximum level [default = %s]\n", pPars->fDoAverage? "yes": "no" );
Abc_Print( -2, "\t-n : toggles computing DSDs of the cut functions [default = %s]\n", pPars->fUseDsd? "yes": "no" );
Abc_Print( -2, "\t-c : toggles computing truth tables in a new way [default = %s]\n", pPars->fUseTtPerm? "yes": "no" );
Abc_Print( -2, "\t-z : toggles using ACD decomposition [default = %s]\n", pPars->fAcd? "yes": "no" );
Abc_Print( -2, "\t-v : toggles verbose output [default = %s]\n", pPars->fVerbose? "yes": "no" );
Abc_Print( -2, "\t-h : prints the command usage\n");
return 1;

View File

@ -116,7 +116,7 @@ Abc_Ntk_t * Abc_NtkIf( Abc_Ntk_t * pNtk, If_Par_t * pPars )
pPars->pTimesReq = Abc_NtkGetCoRequiredFloats(pNtk);
// update timing info to reflect logic level
if ( (pPars->fDelayOpt || pPars->fDsdBalance || pPars->fUserRecLib || pPars->fUserSesLib || pPars->fUserLutDec) && pNtk->pManTime )
if ( (pPars->fDelayOpt || pPars->fDsdBalance || pPars->fUserRecLib || pPars->fUserSesLib || pPars->fAcd) && pNtk->pManTime )
{
int c;
if ( pNtk->AndGateDelay == 0.0 )
@ -427,28 +427,143 @@ Hop_Obj_t * Abc_NodeBuildFromMini( Hop_Man_t * pMan, If_Man_t * p, If_Cut_t * pC
}
/**Function*************************************************************
Synopsis [Implements decomposed LUT-structure of the cut.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_DecRecordToHop( Abc_Ntk_t * pNtkNew, If_Man_t * pIfMan, If_Cut_t * pCutBest, If_Obj_t * pIfObj, Vec_Int_t * vCover, Abc_Obj_t * pNodeTop )
{
extern Hop_Obj_t * Kit_TruthToHop( Hop_Man_t * pMan, unsigned * pTruth, int nVars, Vec_Int_t * vMemory );
assert( !pIfMan->pPars->fUseTtPerm );
Synopsis [Implements decomposed LUT-structure of the cut.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Hop_Obj_t * Abc_DecRecordToHop( Hop_Man_t * pMan, If_Man_t * pIfMan, If_Cut_t * pCutBest, If_Obj_t * pIfObj, Vec_Int_t * vCover )
{
// get the truth table
word * pTruth = If_CutTruthW(pIfMan, pCutBest);
int v;
If_Obj_t * pIfLeaf;
if ( pCutBest->nLeaves <= 6 )
{
/* add fanins */
If_CutForEachLeaf( pIfMan, pCutBest, pIfLeaf, v )
Abc_ObjAddFanin( pNodeTop, (Abc_Obj_t *)If_ObjCopy( pIfLeaf ) );
pNodeTop->Level = Abc_ObjLevelNew( pNodeTop );
pNodeTop->pData = Kit_TruthToHop( (Hop_Man_t *)pNtkNew->pManFunc, (unsigned *)pTruth, If_CutLeaveNum(pCutBest), vCover );
return;
}
// get the delay profile
unsigned delayProfile = pCutBest->acdDelay;
// If_Obj_t * pLeaf;
// int i, leafDelay;
// int DelayMax = -1, nLeafMax = 0;
// unsigned uLeafMask = 0;
// If_CutForEachLeaf( pIfMan, pCutBest, pLeaf, i )
// {
// leafDelay = If_ObjCutBest(pLeaf)->Delay;
// if ( DelayMax < leafDelay )
// {
// DelayMax = leafDelay;
// nLeafMax = 1;
// uLeafMask = (1 << i);
// }
// else if ( DelayMax == leafDelay )
// {
// nLeafMax++;
// uLeafMask |= (1 << i);
// }
// }
// perform LUT-decomposition and return the LUT-structure
unsigned char decompArray[92];
int val = acd_decompose( pTruth, pCutBest->nLeaves, 6, &(delayProfile), decompArray );
assert( val == 0 );
// assert( DelayMax + 2 >= pCutBest->Delay );
// convert the LUT-structure into a set of logic nodes in Abc_Ntk_t
unsigned char bytes_check = decompArray[0];
assert( bytes_check <= 92 );
int byte_p = 2;
unsigned char i, j, k, num_fanins, num_words, num_bytes;
int level, fanin;
word *tt;
Abc_Obj_t *pNewNodes[5];
/* create intermediate LUTs*/
assert( decompArray[1] - 1 <= 5 );
Abc_Obj_t * pFanin;
for ( i = 0; i < decompArray[1]; ++i )
{
if ( i < decompArray[1] - 1 )
{
pNewNodes[i] = Abc_NtkCreateNode( pNtkNew );
}
else
{
pNewNodes[i] = pNodeTop;
}
num_fanins = decompArray[byte_p++];
level = 0;
for ( j = 0; j < num_fanins; ++j )
{
fanin = (int)decompArray[byte_p++];
if ( fanin < If_CutLeaveNum(pCutBest) )
{
pFanin = (Abc_Obj_t *)If_ObjCopy( If_CutLeaf(pIfMan, pCutBest, fanin) );
}
else
{
assert( fanin - If_CutLeaveNum(pCutBest) < i );
pFanin = pNewNodes[fanin - If_CutLeaveNum(pCutBest)];
}
Abc_ObjAddFanin( pNewNodes[i], pFanin );
level = Abc_MaxInt( level, Abc_ObjLevel(pFanin) );
}
pNewNodes[i]->Level = level + (int)(Abc_ObjFaninNum(pNewNodes[i]) > 0);
/* extract the truth table */
tt = pIfMan->puTempW;
num_words = ( num_fanins <= 6 ) ? 1 : ( 1 << ( num_fanins - 6 ) );
num_bytes = ( num_fanins <= 3 ) ? 1 : ( 1 << ( Abc_MinInt( (int)num_fanins, 6 ) - 3 ) );
for ( j = 0; j < num_words; ++j )
{
tt[j] = 0;
for ( k = 0; k < num_bytes; ++k )
{
tt[j] |= ( (word)(decompArray[byte_p++]) ) << ( k << 3 );
}
}
/* extend truth table if size < 5 */
assert( num_fanins != 1 );
if ( num_fanins == 2 )
{
tt[0] |= tt[0] << 4;
}
while ( num_bytes < 4 )
{
tt[0] |= tt[0] << ( num_bytes << 3 );
num_bytes <<= 1;
}
/* add node data */
pNewNodes[i]->pData = Kit_TruthToHop( (Hop_Man_t *)pNtkNew->pManFunc, (unsigned *)tt, (int) num_fanins, vCover );
}
/* check correct read */
assert( byte_p == decompArray[0] );
// this is a placeholder, which takes the truth table and converts it into an AIG without LUT-decomposition
extern Hop_Obj_t * Kit_TruthToHop( Hop_Man_t * pMan, unsigned * pTruth, int nVars, Vec_Int_t * vMemory );
word * pTruth = If_CutTruthW(pIfMan, pCutBest);
assert( !pIfMan->pPars->fUseTtPerm );
return Kit_TruthToHop( (Hop_Man_t *)pMan, (unsigned *)pTruth, If_CutLeaveNum(pCutBest), vCover );
}
}
/**Function*************************************************************
@ -488,13 +603,18 @@ Abc_Obj_t * Abc_NodeFromIf_rec( Abc_Ntk_t * pNtkNew, If_Man_t * pIfMan, If_Obj_t
pNodeNew = Abc_NtkCreateNode( pNtkNew );
// if ( pIfMan->pPars->pLutLib && pIfMan->pPars->pLutLib->fVarPinDelays )
if ( !pIfMan->pPars->fDelayOpt && !pIfMan->pPars->fDelayOptLut && !pIfMan->pPars->fDsdBalance && !pIfMan->pPars->fUseTtPerm &&
!pIfMan->pPars->pLutStruct && !pIfMan->pPars->fUserRecLib && !pIfMan->pPars->fUserSesLib && !pIfMan->pPars->fUserLutDec && !pIfMan->pPars->nGateSize )
!pIfMan->pPars->pLutStruct && !pIfMan->pPars->fAcd && !pIfMan->pPars->fUserRecLib && !pIfMan->pPars->fUserSesLib && !pIfMan->pPars->nGateSize )
If_CutRotatePins( pIfMan, pCutBest );
if ( pIfMan->pPars->fUseCnfs || pIfMan->pPars->fUseMv )
{
If_CutForEachLeafReverse( pIfMan, pCutBest, pIfLeaf, i )
Abc_ObjAddFanin( pNodeNew, Abc_NodeFromIf_rec(pNtkNew, pIfMan, pIfLeaf, vCover) );
}
else if ( pIfMan->pPars->fAcd )
{
If_CutForEachLeaf( pIfMan, pCutBest, pIfLeaf, i )
Abc_NodeFromIf_rec(pNtkNew, pIfMan, pIfLeaf, vCover);
}
else
{
If_CutForEachLeaf( pIfMan, pCutBest, pIfLeaf, i )
@ -548,10 +668,10 @@ Abc_Obj_t * Abc_NodeFromIf_rec( Abc_Ntk_t * pNtkNew, If_Man_t * pIfMan, If_Obj_t
extern Hop_Obj_t * Abc_RecToHop3( Hop_Man_t * pMan, If_Man_t * pIfMan, If_Cut_t * pCut, If_Obj_t * pIfObj );
pNodeNew->pData = Abc_RecToHop3( (Hop_Man_t *)pNtkNew->pManFunc, pIfMan, pCutBest, pIfObj );
}
else if ( pIfMan->pPars->fUserLutDec )
else if ( pIfMan->pPars->fAcd )
{
extern Hop_Obj_t * Abc_DecRecordToHop( Hop_Man_t * pMan, If_Man_t * pIfMan, If_Cut_t * pCut, If_Obj_t * pIfObj, Vec_Int_t * vMemory );
pNodeNew->pData = Abc_DecRecordToHop( (Hop_Man_t *)pNtkNew->pManFunc, pIfMan, pCutBest, pIfObj, vCover );
extern void Abc_DecRecordToHop( Abc_Ntk_t * pNtkNew, If_Man_t * pIfMan, If_Cut_t * pCut, If_Obj_t * pIfObj, Vec_Int_t * vMemory, Abc_Obj_t * pNodeTop );
Abc_DecRecordToHop( pNtkNew, pIfMan, pCutBest, pIfObj, vCover, pNodeNew );
}
else
{

View File

@ -40,6 +40,7 @@
#include "opt/dau/dau.h"
#include "misc/vec/vecHash.h"
#include "misc/vec/vecWec.h"
#include "ACD/ac_wrapper.h"
ABC_NAMESPACE_HEADER_START
@ -126,7 +127,6 @@ struct If_Par_t_
int fDsdBalance; // special delay optimization
int fUserRecLib; // use recorded library
int fUserSesLib; // use SAT-based synthesis
int fUserLutDec; // use LUT-based decomposition
int fBidec; // use bi-decomposition
int fUse34Spec; // use specialized matching
int fUseBat; // use one specialized feature
@ -146,6 +146,7 @@ struct If_Par_t_
int fDeriveLuts; // enables deriving LUT structures
int fDoAverage; // optimize average rather than maximum level
int fHashMapping; // perform AIG hashing after mapping
int fAcd; // perform AIG hashing after mapping
int fVerbose; // the verbosity flag
int fVerboseTrace; // the verbosity flag
char * pLutStruct; // LUT structure
@ -280,6 +281,7 @@ struct If_Man_t_
int pDumpIns[16];
Vec_Str_t * vMarks;
Vec_Int_t * vVisited2;
int useLimitAdc;
// timing manager
Tim_Man_t * pManTim;
@ -303,6 +305,7 @@ struct If_Cut_t_
int iCutFunc; // TT ID of the cut
int uMaskFunc; // polarity bitmask
unsigned uSign; // cut signature
unsigned acdDelay; // Computed pin delay during ACD
unsigned Cost : 12; // the user's cost of the cut (related to IF_COST_MAX)
unsigned fCompl : 1; // the complemented attribute
unsigned fUser : 1; // using the user's area and delay
@ -552,6 +555,7 @@ extern int If_CutPerformCheck45( If_Man_t * p, unsigned * pTruth, in
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 );
extern float If_CutDelayLutStruct( If_Man_t * p, If_Cut_t * pCut, char * pStr, float WireDelay );
// extern int If_CutPerformAcd( If_Man_t * p, unsigned nVars, int lutSize, unsigned * pdelay, int use_late_arrival, unsigned * cost );
extern int If_CluCheckExt( void * p, word * pTruth, int nVars, int nLutLeaf, int nLutRoot,
char * pLut0, char * pLut1, word * pFunc0, word * pFunc1 );
extern int If_CluCheckExt3( void * p, word * pTruth, int nVars, int nLutLeaf, int nLutLeaf2, int nLutRoot,
@ -566,6 +570,9 @@ extern int If_CutSopBalancePinDelaysInt( Vec_Int_t * vCover, int * p
extern int If_CutSopBalancePinDelays( If_Man_t * p, If_Cut_t * pCut, char * pPerm );
extern int If_CutLutBalanceEval( If_Man_t * p, If_Cut_t * pCut );
extern int If_CutLutBalancePinDelays( If_Man_t * p, If_Cut_t * pCut, char * pPerm );
extern int If_AcdEval( If_Man_t * p, If_Cut_t * pCut, int best_delay );
extern int If_AcdReEval( If_Man_t * p, If_Cut_t * pCut );
extern float If_AcdLeafProp( If_Man_t * p, If_Cut_t * pCut, int i, float required );
/*=== ifDsd.c =============================================================*/
extern If_DsdMan_t * If_DsdManAlloc( int nVars, int nLutSize );
extern void If_DsdManAllocIsops( If_DsdMan_t * p, int nLutSize );
@ -693,6 +700,8 @@ extern int If_ManCountSpecialPos( If_Man_t * p );
extern void If_CutTraverse( If_Man_t * p, If_Obj_t * pRoot, If_Cut_t * pCut, Vec_Ptr_t * vNodes );
extern void If_ObjPrint( If_Obj_t * pObj );
extern int acd_evaluate( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned *cost );
extern int acd_decompose( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned char *decomposition );
ABC_NAMESPACE_HEADER_END

View File

@ -62,6 +62,7 @@ void If_ManSetDefaultPars( If_Par_t * pPars )
pPars->fPower = 0;
pPars->fCutMin = 0;
pPars->fBidec = 0;
pPars->fAcd = 0;
pPars->fVerbose = 0;
}
@ -106,9 +107,16 @@ int If_ManPerformMappingComb( If_Man_t * p )
If_Obj_t * pObj;
abctime clkTotal = Abc_Clock();
int i;
p->useLimitAdc = 1;
//p->vVisited2 = Vec_IntAlloc( 100 );
//p->vMarks = Vec_StrStart( If_ManObjNum(p) );
// if ( p->pPars->fAcd )
// {
// p->pPars->nLutSize = 6;
// }
// set arrival times and fanout estimates
If_ManForEachCi( p, pObj, i )
{
@ -121,6 +129,16 @@ int If_ManPerformMappingComb( If_Man_t * p )
{
// map for delay
If_ManPerformMappingRound( p, p->pPars->nCutsMax, 0, 1, 1, "Delay" );
if ( p->pPars->fAcd )
{
// p->pPars->nLutSize = oldLutSize;
p->useLimitAdc = 0;
If_ManPerformMappingRound( p, p->pPars->nCutsMax, 0, 1, 0, "Delay" );
p->useLimitAdc = 1;
// p->pPars->nLutSize = 6;
}
// map for delay second option
p->pPars->fFancy = 1;
If_ManResetOriginalRefs( p );

View File

@ -604,10 +604,6 @@ static inline int If_ManSortCompare( If_Man_t * p, If_Cut_t * pC0, If_Cut_t * pC
return -1;
if ( pC0->nLeaves > pC1->nLeaves )
return 1;
if ( pC0->Delay < pC1->Delay - p->fEpsilon )
return -1;
if ( pC0->Delay > pC1->Delay + p->fEpsilon )
return 1;
if ( pC0->fUseless < pC1->fUseless )
return -1;
if ( pC0->fUseless > pC1->fUseless )
@ -765,7 +761,7 @@ void If_CutSort( If_Man_t * p, If_Set_t * pCutSet, If_Cut_t * pCut )
if ( !pCut->fUseless &&
(p->pPars->fUseDsd || p->pPars->pFuncCell2 || p->pPars->fUseBat ||
p->pPars->pLutStruct || p->pPars->fUserRecLib || p->pPars->fUserSesLib || p->pPars->fUserLutDec ||
p->pPars->pLutStruct || p->pPars->fUserRecLib || p->pPars->fUserSesLib || p->pPars->fAcd ||
p->pPars->fEnableCheck07 || p->pPars->fUseCofVars || p->pPars->fUseAndVars || p->pPars->fUse34Spec ||
p->pPars->fUseDsdTune || p->pPars->fEnableCheck75 || p->pPars->fEnableCheck75u || p->pPars->fUseCheck1 || p->pPars->fUseCheck2) )
{

View File

@ -411,6 +411,132 @@ int If_CutLutBalanceEval( If_Man_t * p, If_Cut_t * pCut )
return DelayMax + 2;
}
}
int If_AcdEval( If_Man_t * p, If_Cut_t * pCut, int best_delay )
{
pCut->fUser = 1;
pCut->Cost = pCut->nLeaves > 1 ? 1 : 0;
pCut->acdDelay = 0;
if ( pCut->nLeaves == 0 ) // const
{
assert( Abc_Lit2Var(If_CutTruthLit(pCut)) == 0 );
return 0;
}
if ( pCut->nLeaves == 1 ) // variable
{
assert( Abc_Lit2Var(If_CutTruthLit(pCut)) == 1 );
return (int)If_ObjCutBest(If_CutLeaf(p, pCut, 0))->Delay;
}
// int LutSize = p->pPars->pLutStruct[0] - '0';
int LutSize = 6;
int i, leaf_delay;
int DelayMax = -1, nLeafMax = 0;
unsigned uLeafMask = 0;
for ( i = 0; i < If_CutLeaveNum(pCut); i++ )
{
leaf_delay = If_ObjCutBest(If_CutLeaf(p, pCut, i))->Delay;
if ( DelayMax < leaf_delay )
{
DelayMax = leaf_delay;
nLeafMax = 1;
uLeafMask = (1 << i);
}
else if ( DelayMax == leaf_delay )
{
nLeafMax++;
uLeafMask |= (1 << i);
}
}
if ( If_CutLeaveNum(pCut) <= LutSize )
{
pCut->acdDelay = ( 1 << LutSize ) - 1;
return DelayMax + 1;
}
// else if ( DelayMax + 1 >= best_delay )
// {
// return DelayMax + 2;
// }
/* compute the decomposition */
int use_late_arrival = DelayMax + 2 >= best_delay;
unsigned cost = 1;
/* TODO: have checks based on delay */
if ( use_late_arrival && nLeafMax > LutSize / 2 )
{
pCut->Cost = IF_COST_MAX;
return ABC_INFINITY;
}
/* remove from critical set */
if ( !use_late_arrival )
uLeafMask = 0;
word *pTruth = If_CutTruthW( p, pCut );
int val = acd_evaluate( pTruth, pCut->nLeaves, LutSize, &uLeafMask, &cost );
/* not feasible decomposition */
pCut->acdDelay = uLeafMask;
if ( val < 0 )
{
pCut->Cost = IF_COST_MAX;
return ABC_INFINITY;
}
pCut->Cost = cost;
return DelayMax + ( use_late_arrival ? 1 : 2 );
}
int If_AcdReEval( If_Man_t * p, If_Cut_t * pCut )
{
// pCut->fUser = 1;
if ( pCut->nLeaves == 0 ) // const
{
assert( Abc_Lit2Var(If_CutTruthLit(pCut)) == 0 );
return 0;
}
if ( pCut->nLeaves == 1 ) // variable
{
assert( Abc_Lit2Var(If_CutTruthLit(pCut)) == 1 );
return (int)If_ObjCutBest(If_CutLeaf(p, pCut, 0))->Delay;
}
// int LutSize = p->pPars->pLutStruct[0] - '0';
int LutSize = 6;
int i, leaf_delay;
int DelayMax = -1, nLeafMax = 0;
unsigned uLeafMask = 0;
for ( i = 0; i < If_CutLeaveNum(pCut); i++ )
{
leaf_delay = If_ObjCutBest(If_CutLeaf(p, pCut, i))->Delay;
leaf_delay += ( ( pCut->acdDelay >> i ) & 1 ) == 0 ? 2 : 1;
DelayMax = Abc_MaxInt( leaf_delay, DelayMax );
}
return DelayMax;
}
float If_AcdLeafProp( If_Man_t * p, If_Cut_t * pCut, int i, float required )
{
if ( pCut->nLeaves == 0 ) // const
{
assert( Abc_Lit2Var(If_CutTruthLit(pCut)) == 0 );
return required;
}
if ( pCut->nLeaves == 1 ) // variable
{
assert( Abc_Lit2Var(If_CutTruthLit(pCut)) == 1 );
return 0;
}
return ( ( pCut->acdDelay >> i ) & 1 ) == 0 ? 2 : 1;
}
/*
int If_CutLutBalanceEval( If_Man_t * p, If_Cut_t * pCut )
{

View File

@ -148,32 +148,6 @@ int * If_CutArrTimeProfile( If_Man_t * p, If_Cut_t * pCut )
return p->pArrTimeProfile;
}
/**Function*************************************************************
Synopsis [Returns the node's delay if its cut it LUT-decomposed.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int If_CutDelayLutDec( If_Man_t * p, If_Cut_t * pCut, If_Obj_t * pObj )
{
// get the truth table
// get the cut leaves' arrival times
// run LUT-decomposition in the evaluation mode
// return expected arrival time at the output
// this is a placeholder code, which is assume the cut has unit delay
int i, ArrTimes = 0;
for ( i = 0; i < If_CutLeaveNum(pCut); i++ )
ArrTimes = Abc_MaxInt( ArrTimes, (int)If_ObjCutBest(If_CutLeaf(p, pCut, i))->Delay );
return ArrTimes + 1;
}
/**Function*************************************************************
Synopsis [Finds the best cut for the given node.]
@ -192,7 +166,7 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep
If_Cut_t * pCut0R, * pCut1R;
int fFunc0R, fFunc1R;
int i, k, v, iCutDsd, fChange;
int fSave0 = p->pPars->fDelayOpt || p->pPars->fDelayOptLut || p->pPars->fDsdBalance || p->pPars->fUserRecLib || p->pPars->fUserSesLib || p->pPars->fUserLutDec ||
int fSave0 = p->pPars->fDelayOpt || p->pPars->fDelayOptLut || p->pPars->fDsdBalance || p->pPars->fUserRecLib || p->pPars->fUserSesLib || p->pPars->fAcd ||
p->pPars->fUseDsdTune || p->pPars->fUseCofVars || p->pPars->fUseAndVars || p->pPars->fUse34Spec || p->pPars->pLutStruct || p->pPars->pFuncCell2 || p->pPars->fUseCheck1 || p->pPars->fUseCheck2;
int fUseAndCut = (p->pPars->nAndDelay > 0) || (p->pPars->nAndArea > 0);
assert( !If_ObjIsAnd(pObj->pFanin0) || pObj->pFanin0->pCutSet->nCuts > 0 );
@ -234,8 +208,10 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep
pCut->fUseless = 1;
}
}
else if ( p->pPars->fUserLutDec )
pCut->Delay = If_CutDelayLutDec( p, pCut, pObj );
else if ( p->pPars->fAcd )
{
pCut->Delay = If_AcdReEval( p, pCut );
}
else if ( p->pPars->fDelayOptLut )
pCut->Delay = If_CutLutBalanceEval( p, pCut );
else if( p->pPars->nGateSize > 0 )
@ -292,6 +268,8 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep
if ( !If_CutMergeOrdered( p, pCut0, pCut1, pCut ) )
continue;
}
if ( p->pPars->fAcd && p->useLimitAdc && pCut->nLeaves > 6 )
continue;
if ( pObj->fSpec && pCut->nLeaves == (unsigned)p->pPars->nLutSize )
continue;
p->nCutsMerged++;
@ -450,7 +428,12 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep
else if ( p->pPars->fDsdBalance )
pCut->Delay = If_CutDsdBalanceEval( p, pCut, NULL );
else if ( p->pPars->fUserRecLib )
pCut->Delay = If_CutDelayRecCost3( p, pCut, pObj );
pCut->Delay = If_CutDelayRecCost3( p, pCut, pObj );
else if ( p->pPars->fAcd )
{
pCut->Delay = If_AcdEval( p, pCut, fFirst ? ABC_INFINITY : (int) If_ObjCutBest(pObj)->Delay );
pCut->fUseless = pCut->Delay == ABC_INFINITY;
}
else if ( p->pPars->fUserSesLib )
{
int Cost = 0;
@ -464,8 +447,6 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep
pCut->fUseless = 1;
}
}
else if ( p->pPars->fUserLutDec )
pCut->Delay = If_CutDelayLutDec( p, pCut, pObj );
else if ( p->pPars->fDelayOptLut )
pCut->Delay = If_CutLutBalanceEval( p, pCut );
else if( p->pPars->nGateSize > 0 )
@ -537,7 +518,7 @@ void If_ObjPerformMappingChoice( If_Man_t * p, If_Obj_t * pObj, int Mode, int fP
If_Set_t * pCutSet;
If_Obj_t * pTemp;
If_Cut_t * pCutTemp, * pCut;
int i, fSave0 = p->pPars->fDelayOpt || p->pPars->fDelayOptLut || p->pPars->fDsdBalance || p->pPars->fUserRecLib || p->pPars->fUserSesLib || p->pPars->fUserLutDec || p->pPars->fUse34Spec;
int i, fSave0 = p->pPars->fDelayOpt || p->pPars->fDelayOptLut || p->pPars->fDsdBalance || p->pPars->fUserRecLib || p->pPars->fUserSesLib || p->pPars->fUse34Spec || p->pPars->fAcd;
assert( pObj->pEquiv != NULL );
// prepare

View File

@ -211,6 +211,12 @@ void If_CutPropagateRequired( If_Man_t * p, If_Obj_t * pObj, If_Cut_t * pCut, fl
pLeaf->Required = IF_MIN( pLeaf->Required, Required - pLutDelays[0] );
}
}
else if ( p->pPars->fAcd )
{
Required = ObjRequired;
If_CutForEachLeaf( p, pCut, pLeaf, i )
pLeaf->Required = IF_MIN( pLeaf->Required, Required - If_AcdLeafProp( p, pCut, i, ObjRequired ) );
}
else
{
if ( pCut->fUser )