parent
7d336f3a8a
commit
033306cfe8
|
@ -15,6 +15,8 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <mockturtle/algorithms/aig_balancing.hpp>
|
#include <mockturtle/algorithms/aig_balancing.hpp>
|
||||||
|
#include <mockturtle/algorithms/balancing.hpp>
|
||||||
|
#include <mockturtle/algorithms/balancing/sop_balancing.hpp>
|
||||||
#include <mockturtle/networks/aig.hpp>
|
#include <mockturtle/networks/aig.hpp>
|
||||||
#include <mockturtle/views/depth_view.hpp>
|
#include <mockturtle/views/depth_view.hpp>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -22,6 +24,7 @@
|
||||||
#include "../core/misc.hpp"
|
#include "../core/misc.hpp"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
using namespace mockturtle;
|
||||||
|
|
||||||
namespace alice {
|
namespace alice {
|
||||||
|
|
||||||
|
@ -30,6 +33,7 @@ class balance_command : public command {
|
||||||
explicit balance_command(const environment::ptr& env)
|
explicit balance_command(const environment::ptr& env)
|
||||||
: command(env,
|
: command(env,
|
||||||
"transforms the current network into a well-balanced AIG") {
|
"transforms the current network into a well-balanced AIG") {
|
||||||
|
add_flag("--xmg, -x", "Balance for XMG");
|
||||||
add_flag("--strash, -s", "Balance AND finding structural hashing");
|
add_flag("--strash, -s", "Balance AND finding structural hashing");
|
||||||
add_flag("--verbose, -v", "print the information");
|
add_flag("--verbose, -v", "print the information");
|
||||||
}
|
}
|
||||||
|
@ -38,7 +42,18 @@ class balance_command : public command {
|
||||||
void execute() {
|
void execute() {
|
||||||
clock_t begin, end;
|
clock_t begin, end;
|
||||||
double totalTime = 0.0;
|
double totalTime = 0.0;
|
||||||
|
if (is_set("xmg")) {
|
||||||
|
xmg_network xmg = store<xmg_network>().current();
|
||||||
|
xmg = balancing(
|
||||||
|
xmg,
|
||||||
|
{sop_rebalancing<xmg_network>{}}); // TODO: we need maj-xor balancing
|
||||||
|
xmg = cleanup_dangling(xmg);
|
||||||
|
auto xmg_copy = cleanup_dangling(xmg);
|
||||||
|
phyLS::print_stats(xmg_copy);
|
||||||
|
|
||||||
|
store<xmg_network>().extend();
|
||||||
|
store<xmg_network>().current() = xmg_copy;
|
||||||
|
} else {
|
||||||
if (store<aig_network>().size() == 0u)
|
if (store<aig_network>().size() == 0u)
|
||||||
std::cerr << "Error: Empty AIG network\n";
|
std::cerr << "Error: Empty AIG network\n";
|
||||||
else {
|
else {
|
||||||
|
@ -61,6 +76,7 @@ class balance_command : public command {
|
||||||
store<aig_network>().extend();
|
store<aig_network>().extend();
|
||||||
store<aig_network>().current() = aig;
|
store<aig_network>().current() = aig;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cout.setf(ios::fixed);
|
cout.setf(ios::fixed);
|
||||||
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
|
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
|
||||||
|
|
|
@ -0,0 +1,139 @@
|
||||||
|
/* phyLS: powerful heightened yielded Logic Synthesis
|
||||||
|
* Copyright (C) 2022-2023 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file rm_multi.hpp
|
||||||
|
*
|
||||||
|
* @brief RM logic optimization
|
||||||
|
*
|
||||||
|
* @author Homyoung
|
||||||
|
* @since 2023/11/16
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RM_MP_HPP
|
||||||
|
#define RM_MP_HPP
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <mockturtle/mockturtle.hpp>
|
||||||
|
|
||||||
|
#include "../../core/rm.hpp"
|
||||||
|
|
||||||
|
namespace alice {
|
||||||
|
|
||||||
|
class xagopt_command : public command {
|
||||||
|
public:
|
||||||
|
explicit xagopt_command(const environment::ptr& env)
|
||||||
|
: command(env, "Performs two-level RM logic optimization") {
|
||||||
|
add_option("strategy, -s", strategy, "cut = 0, mffc = 1");
|
||||||
|
add_flag("--minimum_and_gates, -m",
|
||||||
|
"minimum multiplicative complexity in XAG");
|
||||||
|
add_flag("--xag, -g", "RM logic optimization for xag network");
|
||||||
|
add_flag("--xmg, -x", "RM logic optimization for xmg network");
|
||||||
|
add_flag("--cec,-c", "apply equivalence checking in rewriting");
|
||||||
|
}
|
||||||
|
|
||||||
|
rules validity_rules() const {
|
||||||
|
if (is_set("xmg")) {
|
||||||
|
return {has_store_element<xmg_network>(env),
|
||||||
|
{[this]() { return (strategy <= 1 && strategy >= 0); },
|
||||||
|
"strategy must in [0,1] "}};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {has_store_element<xag_network>(env),
|
||||||
|
{[this]() { return (strategy <= 1 && strategy >= 0); },
|
||||||
|
"strategy must in [0,1] "}};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void execute() {
|
||||||
|
if (is_set("xag")) {
|
||||||
|
// clock_t start, end;
|
||||||
|
// start = clock();
|
||||||
|
mockturtle::xag_network xag = store<xag_network>().current();
|
||||||
|
/* parameters */
|
||||||
|
ps_ntk.multiplicative_complexity = is_set("minimum_and_gates");
|
||||||
|
|
||||||
|
if (strategy == 0)
|
||||||
|
ps_ntk.strategy = rm_rewriting_params::cut;
|
||||||
|
else if (strategy == 1)
|
||||||
|
ps_ntk.strategy = rm_rewriting_params::mffc;
|
||||||
|
else
|
||||||
|
assert(false);
|
||||||
|
|
||||||
|
xag_network xag1, xag2;
|
||||||
|
xag1 = xag;
|
||||||
|
|
||||||
|
depth_view depth_xag1(xag);
|
||||||
|
rm_mixed_polarity(depth_xag1, ps_ntk);
|
||||||
|
xag = cleanup_dangling(xag);
|
||||||
|
|
||||||
|
xag2 = xag;
|
||||||
|
|
||||||
|
if (is_set("cec")) {
|
||||||
|
/* equivalence checking */
|
||||||
|
const auto miter_xag = *miter<xag_network>(xag1, xag2);
|
||||||
|
equivalence_checking_stats eq_st;
|
||||||
|
const auto result = equivalence_checking(miter_xag, {}, &eq_st);
|
||||||
|
assert(*result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// end = clock();
|
||||||
|
// std::cout << "run time: " << (double)(end - start) / CLOCKS_PER_SEC
|
||||||
|
// << std::endl;
|
||||||
|
std::cout << "[rm_mixed_polarity] ";
|
||||||
|
phyLS::print_stats(xag);
|
||||||
|
|
||||||
|
store<xag_network>().extend();
|
||||||
|
store<xag_network>().current() = xag;
|
||||||
|
|
||||||
|
} else if (is_set("xmg")) {
|
||||||
|
// clock_t start, end;
|
||||||
|
// start = clock();
|
||||||
|
mockturtle::xmg_network xmg = store<xmg_network>().current();
|
||||||
|
/* parameters */
|
||||||
|
if (strategy == 0)
|
||||||
|
ps_ntk.strategy = rm_rewriting_params::cut;
|
||||||
|
else if (strategy == 1)
|
||||||
|
ps_ntk.strategy = rm_rewriting_params::mffc;
|
||||||
|
else
|
||||||
|
assert(false);
|
||||||
|
|
||||||
|
xmg_network xmg1, xmg2;
|
||||||
|
xmg1 = xmg;
|
||||||
|
|
||||||
|
depth_view depth_xmg1(xmg);
|
||||||
|
rm_mixed_polarity(depth_xmg1, ps_ntk);
|
||||||
|
xmg = cleanup_dangling(xmg);
|
||||||
|
|
||||||
|
xmg2 = xmg;
|
||||||
|
|
||||||
|
if (is_set("cec")) {
|
||||||
|
/* equivalence checking */
|
||||||
|
const auto miter_xmg = *miter<xmg_network>(xmg1, xmg2);
|
||||||
|
equivalence_checking_stats eq_st;
|
||||||
|
const auto result = equivalence_checking(miter_xmg, {}, &eq_st);
|
||||||
|
assert(*result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// end = clock();
|
||||||
|
// std::cout << "run time: " << (double)(end - start) / CLOCKS_PER_SEC
|
||||||
|
// << std::endl;
|
||||||
|
std::cout << "[rm_mixed_polarity] ";
|
||||||
|
phyLS::print_stats(xmg);
|
||||||
|
|
||||||
|
store<xmg_network>().extend();
|
||||||
|
store<xmg_network>().current() = xmg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int strategy = 0;
|
||||||
|
rm_rewriting_params ps_ntk;
|
||||||
|
};
|
||||||
|
|
||||||
|
ALICE_ADD_COMMAND(xagopt, "Synthesis")
|
||||||
|
|
||||||
|
} // namespace alice
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,151 @@
|
||||||
|
/* phyLS: powerful heightened yielded Logic Synthesis
|
||||||
|
* Copyright (C) 2022-2023 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file rm_multi.hpp
|
||||||
|
*
|
||||||
|
* @brief Multilevel RM logic optimization
|
||||||
|
*
|
||||||
|
* @author Homyoung
|
||||||
|
* @since 2023/11/16
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RM_MP2_HPP
|
||||||
|
#define RM_MP2_HPP
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <mockturtle/mockturtle.hpp>
|
||||||
|
|
||||||
|
#include "../../core/rm_multi.hpp"
|
||||||
|
|
||||||
|
namespace alice {
|
||||||
|
|
||||||
|
class xagopt2_command : public command {
|
||||||
|
public:
|
||||||
|
explicit xagopt2_command(const environment::ptr& env)
|
||||||
|
: command(env, "Performs multi-level RM logic optimization") {
|
||||||
|
add_option("strategy, -s", strategy, "cut = 0, mffc = 1");
|
||||||
|
add_flag("--minimum_and_gates, -m",
|
||||||
|
"minimum multiplicative complexity in XAG");
|
||||||
|
add_flag("--xag, -g", "RM logic optimization for xag network");
|
||||||
|
add_flag("--xmg, -x", "RM logic optimization for xmg network");
|
||||||
|
add_flag("--cec,-c", "apply equivalence checking in rewriting");
|
||||||
|
}
|
||||||
|
|
||||||
|
rules validity_rules() const {
|
||||||
|
if (is_set("xmg")) {
|
||||||
|
return {has_store_element<xmg_network>(env),
|
||||||
|
{[this]() { return (strategy <= 1 && strategy >= 0); },
|
||||||
|
"strategy must in [0,1] "}};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {has_store_element<xag_network>(env),
|
||||||
|
{[this]() { return (strategy <= 1 && strategy >= 0); },
|
||||||
|
"strategy must in [0,1] "}};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void execute() {
|
||||||
|
if (is_set("xag")) {
|
||||||
|
// clock_t start, end;
|
||||||
|
// start = clock();
|
||||||
|
mockturtle::xag_network xag = store<xag_network>().current();
|
||||||
|
/* parameters */
|
||||||
|
ps_ntk.multiplicative_complexity = is_set("minimum_and_gates");
|
||||||
|
|
||||||
|
if (strategy == 0)
|
||||||
|
ps_ntk.strategy = rm_rewriting_params2::cut;
|
||||||
|
else if (strategy == 1)
|
||||||
|
ps_ntk.strategy = rm_rewriting_params2::mffc;
|
||||||
|
else
|
||||||
|
assert(false);
|
||||||
|
|
||||||
|
xag_network xag1, xag2;
|
||||||
|
xag1 = xag;
|
||||||
|
|
||||||
|
// depth_view<mockturtle::xag_network,unit_cost<mockturtle::xag_network>>
|
||||||
|
// depth_xag1(xag);
|
||||||
|
cut_rewriting_params ps;
|
||||||
|
ps.cut_enumeration_ps.cut_size = 6;
|
||||||
|
ps.cut_enumeration_ps.cut_limit = 12;
|
||||||
|
ps.min_cand_cut_size = 2;
|
||||||
|
ps.allow_zero_gain = true;
|
||||||
|
ps.progress = true;
|
||||||
|
rm_mixed_polarity2(xag, ps_ntk, ps);
|
||||||
|
xag = cleanup_dangling(xag);
|
||||||
|
|
||||||
|
xag2 = xag;
|
||||||
|
|
||||||
|
if (is_set("cec")) {
|
||||||
|
/* equivalence checking */
|
||||||
|
const auto miter_xag = *miter<xag_network>(xag1, xag2);
|
||||||
|
equivalence_checking_stats eq_st;
|
||||||
|
const auto result = equivalence_checking(miter_xag, {}, &eq_st);
|
||||||
|
assert(*result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// end = clock();
|
||||||
|
// std::cout << "run time: " << (double)(end - start) / CLOCKS_PER_SEC
|
||||||
|
// << std::endl;
|
||||||
|
std::cout << "[rm_mixed_polarity] ";
|
||||||
|
phyLS::print_stats(xag);
|
||||||
|
|
||||||
|
store<xag_network>().extend();
|
||||||
|
store<xag_network>().current() = xag;
|
||||||
|
|
||||||
|
} else if (is_set("xmg")) {
|
||||||
|
// clock_t start, end;
|
||||||
|
// start = clock();
|
||||||
|
mockturtle::xmg_network xmg = store<xmg_network>().current();
|
||||||
|
/* parameters */
|
||||||
|
if (strategy == 0)
|
||||||
|
ps_ntk.strategy = rm_rewriting_params2::cut;
|
||||||
|
else if (strategy == 1)
|
||||||
|
ps_ntk.strategy = rm_rewriting_params2::mffc;
|
||||||
|
else
|
||||||
|
assert(false);
|
||||||
|
|
||||||
|
xmg_network xmg1, xmg2;
|
||||||
|
xmg1 = xmg;
|
||||||
|
|
||||||
|
cut_rewriting_params ps;
|
||||||
|
ps.cut_enumeration_ps.cut_size = 6;
|
||||||
|
ps.cut_enumeration_ps.cut_limit = 12;
|
||||||
|
ps.min_cand_cut_size = 2;
|
||||||
|
ps.allow_zero_gain = true;
|
||||||
|
ps.progress = true;
|
||||||
|
rm_mixed_polarity2(xmg, ps_ntk, ps);
|
||||||
|
xmg = cleanup_dangling(xmg);
|
||||||
|
|
||||||
|
xmg2 = xmg;
|
||||||
|
|
||||||
|
if (is_set("cec")) {
|
||||||
|
/* equivalence checking */
|
||||||
|
const auto miter_xmg = *miter<xmg_network>(xmg1, xmg2);
|
||||||
|
equivalence_checking_stats eq_st;
|
||||||
|
const auto result = equivalence_checking(miter_xmg, {}, &eq_st);
|
||||||
|
assert(*result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// end = clock();
|
||||||
|
// std::cout << "run time: " << (double)(end - start) / CLOCKS_PER_SEC
|
||||||
|
// << std::endl;
|
||||||
|
std::cout << "[rm_mixed_polarity] ";
|
||||||
|
phyLS::print_stats(xmg);
|
||||||
|
|
||||||
|
store<xmg_network>().extend();
|
||||||
|
store<xmg_network>().current() = xmg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int strategy = 0;
|
||||||
|
rm_rewriting_params2 ps_ntk;
|
||||||
|
};
|
||||||
|
|
||||||
|
ALICE_ADD_COMMAND(xagopt2, "Synthesis")
|
||||||
|
|
||||||
|
} // namespace alice
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,64 @@
|
||||||
|
/* phyLS: powerful heightened yielded Logic Synthesis
|
||||||
|
* Copyright (C) 2023 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file xagrs.hpp
|
||||||
|
*
|
||||||
|
* @brief XAG resubsitution
|
||||||
|
*
|
||||||
|
* @author Homyoung
|
||||||
|
* @since 2023/11/16
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XAGRS_HPP
|
||||||
|
#define XAGRS_HPP
|
||||||
|
|
||||||
|
#include <mockturtle/mockturtle.hpp>
|
||||||
|
#include <mockturtle/algorithms/resubstitution.hpp>
|
||||||
|
#include <mockturtle/networks/xag.hpp>
|
||||||
|
|
||||||
|
#include "../../core/misc.hpp"
|
||||||
|
|
||||||
|
namespace alice
|
||||||
|
{
|
||||||
|
|
||||||
|
class xagrs_command : public command
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit xagrs_command( const environment::ptr& env ) : command( env, "Performs XAG resubsitution" )
|
||||||
|
{
|
||||||
|
add_flag( "-v,--verbose", ps.verbose, "show statistics" );
|
||||||
|
}
|
||||||
|
|
||||||
|
rules validity_rules() const
|
||||||
|
{
|
||||||
|
return { has_store_element<xag_network>( env ) };
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void execute()
|
||||||
|
{
|
||||||
|
/* derive some XAG */
|
||||||
|
xag_network xag = store<xag_network>().current();
|
||||||
|
|
||||||
|
default_resubstitution( xag, ps, &st );
|
||||||
|
xag = cleanup_dangling( xag );
|
||||||
|
|
||||||
|
std::cout << "[xagrs] ";
|
||||||
|
phyLS::print_stats( xag );
|
||||||
|
|
||||||
|
store<xag_network>().extend();
|
||||||
|
store<xag_network>().current() = xag;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
resubstitution_params ps;
|
||||||
|
resubstitution_stats st;
|
||||||
|
};
|
||||||
|
|
||||||
|
ALICE_ADD_COMMAND( xagrs, "Synthesis" )
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,95 @@
|
||||||
|
/* phyLS: powerful heightened yielded Logic Synthesis
|
||||||
|
* Copyright (C) 2023 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file xagrw.hpp
|
||||||
|
*
|
||||||
|
* @brief XAG rewriting
|
||||||
|
*
|
||||||
|
* @author Homyoung
|
||||||
|
* @since 2023/11/16
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XAGRW_HPP
|
||||||
|
#define XAGRW_HPP
|
||||||
|
|
||||||
|
#include <mockturtle/algorithms/equivalence_checking.hpp>
|
||||||
|
#include <mockturtle/algorithms/xag_optimization.hpp>
|
||||||
|
#include <mockturtle/mockturtle.hpp>
|
||||||
|
#include <mockturtle/networks/xag.hpp>
|
||||||
|
#include <mockturtle/properties/migcost.hpp>
|
||||||
|
|
||||||
|
#include "../../core/misc.hpp"
|
||||||
|
#include "../../core/xag_rewriting.hpp"
|
||||||
|
// #include <kitty/print.hpp>
|
||||||
|
|
||||||
|
namespace alice {
|
||||||
|
|
||||||
|
class xagrw_command : public command {
|
||||||
|
public:
|
||||||
|
explicit xagrw_command(const environment::ptr& env)
|
||||||
|
: command(env, "Performs XAG rewriting") {
|
||||||
|
add_option("strategy, -s", strategy,
|
||||||
|
"aggressive = 0, selective = 1, dfs = 2");
|
||||||
|
add_flag("--cec, -c,", "apply equivalence checking in rewriting");
|
||||||
|
add_flag("-v,--verbose", "show statistics");
|
||||||
|
}
|
||||||
|
|
||||||
|
rules validity_rules() const {
|
||||||
|
return {has_store_element<xag_network>(env),
|
||||||
|
{[this]() { return (strategy <= 2 && strategy >= 0); },
|
||||||
|
"strategy must in [0,2] "}};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void execute() {
|
||||||
|
xag_network xag = store<xag_network>().current();
|
||||||
|
unsigned num_inv_ori = num_inverters(xag);
|
||||||
|
|
||||||
|
if (strategy == 0) {
|
||||||
|
ps_xag.strategy = xag_depth_rewriting_params::aggressive;
|
||||||
|
} else if (strategy == 1) {
|
||||||
|
ps_xag.strategy = xag_depth_rewriting_params::selective;
|
||||||
|
} else if (strategy == 2) {
|
||||||
|
ps_xag.strategy = xag_depth_rewriting_params::dfs;
|
||||||
|
} else {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
xag_network xag1, xag2;
|
||||||
|
xag1 = xag;
|
||||||
|
|
||||||
|
depth_view depth_xag1(xag);
|
||||||
|
xag_depth_rewriting(depth_xag1, ps_xag);
|
||||||
|
xag = cleanup_dangling(xag);
|
||||||
|
|
||||||
|
xag2 = xag;
|
||||||
|
|
||||||
|
if (is_set("cec")) {
|
||||||
|
/* equivalence checking */
|
||||||
|
const auto miter_xag = *miter<xag_network>(xag1, xag2);
|
||||||
|
equivalence_checking_stats eq_st;
|
||||||
|
const auto result = equivalence_checking(miter_xag, {}, &eq_st);
|
||||||
|
assert(*result);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned num_inv_opt = num_inverters(xag);
|
||||||
|
|
||||||
|
std::cout << "[xagrw] ";
|
||||||
|
phyLS::print_stats(xag);
|
||||||
|
// std::cout << "num_inv_ori:" << num_inv_ori <<std::endl;
|
||||||
|
// std::cout << "num_inv_opt:" << num_inv_opt << std::endl;
|
||||||
|
|
||||||
|
store<xag_network>().extend();
|
||||||
|
store<xag_network>().current() = xag;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
xag_depth_rewriting_params ps_xag;
|
||||||
|
int strategy = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
ALICE_ADD_COMMAND(xagrw, "Synthesis")
|
||||||
|
} // namespace alice
|
||||||
|
|
||||||
|
#endif
|
|
@ -16,7 +16,7 @@
|
||||||
#include <mockturtle/mockturtle.hpp>
|
#include <mockturtle/mockturtle.hpp>
|
||||||
#include <mockturtle/utils/stopwatch.hpp>
|
#include <mockturtle/utils/stopwatch.hpp>
|
||||||
|
|
||||||
#include "../core/xmginv.hpp"
|
#include "../../core/xmginv.hpp"
|
||||||
|
|
||||||
namespace alice {
|
namespace alice {
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
/* phyLS: powerful heightened yielded Logic Synthesis
|
||||||
|
* Copyright (C) 2023 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file xmgrs.hpp
|
||||||
|
*
|
||||||
|
* @brief XMG resubsitution
|
||||||
|
*
|
||||||
|
* @author Homyoung
|
||||||
|
* @since 2023/11/16
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XMGRS_HPP
|
||||||
|
#define XMGRS_HPP
|
||||||
|
|
||||||
|
#include <mockturtle/algorithms/xmg_resub.hpp>
|
||||||
|
#include <mockturtle/mockturtle.hpp>
|
||||||
|
#include <mockturtle/networks/xmg.hpp>
|
||||||
|
|
||||||
|
#include "../../core/misc.hpp"
|
||||||
|
|
||||||
|
namespace alice {
|
||||||
|
|
||||||
|
class xmgrs_command : public command {
|
||||||
|
public:
|
||||||
|
explicit xmgrs_command(const environment::ptr& env)
|
||||||
|
: command(env, "Performs XMG resubsitution") {
|
||||||
|
add_flag("-v,--verbose", ps.verbose, "show statistics");
|
||||||
|
add_flag("--cec,-c", "apply equivalence checking in resubstitution");
|
||||||
|
}
|
||||||
|
|
||||||
|
rules validity_rules() const { return {has_store_element<xmg_network>(env)}; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void execute() {
|
||||||
|
/* derive some XMG */
|
||||||
|
xmg_network xmg = store<xmg_network>().current();
|
||||||
|
|
||||||
|
xmg_network xmg1, xmg2;
|
||||||
|
xmg1 = xmg;
|
||||||
|
xmg2 = xmg;
|
||||||
|
|
||||||
|
using view_t = depth_view<fanout_view<xmg_network>>;
|
||||||
|
fanout_view<xmg_network> fanout_view{xmg1};
|
||||||
|
view_t resub_view{fanout_view};
|
||||||
|
xmg_resubstitution(resub_view);
|
||||||
|
xmg2 = cleanup_dangling(xmg1);
|
||||||
|
|
||||||
|
std::cout << "[xmgrs] ";
|
||||||
|
auto xmg_copy = cleanup_dangling(xmg2);
|
||||||
|
phyLS::print_stats(xmg_copy);
|
||||||
|
|
||||||
|
if (is_set("cec")) {
|
||||||
|
const auto miter_xmg = *miter<xmg_network>(xmg1, xmg2);
|
||||||
|
equivalence_checking_stats eq_st;
|
||||||
|
const auto result = equivalence_checking(miter_xmg, {}, &eq_st);
|
||||||
|
assert(result);
|
||||||
|
assert(*result);
|
||||||
|
std::cout << "Network is equivalent after resub\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
store<xmg_network>().extend();
|
||||||
|
store<xmg_network>().current() = xmg2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
resubstitution_params ps;
|
||||||
|
resubstitution_stats st;
|
||||||
|
};
|
||||||
|
|
||||||
|
ALICE_ADD_COMMAND(xmgrs, "Synthesis")
|
||||||
|
|
||||||
|
} // namespace alice
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,145 @@
|
||||||
|
/* phyLS: powerful heightened yielded Logic Synthesis
|
||||||
|
* Copyright (C) 2023 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file xmgrw.hpp
|
||||||
|
*
|
||||||
|
* @brief algebraic XMG rewriting
|
||||||
|
*
|
||||||
|
* @author Homyoung
|
||||||
|
* @since 2023/11/16
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XMGRW_COMMAND_HPP
|
||||||
|
#define XMGRW_COMMAND_HPP
|
||||||
|
|
||||||
|
#include <mockturtle/algorithms/equivalence_checking.hpp>
|
||||||
|
#include <mockturtle/algorithms/mig_algebraic_rewriting.hpp>
|
||||||
|
#include <mockturtle/networks/xmg.hpp>
|
||||||
|
#include <mockturtle/views/depth_view.hpp>
|
||||||
|
|
||||||
|
#include "../../core/misc.hpp"
|
||||||
|
#include "../../core/xmg_expand.hpp"
|
||||||
|
#include "../../core/xmg_extract.hpp"
|
||||||
|
#include "../../core/xmg_rewriting.hpp"
|
||||||
|
|
||||||
|
namespace alice {
|
||||||
|
|
||||||
|
class xmgrw_command : public command {
|
||||||
|
public:
|
||||||
|
explicit xmgrw_command(const environment::ptr& env)
|
||||||
|
: command(env, "Performs algebraic XMG rewriting") {
|
||||||
|
add_option("strategy, -s", strategy,
|
||||||
|
"qca = 0, aggressive = 1, selective = 2, dfs = 3");
|
||||||
|
add_flag("--area_aware, -a", "do not increase area");
|
||||||
|
add_flag("--xor3_flattan", "flattan xor3 to 2 xor2s");
|
||||||
|
add_flag("--only_maj", "apply mig_algebraic_depth_rewriting method");
|
||||||
|
add_flag("--cec,-c", "apply equivalence checking in rewriting");
|
||||||
|
add_flag("--expand,-e", "apply xor expand through maj");
|
||||||
|
add_flag("--hunt_constant_xor,-u", "hunt XOR constant nodes");
|
||||||
|
}
|
||||||
|
|
||||||
|
rules validity_rules() const {
|
||||||
|
return {has_store_element<xmg_network>(env),
|
||||||
|
{[this]() { return (strategy <= 3 && strategy >= 0); },
|
||||||
|
"strategy must in [0,3] "}};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void execute() {
|
||||||
|
xmg_network xmg = store<xmg_network>().current();
|
||||||
|
|
||||||
|
if (is_set("only_maj")) {
|
||||||
|
/* parameters */
|
||||||
|
ps_mig.allow_area_increase = !is_set("area_aware");
|
||||||
|
|
||||||
|
if (strategy == 0) {
|
||||||
|
ps_mig.strategy = mig_algebraic_depth_rewriting_params::dfs;
|
||||||
|
} else if (strategy == 1) {
|
||||||
|
ps_mig.strategy = mig_algebraic_depth_rewriting_params::aggressive;
|
||||||
|
} else if (strategy == 2) {
|
||||||
|
ps_mig.strategy = mig_algebraic_depth_rewriting_params::selective;
|
||||||
|
} else {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
depth_view depth_xmg{xmg};
|
||||||
|
mig_algebraic_depth_rewriting(depth_xmg, ps_mig);
|
||||||
|
xmg = cleanup_dangling(xmg);
|
||||||
|
} else if (is_set("hunt_constant_xor")) {
|
||||||
|
auto xors = phyLS::xmg_extract(xmg);
|
||||||
|
ps_expand.strategy = xmg_expand_rewriting_params::constants;
|
||||||
|
ps_expand.xor_index = xors;
|
||||||
|
|
||||||
|
depth_view depth_xmg{xmg};
|
||||||
|
xmg_expand_rewriting(depth_xmg, ps_expand);
|
||||||
|
xmg = cleanup_dangling(xmg);
|
||||||
|
} else if (is_set("expand")) {
|
||||||
|
ps_expand.strategy = xmg_expand_rewriting_params::expand;
|
||||||
|
depth_view depth_xmg{xmg};
|
||||||
|
xmg_expand_rewriting(depth_xmg, ps_expand);
|
||||||
|
xmg = cleanup_dangling(xmg);
|
||||||
|
} else {
|
||||||
|
/* parameters */
|
||||||
|
ps_xmg.allow_area_increase = !is_set("area_aware");
|
||||||
|
ps_xmg.apply_xor3_to_xor2 = is_set("xor3_flattan");
|
||||||
|
ps_mig.allow_area_increase = !is_set("area_aware");
|
||||||
|
|
||||||
|
if (strategy == 0) {
|
||||||
|
ps_xmg.strategy = xmg_depth_rewriting_params::qca;
|
||||||
|
ps_mig.strategy = mig_algebraic_depth_rewriting_params::dfs;
|
||||||
|
} else if (strategy == 1) {
|
||||||
|
ps_xmg.strategy = xmg_depth_rewriting_params::aggressive;
|
||||||
|
ps_mig.strategy = mig_algebraic_depth_rewriting_params::aggressive;
|
||||||
|
} else if (strategy == 2) {
|
||||||
|
ps_xmg.strategy = xmg_depth_rewriting_params::selective;
|
||||||
|
ps_mig.strategy = mig_algebraic_depth_rewriting_params::selective;
|
||||||
|
} else if (strategy == 3) {
|
||||||
|
ps_xmg.strategy = xmg_depth_rewriting_params::dfs;
|
||||||
|
ps_mig.strategy = mig_algebraic_depth_rewriting_params::dfs;
|
||||||
|
} else {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
xmg_network xmg1, xmg2;
|
||||||
|
xmg1 = xmg;
|
||||||
|
|
||||||
|
/* mig_algebraic_depth_rewriting is suitable for ntk that has majority
|
||||||
|
* nodes */
|
||||||
|
depth_view depth_xmg1{xmg};
|
||||||
|
mig_algebraic_depth_rewriting(depth_xmg1, ps_mig);
|
||||||
|
xmg = cleanup_dangling(xmg);
|
||||||
|
|
||||||
|
depth_view depth_xmg2{xmg};
|
||||||
|
xmg_depth_rewriting(depth_xmg2, ps_xmg);
|
||||||
|
xmg = cleanup_dangling(xmg);
|
||||||
|
xmg2 = xmg;
|
||||||
|
|
||||||
|
if (is_set("cec")) {
|
||||||
|
/* equivalence checking */
|
||||||
|
const auto miter_xmg = *miter<xmg_network>(xmg1, xmg2);
|
||||||
|
equivalence_checking_stats eq_st;
|
||||||
|
const auto result = equivalence_checking(miter_xmg, {}, &eq_st);
|
||||||
|
assert(*result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "[xmgrw] ";
|
||||||
|
auto xmg_copy = cleanup_dangling(xmg);
|
||||||
|
phyLS::print_stats(xmg_copy);
|
||||||
|
|
||||||
|
store<xmg_network>().extend();
|
||||||
|
store<xmg_network>().current() = xmg;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
mig_algebraic_depth_rewriting_params ps_mig;
|
||||||
|
xmg_depth_rewriting_params ps_xmg;
|
||||||
|
xmg_expand_rewriting_params ps_expand;
|
||||||
|
int strategy = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
ALICE_ADD_COMMAND(xmgrw, "Synthesis")
|
||||||
|
} // namespace alice
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,824 @@
|
||||||
|
/* phyLS: powerful heightened yielded Logic Synthesis
|
||||||
|
* Copyright (C) 2022-2023 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file rm_multi.hpp
|
||||||
|
*
|
||||||
|
* @brief RM logic optimization
|
||||||
|
*
|
||||||
|
* @author Homyoung
|
||||||
|
* @since 2023/11/16
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
#include <iostream>
|
||||||
|
#include <mockturtle/mockturtle.hpp>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace mockturtle {
|
||||||
|
|
||||||
|
/*! \brief Parameters for rm_logic_optimization.
|
||||||
|
*
|
||||||
|
* The data structure `rm_logic_optimization` holds configurable
|
||||||
|
* parameters with default arguments for `rm_logic_optimization`.
|
||||||
|
*/
|
||||||
|
struct rm_rewriting_params {
|
||||||
|
/*! \brief Rewriting strategy. */
|
||||||
|
enum strategy_t {
|
||||||
|
/*! \brief Cut is used to divide the network. */
|
||||||
|
cut,
|
||||||
|
/*! \brief mffc is used to divide the network. */
|
||||||
|
mffc,
|
||||||
|
} strategy = cut;
|
||||||
|
|
||||||
|
/*! \brief minimum multiplicative complexity in XAG. */
|
||||||
|
bool multiplicative_complexity{false};
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template <class Ntk>
|
||||||
|
class rm_mixed_polarity_impl {
|
||||||
|
public:
|
||||||
|
using node_t = node<Ntk>;
|
||||||
|
using signal_t = signal<Ntk>;
|
||||||
|
|
||||||
|
rm_mixed_polarity_impl(Ntk& ntk, rm_rewriting_params const& ps_ntk)
|
||||||
|
: ntk(ntk), ps_ntk(ps_ntk) {}
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
switch (ps_ntk.strategy) {
|
||||||
|
case rm_rewriting_params::cut:
|
||||||
|
ntk_cut();
|
||||||
|
break;
|
||||||
|
case rm_rewriting_params::mffc:
|
||||||
|
ntk_mffc();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/* for cost estimation we use reference counters initialized by the fanout
|
||||||
|
* size. */
|
||||||
|
void initialize_refs(Ntk& ntk1) {
|
||||||
|
ntk1.clear_values();
|
||||||
|
ntk1.foreach_node(
|
||||||
|
[&](auto const& n) { ntk1.set_value(n, ntk1.fanout_size(n)); });
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/* Count the number of and gates. */
|
||||||
|
int count_node_num(vector<string>& minterm, int variate_num,
|
||||||
|
string polarity) {
|
||||||
|
int count = 0;
|
||||||
|
if (variate_num > 1) {
|
||||||
|
for (int i = 0; i < minterm.size(); i++) {
|
||||||
|
int count1 = 0;
|
||||||
|
for (int j = 0; j < variate_num; j++) {
|
||||||
|
if (minterm[i][j] == '1' || polarity[j] == '2') count1++;
|
||||||
|
}
|
||||||
|
if (count1 > 0) count = count + count1 - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/* Convert ternary to decimal. */
|
||||||
|
int atoint(string s, int radix) {
|
||||||
|
int ans = 0;
|
||||||
|
for (int i = 0; i < s.size(); i++) {
|
||||||
|
char t = s[i];
|
||||||
|
if (t >= '0' && t <= '9')
|
||||||
|
ans = ans * radix + t - '0';
|
||||||
|
else
|
||||||
|
ans = ans * radix + t - 'a' + 10;
|
||||||
|
}
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/* Convert decimal to ternary. */
|
||||||
|
string intToA(int n, int radix) {
|
||||||
|
string ans = "";
|
||||||
|
do {
|
||||||
|
int t = n % radix;
|
||||||
|
if (t >= 0 && t <= 9)
|
||||||
|
ans += t + '0';
|
||||||
|
else
|
||||||
|
ans += t - 10 + 'a';
|
||||||
|
n /= radix;
|
||||||
|
} while (n != 0);
|
||||||
|
reverse(ans.begin(), ans.end());
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/* create signal by expression. */
|
||||||
|
signal_t create_ntk_from_str(std::string const& s,
|
||||||
|
std::vector<node_t> const& leaves) {
|
||||||
|
std::vector<signal_t> pis;
|
||||||
|
pis.clear();
|
||||||
|
for (const auto& l : leaves) {
|
||||||
|
pis.push_back(ntk.make_signal(l));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stack<signal_t> inputs;
|
||||||
|
int flag = 0;
|
||||||
|
int flag1 = 0;
|
||||||
|
|
||||||
|
for (auto i = 0; i < s.size(); i++) {
|
||||||
|
if (s[i] == '[') {
|
||||||
|
continue;
|
||||||
|
} else if (s[i] == '(') {
|
||||||
|
continue;
|
||||||
|
} else if (s[i] == '1') {
|
||||||
|
flag1 = 1;
|
||||||
|
continue;
|
||||||
|
} else if (s[i] >= 'a') {
|
||||||
|
if (flag == 1) {
|
||||||
|
inputs.push(ntk.create_not(pis[s[i] - 'a']));
|
||||||
|
flag = 0;
|
||||||
|
} else
|
||||||
|
inputs.push(pis[s[i] - 'a']);
|
||||||
|
} else if (s[i] == ')') {
|
||||||
|
auto x1 = inputs.top();
|
||||||
|
inputs.pop();
|
||||||
|
|
||||||
|
auto x2 = inputs.top();
|
||||||
|
inputs.pop();
|
||||||
|
|
||||||
|
inputs.push(ntk.create_and(x1, x2));
|
||||||
|
} else if (s[i] == ']') {
|
||||||
|
if (flag1 == 1) {
|
||||||
|
auto x1 = inputs.top();
|
||||||
|
inputs.pop();
|
||||||
|
inputs.push(ntk.create_not(x1));
|
||||||
|
flag1 = 0;
|
||||||
|
} else {
|
||||||
|
auto x1 = inputs.top();
|
||||||
|
inputs.pop();
|
||||||
|
|
||||||
|
auto x2 = inputs.top();
|
||||||
|
inputs.pop();
|
||||||
|
inputs.push(ntk.create_xor(x1, x2));
|
||||||
|
}
|
||||||
|
} else if (s[i] == '!') {
|
||||||
|
flag = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return inputs.top();
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/* List all possible variable values/List truth table. */
|
||||||
|
vector<string> list_truth_table(int& variate_num) {
|
||||||
|
int a = pow(2, variate_num);
|
||||||
|
vector<int> b;
|
||||||
|
for (int i = 0; i < a; i++) {
|
||||||
|
b.push_back(i);
|
||||||
|
}
|
||||||
|
vector<string> binary;
|
||||||
|
for (int i = 0; i < a; i++) {
|
||||||
|
string binary1;
|
||||||
|
for (int j = variate_num - 1; j >= 0; j--) {
|
||||||
|
int d = ((b[i] >> j) & 1);
|
||||||
|
binary1 += d + 48;
|
||||||
|
}
|
||||||
|
binary.push_back(binary1);
|
||||||
|
}
|
||||||
|
return binary;
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/* List all possible polarity values. */
|
||||||
|
vector<string> list_all_polarities(int& variate_num) {
|
||||||
|
int a_1 = pow(2, variate_num);
|
||||||
|
vector<int> c;
|
||||||
|
for (int i = 0; i < a_1; i++) {
|
||||||
|
c.push_back(i);
|
||||||
|
}
|
||||||
|
vector<string> polarity1;
|
||||||
|
for (int i = 0; i < a_1; i++) {
|
||||||
|
string polarity2;
|
||||||
|
for (int j = variate_num - 1; j >= 0; j--) {
|
||||||
|
int d = ((c[i] >> j) & 1);
|
||||||
|
polarity2 += d + 48;
|
||||||
|
}
|
||||||
|
polarity1.push_back(polarity2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store all polarities. */
|
||||||
|
vector<string> polarity;
|
||||||
|
polarity.push_back(polarity1[0]);
|
||||||
|
int a2 = pow(3, variate_num);
|
||||||
|
string str1 = polarity1[0];
|
||||||
|
string str2 = polarity1[1];
|
||||||
|
for (int i = 0; i < a2 - 1; i++) {
|
||||||
|
int num1 = atoint(str1, 3);
|
||||||
|
int num2 = atoint(str2, 3);
|
||||||
|
|
||||||
|
int sum = num1 + num2;
|
||||||
|
string str3 = intToA(sum, 3);
|
||||||
|
|
||||||
|
str1 = "0";
|
||||||
|
if (str3.size() < variate_num) {
|
||||||
|
for (int i = 0; i < variate_num - str3.size() - 1; i++) str1 += '0';
|
||||||
|
|
||||||
|
str1 += str3;
|
||||||
|
} else
|
||||||
|
str1 = str3;
|
||||||
|
|
||||||
|
polarity.push_back(str1);
|
||||||
|
}
|
||||||
|
return polarity;
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/* Mixed polarity conversion algorithm based on list technique. */
|
||||||
|
vector<string> polarity_conversion(int& variate_num, vector<string>& minterm,
|
||||||
|
string& polarity) {
|
||||||
|
vector<string> RM_product = minterm;
|
||||||
|
string str;
|
||||||
|
for (int i = 0; i < variate_num; i++) {
|
||||||
|
for (int j = 0; j < RM_product.size(); j++) {
|
||||||
|
if (polarity[i] == '0') {
|
||||||
|
if (RM_product[j][i] == '0') {
|
||||||
|
str = RM_product[j];
|
||||||
|
str[i] = '1';
|
||||||
|
RM_product.push_back(str);
|
||||||
|
}
|
||||||
|
} else if (polarity[i] == '1') {
|
||||||
|
if (RM_product[j][i] == '1') {
|
||||||
|
str = RM_product[j];
|
||||||
|
str[i] = '0';
|
||||||
|
RM_product.push_back(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (polarity[i] == '0') {
|
||||||
|
/* Delete the minimum number of even items. */
|
||||||
|
if (RM_product.size() > 0) {
|
||||||
|
sort(RM_product.begin(), RM_product.end());
|
||||||
|
for (int m = 0; m < RM_product.size() - 1; m++) {
|
||||||
|
if (RM_product[m] == RM_product[m + 1]) {
|
||||||
|
RM_product[m] = "0";
|
||||||
|
RM_product[m + 1] = "0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Delete item with '0' in array. */
|
||||||
|
vector<string> final_term;
|
||||||
|
final_term.clear();
|
||||||
|
for (int m = 0; m < RM_product.size(); m++) {
|
||||||
|
if (RM_product[m] != "0") final_term.push_back(RM_product[m]);
|
||||||
|
}
|
||||||
|
RM_product.clear();
|
||||||
|
RM_product = final_term;
|
||||||
|
} else if (polarity[i] == '1') {
|
||||||
|
/* Delete the minimum number of even items. */
|
||||||
|
if (RM_product.size() > 0) {
|
||||||
|
sort(RM_product.begin(), RM_product.end());
|
||||||
|
for (int m = 0; m < RM_product.size() - 1; m++) {
|
||||||
|
if (RM_product[m] == RM_product[m + 1]) {
|
||||||
|
RM_product[m] = "0";
|
||||||
|
RM_product[m + 1] = "0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Delete item with '0' in array. */
|
||||||
|
vector<string> final_term;
|
||||||
|
final_term.clear();
|
||||||
|
for (int m = 0; m < RM_product.size(); m++) {
|
||||||
|
if (RM_product[m] != "0") {
|
||||||
|
if (RM_product[m][i] == '0')
|
||||||
|
RM_product[m][i] = '1';
|
||||||
|
else if (RM_product[m][i] == '1')
|
||||||
|
RM_product[m][i] = '0';
|
||||||
|
final_term.push_back(RM_product[m]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RM_product.clear();
|
||||||
|
RM_product = final_term;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return RM_product;
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/* Search for the optimal polarity and the corresponding product term. */
|
||||||
|
void search_for_optimal_polarity(vector<string>& minterm,
|
||||||
|
vector<string>& polarity, int& variate_num,
|
||||||
|
vector<string>& RM_product,
|
||||||
|
string& optimal_polarity) {
|
||||||
|
vector<string> RM_product_initial;
|
||||||
|
for (int l = 0; l < polarity.size(); l++) {
|
||||||
|
RM_product_initial =
|
||||||
|
polarity_conversion(variate_num, minterm, polarity[l]);
|
||||||
|
|
||||||
|
int count1, count2;
|
||||||
|
count1 = count_the_number_of_nodes(variate_num, RM_product_initial,
|
||||||
|
polarity[l]);
|
||||||
|
count2 =
|
||||||
|
count_the_number_of_nodes(variate_num, RM_product, optimal_polarity);
|
||||||
|
if (count1 < count2) {
|
||||||
|
optimal_polarity = polarity[l];
|
||||||
|
RM_product.clear();
|
||||||
|
RM_product = RM_product_initial;
|
||||||
|
RM_product_initial.clear();
|
||||||
|
} else {
|
||||||
|
RM_product_initial.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/* Count the number of nodes in the new network. */
|
||||||
|
int count_the_number_of_nodes(int& variate_num, vector<string>& RM_product,
|
||||||
|
string& optimal_polarity) {
|
||||||
|
/* Count the number of nodes. */
|
||||||
|
int node_num = 0;
|
||||||
|
if (RM_product.size() > 1) node_num = RM_product.size() - 1;
|
||||||
|
|
||||||
|
if (variate_num > 1) {
|
||||||
|
for (int i = 0; i < RM_product.size(); i++) {
|
||||||
|
int n = 0;
|
||||||
|
for (int j = variate_num - 1; j >= 0; j--) {
|
||||||
|
if (RM_product[i][j] == '1' || optimal_polarity[j] == '2') n++;
|
||||||
|
}
|
||||||
|
if (n > 0) node_num = node_num + n - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return node_num;
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/* Create expression. */
|
||||||
|
string create_expression(vector<string>& RM_product, int& variate_num,
|
||||||
|
string& optimal_polarity, vector<string>& binary) {
|
||||||
|
string st = "abcdefghijklmnopqrstuvwxyz";
|
||||||
|
string expression = "";
|
||||||
|
if (RM_product.size() > 1)
|
||||||
|
for (int i = 0; i < RM_product.size() - 1; i++) expression += '[';
|
||||||
|
for (int i = 0; i < RM_product.size(); i++) {
|
||||||
|
int k = 0;
|
||||||
|
int l = 0;
|
||||||
|
int m = 0;
|
||||||
|
for (int j = variate_num - 1; j >= 0; j--) {
|
||||||
|
if (RM_product[i][j] == '1' || optimal_polarity[j] == '2') l++;
|
||||||
|
}
|
||||||
|
for (int j = 0; j < l - 1; j++) expression += '(';
|
||||||
|
for (int j = variate_num - 1; j >= 0; j--) {
|
||||||
|
if (optimal_polarity[j] == '0' && RM_product[i][j] == '1') {
|
||||||
|
expression += st[k];
|
||||||
|
m++;
|
||||||
|
} else if (optimal_polarity[j] == '1' && RM_product[i][j] == '1') {
|
||||||
|
expression += '!';
|
||||||
|
expression += st[k];
|
||||||
|
m++;
|
||||||
|
} else if (optimal_polarity[j] == '2' && RM_product[i][j] == '1') {
|
||||||
|
expression += st[k];
|
||||||
|
m++;
|
||||||
|
} else if (optimal_polarity[j] == '2' && RM_product[i][j] == '0') {
|
||||||
|
expression += '!';
|
||||||
|
expression += st[k];
|
||||||
|
m++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((m > 1 && RM_product[i][j] == '1') ||
|
||||||
|
(m > 1 && optimal_polarity[j] == '2'))
|
||||||
|
expression += ')';
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
if (RM_product[i] == binary[0]) {
|
||||||
|
int flag = 0;
|
||||||
|
for (int m = variate_num - 1; m >= 0; m--) {
|
||||||
|
if (optimal_polarity[m] == '2') flag = 1;
|
||||||
|
}
|
||||||
|
if (flag == 0) expression += '1';
|
||||||
|
}
|
||||||
|
if (i > 0 && RM_product.size() > 1) expression += ']';
|
||||||
|
}
|
||||||
|
return expression;
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/* Replace network. */
|
||||||
|
void substitute_network_mffc(string& expression, std::vector<node_t>& leaves,
|
||||||
|
node_t n) {
|
||||||
|
auto opt = create_ntk_from_str(expression, leaves);
|
||||||
|
ntk.substitute_node(n, opt);
|
||||||
|
ntk.set_value(n, 0);
|
||||||
|
ntk.set_value(ntk.get_node(opt), ntk.fanout_size(ntk.get_node(opt)));
|
||||||
|
for (auto i = 0u; i < leaves.size(); i++) {
|
||||||
|
ntk.set_value(leaves[i], ntk.fanout_size(leaves[i]));
|
||||||
|
}
|
||||||
|
ntk.update_levels();
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/* Replace network. */
|
||||||
|
void substitute_network_cut(string& expression, std::vector<node_t>& leaves,
|
||||||
|
node_t n) {
|
||||||
|
auto opt = create_ntk_from_str(expression, leaves);
|
||||||
|
ntk.substitute_node(n, opt);
|
||||||
|
ntk.update_levels();
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/* get children of top node, ordered by node level (ascending). */
|
||||||
|
vector<signal<Ntk>> ordered_children(node<Ntk> const& n) const {
|
||||||
|
vector<signal<Ntk>> children;
|
||||||
|
ntk.foreach_fanin(n, [&children](auto const& f) { children.push_back(f); });
|
||||||
|
std::sort(
|
||||||
|
children.begin(), children.end(),
|
||||||
|
[this](auto const& c1, auto const& c2) {
|
||||||
|
if (ntk.level(ntk.get_node(c1)) == ntk.level(ntk.get_node(c2))) {
|
||||||
|
return c1.index < c2.index;
|
||||||
|
} else {
|
||||||
|
return ntk.level(ntk.get_node(c1)) < ntk.level(ntk.get_node(c2));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/* Judge whether the leaf node is reached. */
|
||||||
|
int is_existence(long int root, vector<signal_t> pis) {
|
||||||
|
int flag = 0;
|
||||||
|
for (int i = 0; i < pis.size(); i++) {
|
||||||
|
if (root == ntk.get_node(pis[i])) {
|
||||||
|
flag = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/* Hierarchical ergodic statistics AND gates node cost function. */
|
||||||
|
void LevelOrder(long int root, vector<signal_t> pis,
|
||||||
|
int& optimization_and_nodes) {
|
||||||
|
int a = 0;
|
||||||
|
int b = 0;
|
||||||
|
if (is_existence(root, pis) == 1) return;
|
||||||
|
/* Create a queue container. */
|
||||||
|
queue<long int> deq;
|
||||||
|
|
||||||
|
deq.push(root);
|
||||||
|
while (!deq.empty()) {
|
||||||
|
long int tr = deq.front();
|
||||||
|
deq.pop();
|
||||||
|
|
||||||
|
vector<signal<Ntk>> ocs;
|
||||||
|
ocs.clear();
|
||||||
|
/* get children of top node, ordered by node level (ascending). */
|
||||||
|
ocs = ordered_children(tr);
|
||||||
|
|
||||||
|
if (ocs.size() == 2 && is_existence(ntk.get_node(ocs[0]), pis) != 1) {
|
||||||
|
deq.push(ntk.get_node(ocs[0]));
|
||||||
|
if (ntk.is_and(ntk.get_node(ocs[0])) &&
|
||||||
|
ntk.fanout_size(ntk.get_node(ocs[0])) != 1u && a == 0) {
|
||||||
|
optimization_and_nodes = optimization_and_nodes - 1;
|
||||||
|
a = 1;
|
||||||
|
} else if (ntk.is_and(ntk.get_node(ocs[0])) && a == 1)
|
||||||
|
optimization_and_nodes = optimization_and_nodes - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ocs.size() == 2 && is_existence(ntk.get_node(ocs[1]), pis) != 1) {
|
||||||
|
deq.push(ntk.get_node(ocs[1]));
|
||||||
|
if (ntk.is_and(ntk.get_node(ocs[1])) &&
|
||||||
|
ntk.fanout_size(ntk.get_node(ocs[1])) != 1u && b == 0) {
|
||||||
|
optimization_and_nodes = optimization_and_nodes - 1;
|
||||||
|
b = 1;
|
||||||
|
} else if (ntk.is_and(ntk.get_node(ocs[1])) && b == 1)
|
||||||
|
optimization_and_nodes = optimization_and_nodes - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/* Cut is used to divide the network. */
|
||||||
|
void ntk_cut() {
|
||||||
|
/* for cost estimation we use reference counters initialized by the fanout
|
||||||
|
* size. */
|
||||||
|
initialize_refs(ntk);
|
||||||
|
|
||||||
|
/* enumerate cuts */
|
||||||
|
cut_enumeration_params ps;
|
||||||
|
ps.cut_size = 6;
|
||||||
|
ps.cut_limit = 8;
|
||||||
|
ps.minimize_truth_table = true;
|
||||||
|
/* true enables truth table computation */
|
||||||
|
auto cuts = cut_enumeration<Ntk, true>(ntk, ps);
|
||||||
|
|
||||||
|
/* iterate over all original nodes in the network */
|
||||||
|
const auto size = ntk.size();
|
||||||
|
ntk.foreach_node([&](auto n, auto index) {
|
||||||
|
/* stop once all original nodes were visited */
|
||||||
|
if (index >= size) return false;
|
||||||
|
|
||||||
|
/* do not iterate over constants or PIs */
|
||||||
|
if (ntk.is_constant(n) || ntk.is_pi(n)) return true;
|
||||||
|
|
||||||
|
/* skip cuts with small MFFC */
|
||||||
|
if (mffc_size(ntk, n) == 1) return true;
|
||||||
|
|
||||||
|
/* foreach cut */
|
||||||
|
for (auto& cut : cuts.cuts(ntk.node_to_index(n))) {
|
||||||
|
/* skip trivial cuts */
|
||||||
|
if (cut->size() < 2) continue;
|
||||||
|
|
||||||
|
std::vector<node_t> leaves;
|
||||||
|
for (auto leaf_index : *cut) {
|
||||||
|
leaves.push_back(ntk.index_to_node(leaf_index));
|
||||||
|
}
|
||||||
|
cut_view<Ntk> dcut(ntk, leaves, ntk.make_signal(n));
|
||||||
|
|
||||||
|
if (dcut.num_gates() > 14) continue;
|
||||||
|
|
||||||
|
/* skip cuts with small MFFC */
|
||||||
|
int mffc_num_nodes = mffc_size(dcut, n);
|
||||||
|
if (mffc_num_nodes == 1) continue;
|
||||||
|
|
||||||
|
string tt = to_binary(cuts.truth_table(*cut));
|
||||||
|
string str = "1";
|
||||||
|
|
||||||
|
int index1 = tt.find(str);
|
||||||
|
if (index1 >= tt.length()) continue;
|
||||||
|
|
||||||
|
int len = tt.length();
|
||||||
|
/* Stores the number of input variables. */
|
||||||
|
int variate_num = log(len) / log(2);
|
||||||
|
|
||||||
|
/* List all possible variable values/List truth table. */
|
||||||
|
vector<string> binary = list_truth_table(variate_num);
|
||||||
|
|
||||||
|
/* Stores the output of the truth table. */
|
||||||
|
vector<char> c_out;
|
||||||
|
for (int i = len - 1; i >= 0; i--) {
|
||||||
|
c_out.push_back(tt[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<char> c_out1;
|
||||||
|
/* Minimum item for storing binary. */
|
||||||
|
vector<string> minterm;
|
||||||
|
for (int i = 0; i < binary.size(); i++) {
|
||||||
|
if (c_out[i] != '0') {
|
||||||
|
minterm.push_back(binary[i]);
|
||||||
|
c_out1.push_back(c_out[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store all polarities. */
|
||||||
|
vector<string> polarity = list_all_polarities(variate_num);
|
||||||
|
|
||||||
|
/* Count the initial cost. */
|
||||||
|
/* Storage optimal polarity. */
|
||||||
|
string optimal_polarity = polarity[0];
|
||||||
|
/* Mixed polarity conversion algorithm based on list technique. */
|
||||||
|
vector<string> RM_product =
|
||||||
|
polarity_conversion(variate_num, minterm, optimal_polarity);
|
||||||
|
|
||||||
|
/* Search for the optimal polarity and the corresponding product term.
|
||||||
|
*/
|
||||||
|
search_for_optimal_polarity(minterm, polarity, variate_num, RM_product,
|
||||||
|
optimal_polarity);
|
||||||
|
|
||||||
|
/* Count the number of nodes in the new network. */
|
||||||
|
int node_num_new = count_the_number_of_nodes(variate_num, RM_product,
|
||||||
|
optimal_polarity);
|
||||||
|
|
||||||
|
if (ps_ntk.multiplicative_complexity == true) {
|
||||||
|
int optimization_nodes = dcut.num_gates() - node_num_new -
|
||||||
|
(dcut.num_gates() - mffc_num_nodes);
|
||||||
|
if (optimization_nodes > 0) {
|
||||||
|
std::vector<signal_t> pis;
|
||||||
|
pis.clear();
|
||||||
|
for (const auto& l : leaves) {
|
||||||
|
pis.push_back(ntk.make_signal(l));
|
||||||
|
}
|
||||||
|
|
||||||
|
int and_num = 0;
|
||||||
|
/* Count the number of and nodes in the new network. */
|
||||||
|
int and_num_new =
|
||||||
|
count_node_num(RM_product, variate_num, optimal_polarity);
|
||||||
|
|
||||||
|
dcut.foreach_gate([&](auto const& n1) {
|
||||||
|
if (ntk.is_and(n1)) and_num++;
|
||||||
|
});
|
||||||
|
|
||||||
|
int optimization_and_nodes = and_num - and_num_new;
|
||||||
|
|
||||||
|
/* Hierarchical ergodic statistics AND gates node cost function. */
|
||||||
|
LevelOrder(n, pis, optimization_and_nodes);
|
||||||
|
|
||||||
|
if (optimization_and_nodes >= 0) {
|
||||||
|
/* Create expression. */
|
||||||
|
string expression = create_expression(RM_product, variate_num,
|
||||||
|
optimal_polarity, binary);
|
||||||
|
|
||||||
|
/* Replace network. */
|
||||||
|
substitute_network_cut(expression, leaves, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int optimization_nodes = dcut.num_gates() - node_num_new -
|
||||||
|
(dcut.num_gates() - mffc_num_nodes);
|
||||||
|
|
||||||
|
if (optimization_nodes > 0) {
|
||||||
|
/* Create expression. */
|
||||||
|
string expression = create_expression(RM_product, variate_num,
|
||||||
|
optimal_polarity, binary);
|
||||||
|
|
||||||
|
/* Replace network. */
|
||||||
|
substitute_network_cut(expression, leaves, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/* mffc is used to divide the network. */
|
||||||
|
void ntk_mffc() {
|
||||||
|
/* for cost estimation we use reference counters initialized by the fanout
|
||||||
|
* size. */
|
||||||
|
ntk.clear_visited();
|
||||||
|
ntk.clear_values();
|
||||||
|
ntk.foreach_node(
|
||||||
|
[&](auto const& n) { ntk.set_value(n, ntk.fanout_size(n)); });
|
||||||
|
|
||||||
|
/* iterate over all original nodes in the network */
|
||||||
|
const auto size = ntk.size();
|
||||||
|
ntk.foreach_node([&](auto n, auto index) {
|
||||||
|
/* stop once all original nodes were visited */
|
||||||
|
if (index >= size) return false;
|
||||||
|
|
||||||
|
if (ntk.fanout_size(n) == 0u) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* do not iterate over constants or PIs */
|
||||||
|
if (ntk.is_constant(n) || ntk.is_pi(n)) return true;
|
||||||
|
|
||||||
|
/* skip cuts with small MFFC */
|
||||||
|
if (mffc_size(ntk, n) == 1) return true;
|
||||||
|
|
||||||
|
mffc_view mffc{ntk, n};
|
||||||
|
if (mffc.num_pos() == 0 || mffc.num_pis() > 6) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<node_t> leaves(mffc.num_pis());
|
||||||
|
mffc.foreach_pi([&](auto const& m, auto j) { leaves[j] = m; });
|
||||||
|
|
||||||
|
default_simulator<kitty::dynamic_truth_table> sim(mffc.num_pis());
|
||||||
|
string tt = to_binary(simulate<kitty::dynamic_truth_table>(mffc, sim)[0]);
|
||||||
|
string str = "1";
|
||||||
|
|
||||||
|
int index1 = tt.find(str);
|
||||||
|
if (index1 >= tt.length()) return true;
|
||||||
|
|
||||||
|
int len = tt.length();
|
||||||
|
/* Stores the number of input variables. */
|
||||||
|
int variate_num = log(len) / log(2);
|
||||||
|
|
||||||
|
/* List all possible variable values/List truth table. */
|
||||||
|
vector<string> binary = list_truth_table(variate_num);
|
||||||
|
|
||||||
|
/* Stores the output of the truth table. */
|
||||||
|
vector<char> c_out;
|
||||||
|
for (int i = len - 1; i >= 0; i--) {
|
||||||
|
c_out.push_back(tt[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<char> c_out1;
|
||||||
|
/* Minimum item for storing binary. */
|
||||||
|
vector<string> minterm;
|
||||||
|
for (int i = 0; i < binary.size(); i++) {
|
||||||
|
if (c_out[i] != '0') {
|
||||||
|
minterm.push_back(binary[i]);
|
||||||
|
c_out1.push_back(c_out[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store all polarities. */
|
||||||
|
vector<string> polarity = list_all_polarities(variate_num);
|
||||||
|
|
||||||
|
/* Count the initial cost. */
|
||||||
|
/* Storage optimal polarity. */
|
||||||
|
string optimal_polarity = polarity[0];
|
||||||
|
/* Mixed polarity conversion algorithm based on list technique. */
|
||||||
|
vector<string> RM_product =
|
||||||
|
polarity_conversion(variate_num, minterm, optimal_polarity);
|
||||||
|
|
||||||
|
/* Search for the optimal polarity and the corresponding product term. */
|
||||||
|
search_for_optimal_polarity(minterm, polarity, variate_num, RM_product,
|
||||||
|
optimal_polarity);
|
||||||
|
|
||||||
|
/* Count the number of nodes in the new network. */
|
||||||
|
int node_num_new =
|
||||||
|
count_the_number_of_nodes(variate_num, RM_product, optimal_polarity);
|
||||||
|
|
||||||
|
if (ps_ntk.multiplicative_complexity == true) {
|
||||||
|
/* Count the number of and nodes in the new network. */
|
||||||
|
int and_num_new =
|
||||||
|
count_node_num(RM_product, variate_num, optimal_polarity);
|
||||||
|
int and_num = 0;
|
||||||
|
mffc.foreach_gate([&](auto const& n1, auto i) {
|
||||||
|
if (ntk.is_and(n1)) and_num++;
|
||||||
|
});
|
||||||
|
|
||||||
|
int optimization_nodes = mffc.num_gates() - node_num_new;
|
||||||
|
int optimization_and_nodes = and_num - and_num_new;
|
||||||
|
|
||||||
|
if (optimization_nodes > 0 && optimization_and_nodes >= 0) {
|
||||||
|
/* Create expression. */
|
||||||
|
string expression = create_expression(RM_product, variate_num,
|
||||||
|
optimal_polarity, binary);
|
||||||
|
|
||||||
|
/* Replace network. */
|
||||||
|
substitute_network_mffc(expression, leaves, n);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int optimization_nodes = mffc.num_gates() - node_num_new;
|
||||||
|
if (optimization_nodes > 0) {
|
||||||
|
/* Create expression. */
|
||||||
|
string expression = create_expression(RM_product, variate_num,
|
||||||
|
optimal_polarity, binary);
|
||||||
|
|
||||||
|
/* Replace network. */
|
||||||
|
substitute_network_mffc(expression, leaves, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
private:
|
||||||
|
Ntk& ntk;
|
||||||
|
rm_rewriting_params const& ps_ntk;
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
/*! \brief RM logic optimization.
|
||||||
|
*
|
||||||
|
* This algorithm divides the network and then attempts to rewrite the
|
||||||
|
subnetwork by RM logic
|
||||||
|
* in terms of gates of the same network. The rewritten structures are added
|
||||||
|
* to the network, and if they lead to area improvement, will be used as new
|
||||||
|
* parts of the logic.
|
||||||
|
*
|
||||||
|
* **Required network functions:**
|
||||||
|
* - `get_node`
|
||||||
|
* - `level`
|
||||||
|
* - `update_levels`
|
||||||
|
* - `create_and`
|
||||||
|
* - `create_not`
|
||||||
|
* - `create_xor`
|
||||||
|
* - `substitute_node`
|
||||||
|
* - `foreach_node`
|
||||||
|
* - `foreach_po`
|
||||||
|
* - `foreach_fanin`
|
||||||
|
* - `is_and`
|
||||||
|
* - `clear_values`
|
||||||
|
* - `set_value`
|
||||||
|
* - `value`
|
||||||
|
* - `fanout_size`
|
||||||
|
*
|
||||||
|
\verbatim embed:rst
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
\endverbatim
|
||||||
|
*/
|
||||||
|
template <class Ntk>
|
||||||
|
void rm_mixed_polarity(Ntk& ntk, rm_rewriting_params const& ps_ntk = {}) {
|
||||||
|
static_assert(is_network_type_v<Ntk>, "Ntk is not a network type");
|
||||||
|
static_assert(has_get_node_v<Ntk>,
|
||||||
|
"Ntk does not implement the get_node method");
|
||||||
|
static_assert(has_level_v<Ntk>, "Ntk does not implement the level method");
|
||||||
|
static_assert(has_create_maj_v<Ntk>,
|
||||||
|
"Ntk does not implement the create_maj method");
|
||||||
|
static_assert(has_create_xor_v<Ntk>,
|
||||||
|
"Ntk does not implement the create_maj method");
|
||||||
|
static_assert(has_substitute_node_v<Ntk>,
|
||||||
|
"Ntk does not implement the substitute_node method");
|
||||||
|
static_assert(has_update_levels_v<Ntk>,
|
||||||
|
"Ntk does not implement the update_levels method");
|
||||||
|
static_assert(has_foreach_node_v<Ntk>,
|
||||||
|
"Ntk does not implement the foreach_node method");
|
||||||
|
static_assert(has_foreach_po_v<Ntk>,
|
||||||
|
"Ntk does not implement the foreach_po method");
|
||||||
|
static_assert(has_foreach_fanin_v<Ntk>,
|
||||||
|
"Ntk does not implement the foreach_fanin method");
|
||||||
|
static_assert(has_is_and_v<Ntk>, "Ntk does not implement the is_and method");
|
||||||
|
static_assert(has_is_xor_v<Ntk>, "Ntk does not implement the is_xor method");
|
||||||
|
static_assert(has_clear_values_v<Ntk>,
|
||||||
|
"Ntk does not implement the clear_values method");
|
||||||
|
static_assert(has_set_value_v<Ntk>,
|
||||||
|
"Ntk does not implement the set_value method");
|
||||||
|
static_assert(has_value_v<Ntk>, "Ntk does not implement the value method");
|
||||||
|
static_assert(has_fanout_size_v<Ntk>,
|
||||||
|
"Ntk does not implement the fanout_size method");
|
||||||
|
|
||||||
|
detail::rm_mixed_polarity_impl p(ntk, ps_ntk);
|
||||||
|
p.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace mockturtle */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,678 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#include <mockturtle/mockturtle.hpp>
|
||||||
|
|
||||||
|
namespace mockturtle
|
||||||
|
{
|
||||||
|
|
||||||
|
/*! \brief Parameters for xag_depth_rewriting.
|
||||||
|
*
|
||||||
|
* The data structure `xag_depth_rewriting_params` holds configurable
|
||||||
|
* parameters with default arguments for `xag_depth_rewriting`.
|
||||||
|
*/
|
||||||
|
struct xag_depth_rewriting_params
|
||||||
|
{
|
||||||
|
/*! \brief Rewriting strategy. */
|
||||||
|
enum strategy_t
|
||||||
|
{
|
||||||
|
/*! \brief DFS rewriting strategy.
|
||||||
|
*
|
||||||
|
* Applies depth rewriting once to all output cones whose drivers have
|
||||||
|
* maximum levels
|
||||||
|
*/
|
||||||
|
dfs,
|
||||||
|
/*! \brief Aggressive rewriting strategy.
|
||||||
|
*
|
||||||
|
* Applies depth reduction multiple times until the number of nodes, which
|
||||||
|
* cannot be rewritten, matches the number of nodes, in the current
|
||||||
|
* network; or the new network size is larger than the initial size w.r.t.
|
||||||
|
* to an `overhead`.
|
||||||
|
*/
|
||||||
|
aggressive,
|
||||||
|
/*! \brief Selective rewriting strategy.
|
||||||
|
*
|
||||||
|
* Like `aggressive`, but only applies rewriting to nodes on critical paths
|
||||||
|
* and without `overhead`.
|
||||||
|
*/
|
||||||
|
selective,
|
||||||
|
} strategy = dfs;
|
||||||
|
|
||||||
|
/*! \brief Overhead factor in aggressive rewriting strategy.
|
||||||
|
*
|
||||||
|
* When comparing to the initial size in aggressive depth rewriting, phyLS the
|
||||||
|
* number of dangling nodes are taken into account.
|
||||||
|
*/
|
||||||
|
float overhead{2.0f};
|
||||||
|
|
||||||
|
bool verbose{false};
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template<class Ntk>
|
||||||
|
class xag_depth_rewriting_impl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
xag_depth_rewriting_impl( Ntk& ntk, xag_depth_rewriting_params const& ps )
|
||||||
|
: ntk( ntk ), ps( ps )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void run()
|
||||||
|
{
|
||||||
|
switch ( ps.strategy )
|
||||||
|
{
|
||||||
|
case xag_depth_rewriting_params::dfs:
|
||||||
|
run_dfs();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case xag_depth_rewriting_params::selective:
|
||||||
|
run_selective();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case xag_depth_rewriting_params::aggressive:
|
||||||
|
run_aggressive();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*****************************************Optimization strategies Begin********************************************************************/
|
||||||
|
private:
|
||||||
|
void run_dfs()
|
||||||
|
{
|
||||||
|
ntk.foreach_po( [this]( auto po ) {
|
||||||
|
const auto driver = ntk.get_node( po );
|
||||||
|
if ( ntk.level( driver ) < ntk.depth() )
|
||||||
|
return;
|
||||||
|
topo_view topo{ntk, po};
|
||||||
|
topo.foreach_node( [this]( auto n ) {
|
||||||
|
reduce_depth_ultimate( n );
|
||||||
|
return true;
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
void run_selective()
|
||||||
|
{
|
||||||
|
uint32_t counter{0};
|
||||||
|
while ( true )
|
||||||
|
{
|
||||||
|
mark_critical_paths();
|
||||||
|
|
||||||
|
topo_view topo{ntk};
|
||||||
|
topo.foreach_node( [this, &counter]( auto n ) {
|
||||||
|
if ( ntk.fanout_size( n ) == 0 || ntk.value( n ) == 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( reduce_depth_ultimate( n ) )
|
||||||
|
{
|
||||||
|
mark_critical_paths();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++counter;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
if ( counter > ntk.size() )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
void run_aggressive()
|
||||||
|
{
|
||||||
|
uint32_t counter{0}, init_size{ntk.size()};
|
||||||
|
while ( true )
|
||||||
|
{
|
||||||
|
topo_view topo{ntk};
|
||||||
|
topo.foreach_node( [this, &counter]( auto n ) {
|
||||||
|
if ( ntk.fanout_size( n ) == 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( !reduce_depth_ultimate( n ) )
|
||||||
|
{
|
||||||
|
++counter;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
if ( ntk.size() > ps.overhead * init_size )
|
||||||
|
break;
|
||||||
|
if ( counter > ntk.size() )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************Optimization strategies End**********************************************************************/
|
||||||
|
|
||||||
|
/*****************************************Optimization Functions Begin*********************************************************************/
|
||||||
|
private:
|
||||||
|
bool reduce_depth_ultimate( node<Ntk> const& n )
|
||||||
|
{
|
||||||
|
auto b_1 = xor_inv_transfer( n );
|
||||||
|
auto b2 = xor_inv_remove( n );
|
||||||
|
auto b3 = xor_and_transfer( n );
|
||||||
|
auto b4 = reduce_depth_and_common_fanin( n );
|
||||||
|
auto b5 = reduce_depth_use_constant_fanin( n );
|
||||||
|
auto b6 = reduce_depth_use_xor_or_convert( n );
|
||||||
|
auto b7 = reduce_depth_use_xor_and_convert( n );
|
||||||
|
// auto b8 = reduce_depth_use_xor_or_convert2( n );
|
||||||
|
|
||||||
|
if(!( b_1 | b2 | b3 | b4 | b5 | b6 | b7 )){ return false; }
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/* [!a!b]=[ab], ![!a!b] = ![ab] */
|
||||||
|
/* Remove the INV of the two children of an node, thie node's type must be XOR. */
|
||||||
|
bool xor_inv_remove( node<Ntk> const& n )
|
||||||
|
{
|
||||||
|
if ( !ntk.is_xor( n ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( ntk.level( n ) == 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* get children of top node, ordered by node level (ascending) */
|
||||||
|
auto ocs = ordered_children( n );
|
||||||
|
|
||||||
|
/* The two children must both have INV. */
|
||||||
|
if ( ntk.is_complemented(ocs[0]) && ntk.is_complemented(ocs[1]) )
|
||||||
|
{
|
||||||
|
ocs[0] = !ocs[0];
|
||||||
|
ocs[1] = !ocs[1];
|
||||||
|
|
||||||
|
auto opt = ntk.create_xor( ocs[0], ocs[1] );
|
||||||
|
ntk.substitute_node( n, opt );
|
||||||
|
ntk.update_levels();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/* ![!ab] = ![a!b] = [ab], [!ab] = [a!b] = ![ab] */
|
||||||
|
/* Transfer the INV of the input to the fanout. */
|
||||||
|
/* can be used for subsquent optimization such as (a[!ab]) = (a![ab]) = (ab) */
|
||||||
|
bool xor_inv_transfer( node<Ntk> const& n )
|
||||||
|
{
|
||||||
|
if ( !ntk.is_xor( n ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( ntk.level( n ) == 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* get children of top node, ordered by node level (ascending). */
|
||||||
|
auto ocs = ordered_children( n );
|
||||||
|
|
||||||
|
if(!ntk.is_complemented(ocs[0]) && !ntk.is_complemented(ocs[1]))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( ( ntk.is_complemented(ocs[0]) ^ ntk.is_complemented(ocs[1] ) ) == 1)
|
||||||
|
{
|
||||||
|
if(ntk.is_complemented(ocs[0]))
|
||||||
|
{
|
||||||
|
ocs[0] = !ocs[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ocs[1] = !ocs[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto opt = ntk.create_xor(ocs[0], ocs[1]) ^ true;
|
||||||
|
ntk.substitute_node( n, opt );
|
||||||
|
ntk.update_levels();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
bool reduce_depth_use_constant_fanin( node<Ntk> const& n )
|
||||||
|
{
|
||||||
|
if ( ntk.level( n ) == 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* get children of top node, ordered by node level (ascending). */
|
||||||
|
auto ocs = ordered_children( n );
|
||||||
|
|
||||||
|
if(ntk.fanout_size(ntk.get_node(ocs[0])) ==1 && ntk.fanout_size(ntk.get_node(ocs[1])) == 1)
|
||||||
|
{
|
||||||
|
if(ntk.is_xor(n))
|
||||||
|
{
|
||||||
|
if(ocs[0].index == 0 || ocs[1].index == 0)
|
||||||
|
{
|
||||||
|
if(ocs[0].index == 0 )
|
||||||
|
{
|
||||||
|
auto opt = ntk.is_complemented(ocs[0])? !ocs[1] : ocs[1];
|
||||||
|
ntk.substitute_node(n,opt);
|
||||||
|
ntk.update_levels();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ocs[1].index == 0 )
|
||||||
|
{
|
||||||
|
auto opt = ntk.is_complemented(ocs[1])? !ocs[0] : ocs[0];
|
||||||
|
ntk.substitute_node(n,opt);
|
||||||
|
ntk.update_levels();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ocs[0].index == 1 || ocs[1].index == 1 )
|
||||||
|
{
|
||||||
|
if(ocs[0].index == 1 )
|
||||||
|
{
|
||||||
|
auto opt = ntk.is_complemented(ocs[0])? ocs[1] : !ocs[1];
|
||||||
|
ntk.substitute_node(n, opt);
|
||||||
|
ntk.update_levels();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ocs[1].index == 1 )
|
||||||
|
{
|
||||||
|
auto opt = ntk.is_complemented(ocs[1])? ocs[0] : !ocs[0];
|
||||||
|
ntk.substitute_node(n, opt);
|
||||||
|
ntk.update_levels();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ntk.is_and(n))
|
||||||
|
{
|
||||||
|
if(ocs[0].index == 1 || ocs[1].index == 1)
|
||||||
|
{
|
||||||
|
if(ocs[0].index == 1 && !ntk.is_complemented(ocs[0]) )
|
||||||
|
{
|
||||||
|
auto opt = ocs[1];
|
||||||
|
ntk.substitute_node(n,opt);
|
||||||
|
ntk.update_levels();
|
||||||
|
}
|
||||||
|
else if(ocs[1].index == 1 && ntk.is_complemented(ocs[1]))
|
||||||
|
{
|
||||||
|
auto opt = ocs[0];
|
||||||
|
ntk.substitute_node(n,opt);
|
||||||
|
ntk.update_levels();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* XOR: [a0] = a, [a1] = !a.*/
|
||||||
|
/* AND: (a1) = a, (a0) = 0. */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/* Use the Boolean configuration between AND and XOR.
|
||||||
|
* There are main two expression for reference.
|
||||||
|
* (a[!ab]) = (ab), (!a[ab]) = (!ab). */
|
||||||
|
bool reduce_depth_use_xor_and_convert( node<Ntk> const& n )
|
||||||
|
{
|
||||||
|
if ( !ntk.is_and( n ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( ntk.level( n ) == 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* get children of top node, ordered by node level (ascending). */
|
||||||
|
const auto ocs = ordered_children( n );
|
||||||
|
|
||||||
|
/* depth of last child must be (significantly) higher than depth of second child */
|
||||||
|
if ( ntk.level( ntk.get_node( ocs[1] ) ) <= ntk.level( ntk.get_node( ocs[0] ) ) + 1 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( !ntk.is_xor( ntk.get_node( ocs[1] ) ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto ocs2 = ordered_children( ntk.get_node( ocs[1] ) );
|
||||||
|
/* Judgement */
|
||||||
|
if( ocs[0].index == ocs2[0].index && (ocs[0].complement ^ ocs2[0].complement) == 1)
|
||||||
|
{
|
||||||
|
if(ntk.fanout_size(ntk.get_node(ocs[1])) == 1)
|
||||||
|
{
|
||||||
|
auto opt = ntk.create_and( ocs[0], ocs2[1] );
|
||||||
|
ntk.substitute_node( n, opt );
|
||||||
|
ntk.update_levels();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/* Refer to follow two expressions:
|
||||||
|
* (a(ab)) = (ab), (!a(!a!b)) = (!a!b).
|
||||||
|
*/
|
||||||
|
bool reduce_depth_and_common_fanin( node<Ntk> const& n )
|
||||||
|
{
|
||||||
|
if ( !ntk.is_and( n ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( ntk.level( n ) == 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* get children of top node, ordered by node level (ascending). */
|
||||||
|
const auto ocs = ordered_children( n );
|
||||||
|
|
||||||
|
/* depth of last child must be (significantly) higher than depth of second child */
|
||||||
|
if ( ntk.level( ntk.get_node( ocs[1] ) ) <= ntk.level( ntk.get_node( ocs[0] ) ) + 1 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( !ntk.is_and( ntk.get_node( ocs[1] ) ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto ocs2 = ordered_children( ntk.get_node( ocs[1] ) );
|
||||||
|
|
||||||
|
if(ocs[0] == ocs2[0] && ntk.fanout_size(ntk.get_node(ocs[1])) == 1 && ntk.fanout_size(ntk.get_node(ocs[1])) == 1)
|
||||||
|
{
|
||||||
|
auto opt = ocs[1];
|
||||||
|
ntk.substitute_node(n,opt);
|
||||||
|
ntk.update_levels();
|
||||||
|
}
|
||||||
|
/*if( auto cand = find_common_grand_child_two( ocs, ocs2 ); cand)
|
||||||
|
{
|
||||||
|
auto r = *cand;
|
||||||
|
|
||||||
|
auto opt = ntk.create_and( r.y, r.a );
|
||||||
|
ntk.substitute_node( n, opt );
|
||||||
|
ntk.update_levels();
|
||||||
|
return true;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/* (a[ab]) = [a(ab)] */
|
||||||
|
bool xor_and_transfer( node<Ntk> const& n )
|
||||||
|
{
|
||||||
|
if ( ntk.level( n ) == 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* get children of top node, ordered by node level (ascending). */
|
||||||
|
const auto ocs = ordered_children( n );
|
||||||
|
|
||||||
|
/* depth of last child must be (significantly) higher than depth of second child */
|
||||||
|
if ( ntk.level( ntk.get_node( ocs[1] ) ) <= ntk.level( ntk.get_node( ocs[0] ) ) + 1 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( !ntk.is_and( n ) && !ntk.is_xor( ntk.get_node( ocs[1] ) ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto ocs2 = ordered_children( ntk.get_node( ocs[1] ) );
|
||||||
|
|
||||||
|
/* refer to the expressions above. */
|
||||||
|
if ( !ntk.is_complemented(ocs[0]) && !ntk.is_complemented(ocs[1]) && !ntk.is_complemented(ocs2[0]) && !ntk.is_complemented(ocs2[1]) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(ntk.fanout_size(ntk.get_node(ocs[1])) == 1)
|
||||||
|
{
|
||||||
|
if(ocs[0] == ocs2[0])
|
||||||
|
{
|
||||||
|
auto opt = ntk.create_xor(ocs[0], ntk.create_and(ocs2[0], ocs2[1]));
|
||||||
|
ntk.substitute_node(n, opt);
|
||||||
|
ntk.update_levels();
|
||||||
|
}
|
||||||
|
/*if ( auto cand = find_common_grand_child_two( ocs, ocs2 ); cand )
|
||||||
|
{
|
||||||
|
auto r = *cand;
|
||||||
|
auto opt = ntk.create_xor( r.a, ntk.create_and( r.a, r.y ) );
|
||||||
|
ntk.substitute_node( n, opt );
|
||||||
|
ntk.update_levels();
|
||||||
|
return true;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/* [a!(!a!b)]= (!ab) [!a!(!a!b)]= !(!ab)*/
|
||||||
|
bool reduce_depth_use_xor_or_convert( node<Ntk> const& n )
|
||||||
|
{
|
||||||
|
if ( ntk.level( n ) == 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* get children of top node, ordered by node level (ascending). */
|
||||||
|
auto ocs = ordered_children( n );
|
||||||
|
|
||||||
|
/* depth of last child must be (significantly) higher than depth of second child */
|
||||||
|
if ( ntk.level( ntk.get_node( ocs[1] ) ) <= ntk.level( ntk.get_node( ocs[0] ) ) + 1 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( !ntk.is_xor( n ) && !ntk.is_and( ntk.get_node( ocs[1] ) ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto ocs2 = ordered_children(ntk.get_node(ocs[1]));
|
||||||
|
|
||||||
|
if (ocs[0].index == ocs2[0].index && ntk.is_complemented(ocs[1]) && ntk.is_complemented(ocs2[0]) && ntk.is_complemented(ocs2[1]) && ntk.fanout_size(ntk.get_node(ocs[1])) == 1 )
|
||||||
|
{
|
||||||
|
if(ntk.is_complemented(ocs[0]))
|
||||||
|
{
|
||||||
|
ocs2[1] = !ocs2[1];
|
||||||
|
auto opt = ntk.create_nand(ocs2[0], ocs2[1]);
|
||||||
|
ntk.substitute_node(n, opt);
|
||||||
|
ntk.update_levels();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ocs2[1] = !ocs2[1];
|
||||||
|
auto opt = ntk.create_and(ocs2[0], ocs2[1]);
|
||||||
|
ntk.substitute_node(n, opt);
|
||||||
|
ntk.update_levels();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/*{a!b} = {a[!ab]} = !(!a![!ab])); !{a!b} = (!ab)*/
|
||||||
|
bool reduce_depth_use_xor_or_convert2( node<Ntk> const& n )
|
||||||
|
{
|
||||||
|
if ( ntk.level( n ) == 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* get children of top node, ordered by node level (ascending). */
|
||||||
|
const auto ocs = ordered_children( n );
|
||||||
|
|
||||||
|
/* depth of last child must be (significantly) higher than depth of second child */
|
||||||
|
if ( ntk.level( ntk.get_node( ocs[1] ) ) <= ntk.level( ntk.get_node( ocs[0] ) ) + 1 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( !ntk.is_and( n ) && !ntk.is_xor( ntk.get_node( ocs[1] ) ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto ocs2 = ordered_children( ntk.get_node( ocs[1] ) );
|
||||||
|
|
||||||
|
if(ntk.is_complemented(ocs[0]) && ntk.is_complemented(ocs[1]) && ocs[0] == ocs2[0] )
|
||||||
|
{
|
||||||
|
if(ntk.fanout_size(ntk.get_node(ocs[1])) == 1 && !ntk.is_complemented(ocs2[1]))
|
||||||
|
{
|
||||||
|
auto opt = ntk.create_or(ocs2[0], ocs2[1]);
|
||||||
|
ntk.substitute_node(n, opt);
|
||||||
|
ntk.update_levels();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*****************************************Optimization Functions End***********************************************************************/
|
||||||
|
|
||||||
|
/*****************************************Other Necessary Parts Begin**********************************************************************/
|
||||||
|
|
||||||
|
bool is_signal_equal( const signal<Ntk>& a, const signal<Ntk>& b )
|
||||||
|
{
|
||||||
|
return ( a == b ? true : false );
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/* used for the subsquent judgement of the common child-node. */
|
||||||
|
using children_t = std::array< signal<Ntk>, 2 >;
|
||||||
|
std::bitset<4> get_pair_pattern( const children_t& c1, const children_t& c2 )
|
||||||
|
{
|
||||||
|
std::bitset<4> equals;
|
||||||
|
|
||||||
|
equals.set( 0u, is_signal_equal( c1[0], c2[0] ) );
|
||||||
|
equals.set( 1u, is_signal_equal( c1[0], c2[1] ) );
|
||||||
|
equals.set( 2u, is_signal_equal( c1[1], c2[0] ) );
|
||||||
|
equals.set( 3u, is_signal_equal( c1[1], c2[1] ) );
|
||||||
|
|
||||||
|
return equals;
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
/* used to judge which two nodes are common. */
|
||||||
|
std::vector<size_t> equal_idx( const std::bitset<4> pattern )
|
||||||
|
{
|
||||||
|
std::vector<size_t> r;
|
||||||
|
for( size_t idx = 0; idx < pattern.size(); idx++ )
|
||||||
|
{
|
||||||
|
if( pattern.test( idx ) )
|
||||||
|
{
|
||||||
|
r.push_back( idx );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
struct grand_children_pair_t
|
||||||
|
{
|
||||||
|
signal<Ntk> x;
|
||||||
|
signal<Ntk> y;
|
||||||
|
signal<Ntk> a; //common grand child a
|
||||||
|
};
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
std::optional<grand_children_pair_t> find_common_grand_child_two( const children_t& c1, const children_t& c2 )
|
||||||
|
{
|
||||||
|
grand_children_pair_t r;
|
||||||
|
auto p = get_pair_pattern( c1, c2 );
|
||||||
|
|
||||||
|
std::vector<signal<Ntk>> common;
|
||||||
|
|
||||||
|
for( size_t idx = 0; idx < p.size(); idx++ )
|
||||||
|
{
|
||||||
|
if( p.test(idx) )
|
||||||
|
{
|
||||||
|
assert( c1[idx / 2] == c2[ idx % 2 ] );
|
||||||
|
common.push_back( c1[ idx / 2] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for xor children, require at least one common children */
|
||||||
|
if( common.size() != 1u )
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
/* save the records */
|
||||||
|
r.a = common[0u];
|
||||||
|
|
||||||
|
for( auto i = 0u; i < 2u; i++ )
|
||||||
|
{
|
||||||
|
if( c1[i] != common[0u] && c1[i] != common[0u] )
|
||||||
|
{
|
||||||
|
r.x = c1[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if( c2[i] != common[0u] && c2[i] != common[0u] )
|
||||||
|
{
|
||||||
|
r.y = c2[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
|
||||||
|
std::array<signal<Ntk>, 2> ordered_children( node<Ntk> const& n ) const
|
||||||
|
{
|
||||||
|
std::array<signal<Ntk>, 2> children;
|
||||||
|
ntk.foreach_fanin( n, [&children]( auto const& f, auto i ) { children[i] = f; } );
|
||||||
|
std::sort( children.begin(), children.end(), [this]( auto const& c1, auto const& c2 ) {
|
||||||
|
if( ntk.level( ntk.get_node( c1 ) ) == ntk.level( ntk.get_node( c2 ) ) )
|
||||||
|
{
|
||||||
|
return c1.index < c2.index;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ntk.level( ntk.get_node( c1 ) ) < ntk.level( ntk.get_node( c2 ) );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
void mark_critical_path( node<Ntk> const& n )
|
||||||
|
{
|
||||||
|
if ( ntk.is_pi( n ) || ntk.is_constant( n ) || ntk.value( n ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto level = ntk.level( n );
|
||||||
|
ntk.set_value( n, 1 );
|
||||||
|
ntk.foreach_fanin( n, [this, level]( auto const& f ) {
|
||||||
|
if ( ntk.level( ntk.get_node( f ) ) == level - 1 )
|
||||||
|
{
|
||||||
|
mark_critical_path( ntk.get_node( f ) );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
/**************************************************************************************************************/
|
||||||
|
void mark_critical_paths()
|
||||||
|
{
|
||||||
|
ntk.clear_values();
|
||||||
|
ntk.foreach_po( [this]( auto const& f ) {
|
||||||
|
if ( ntk.level( ntk.get_node( f ) ) == ntk.depth() )
|
||||||
|
{
|
||||||
|
mark_critical_path( ntk.get_node( f ) );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
/*****************************************Other Necessary Parts End************************************************************************/
|
||||||
|
private:
|
||||||
|
Ntk& ntk;
|
||||||
|
xag_depth_rewriting_params const& ps;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
/*! \brief xag algebraic depth rewriting.
|
||||||
|
*
|
||||||
|
* This algorithm tries to rewrite a network with majority gates for depth
|
||||||
|
* optimization using the associativity and distributivity rule in
|
||||||
|
* majority-of-3 logic. It can be applied to networks other than xags, but
|
||||||
|
* only considers pairs of nodes which both implement the majority-of-3
|
||||||
|
* function and the XOR function.
|
||||||
|
*
|
||||||
|
* **Required network functions:**
|
||||||
|
* - `get_node`
|
||||||
|
* - `level`
|
||||||
|
* - `update_levels`
|
||||||
|
* - `create_maj`
|
||||||
|
* - `substitute_node`
|
||||||
|
* - `foreach_node`
|
||||||
|
* - `foreach_po`
|
||||||
|
* - `foreach_fanin`
|
||||||
|
* - `is_maj`
|
||||||
|
* - `clear_values`
|
||||||
|
* - `set_value`
|
||||||
|
* - `value`
|
||||||
|
* - `fanout_size`
|
||||||
|
*
|
||||||
|
\verbatim embed:rst
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
\endverbatim
|
||||||
|
*/
|
||||||
|
template<class Ntk>
|
||||||
|
void xag_depth_rewriting( Ntk& ntk, xag_depth_rewriting_params const& ps = {} )
|
||||||
|
{
|
||||||
|
static_assert( is_network_type_v<Ntk>, "Ntk is not a network type" );
|
||||||
|
static_assert( has_get_node_v<Ntk>, "Ntk does not implement the get_node method" );
|
||||||
|
static_assert( has_level_v<Ntk>, "Ntk does not implement the level method" );
|
||||||
|
static_assert( has_create_maj_v<Ntk>, "Ntk does not implement the create_maj method" );
|
||||||
|
static_assert( has_create_xor_v<Ntk>, "Ntk does not implement the create_maj method" );
|
||||||
|
static_assert( has_substitute_node_v<Ntk>, "Ntk does not implement the substitute_node method" );
|
||||||
|
static_assert( has_update_levels_v<Ntk>, "Ntk does not implement the update_levels method" );
|
||||||
|
static_assert( has_foreach_node_v<Ntk>, "Ntk does not implement the foreach_node method" );
|
||||||
|
static_assert( has_foreach_po_v<Ntk>, "Ntk does not implement the foreach_po method" );
|
||||||
|
static_assert( has_foreach_fanin_v<Ntk>, "Ntk does not implement the foreach_fanin method" );
|
||||||
|
static_assert( has_is_and_v<Ntk>, "Ntk does not implement the is_and method" );
|
||||||
|
static_assert( has_is_xor_v<Ntk>, "Ntk does not implement the is_xor method" );
|
||||||
|
static_assert( has_clear_values_v<Ntk>, "Ntk does not implement the clear_values method" );
|
||||||
|
static_assert( has_set_value_v<Ntk>, "Ntk does not implement the set_value method" );
|
||||||
|
static_assert( has_value_v<Ntk>, "Ntk does not implement the value method" );
|
||||||
|
static_assert( has_fanout_size_v<Ntk>, "Ntk does not implement the fanout_size method" );
|
||||||
|
|
||||||
|
detail::xag_depth_rewriting_impl<Ntk> p( ntk, ps );
|
||||||
|
p.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace mockturtle */
|
|
@ -0,0 +1,170 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#include <mockturtle/mockturtle.hpp>
|
||||||
|
|
||||||
|
namespace mockturtle
|
||||||
|
{
|
||||||
|
struct xmg_expand_rewriting_params
|
||||||
|
{
|
||||||
|
enum strategy_t
|
||||||
|
{
|
||||||
|
expand,
|
||||||
|
constants
|
||||||
|
} strategy = expand;
|
||||||
|
|
||||||
|
std::vector<unsigned> xor_index;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
template<class Ntk>
|
||||||
|
class xmg_expand_rewriting_impl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
xmg_expand_rewriting_impl( Ntk& ntk, xmg_expand_rewriting_params const& ps )
|
||||||
|
: ntk( ntk ), ps( ps )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void run()
|
||||||
|
{
|
||||||
|
switch( ps.strategy )
|
||||||
|
{
|
||||||
|
case xmg_expand_rewriting_params::expand:
|
||||||
|
run_xor_maj_expand();
|
||||||
|
break;
|
||||||
|
case xmg_expand_rewriting_params::constants:
|
||||||
|
run_xor_constants();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void run_xor_maj_expand()
|
||||||
|
{
|
||||||
|
ntk.foreach_po( [this]( auto po ) {
|
||||||
|
topo_view topo{ntk, po};
|
||||||
|
topo.foreach_node( [this]( auto n ) {
|
||||||
|
xor_maj_expand( n );
|
||||||
|
return true;
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_xor_constants()
|
||||||
|
{
|
||||||
|
ntk.foreach_po( [this]( auto po ) {
|
||||||
|
topo_view topo{ntk, po};
|
||||||
|
topo.foreach_node( [this]( auto n ) {
|
||||||
|
xor_constants( n, ps.xor_index );
|
||||||
|
return true;
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void print_children( std::array<signal<Ntk>, 3u> const& children )
|
||||||
|
{
|
||||||
|
std::cout << "children 0 : " << ntk.get_node( children[0] ) << std::endl;
|
||||||
|
std::cout << "children 1 : " << ntk.get_node( children[1] ) << std::endl;
|
||||||
|
std::cout << "children 2 : " << ntk.get_node( children[2] ) << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool xor_constants( node<Ntk> const& n, std::vector<unsigned> const& xors )
|
||||||
|
{
|
||||||
|
if ( !ntk.is_xor3( n ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto copy_node_2n = n * 2;
|
||||||
|
auto copy_node_2n_plus_1 = n * 2 + 1;
|
||||||
|
|
||||||
|
if( std::find( xors.begin(), xors.end(), copy_node_2n ) != xors.end() )
|
||||||
|
{
|
||||||
|
//std::cout << "Please assign constants to node " << n << std::endl;
|
||||||
|
auto opt = ntk.get_constant( false );
|
||||||
|
ntk.substitute_node( n, opt );
|
||||||
|
ntk.update_levels();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if( std::find( xors.begin(), xors.end(), copy_node_2n_plus_1 ) != xors.end() )
|
||||||
|
{
|
||||||
|
//std::cout << "Please assign constants to node " << n << std::endl;
|
||||||
|
auto opt = ntk.get_constant( true );
|
||||||
|
ntk.substitute_node( n, opt );
|
||||||
|
ntk.update_levels();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool xor_maj_expand( node<Ntk> const& n )
|
||||||
|
{
|
||||||
|
if ( !ntk.is_xor3( n ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( ntk.level( n ) <= 1 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* get children of top node, ordered by node level (ascending) */
|
||||||
|
const auto ocs = ordered_children( n );
|
||||||
|
|
||||||
|
/* if the first child is not constant, return */
|
||||||
|
if( ocs[0].index != 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( !ntk.is_maj( ntk.get_node( ocs[1] ) ) || !ntk.is_maj( ntk.get_node( ocs[2] ) ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto ogcs = ordered_children( ntk.get_node( ocs[1] ) );
|
||||||
|
|
||||||
|
auto n1 = ntk.create_xor( ogcs[0], ocs[2] );
|
||||||
|
auto n2 = ntk.create_xor( ogcs[1], ocs[2] );
|
||||||
|
auto n3 = ntk.create_xor( ogcs[2], ocs[2] );
|
||||||
|
|
||||||
|
auto opt = ntk.create_maj( n1, n2, n3 );
|
||||||
|
ntk.substitute_node( n, opt );
|
||||||
|
ntk.update_levels();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<signal<Ntk>, 3> ordered_children( node<Ntk> const& n ) const
|
||||||
|
{
|
||||||
|
std::array<signal<Ntk>, 3> children;
|
||||||
|
ntk.foreach_fanin( n, [&children]( auto const& f, auto i ) { children[i] = f; } );
|
||||||
|
std::sort( children.begin(), children.end(), [this]( auto const& c1, auto const& c2 ) {
|
||||||
|
if( ntk.level( ntk.get_node( c1 ) ) == ntk.level( ntk.get_node( c2 ) ) )
|
||||||
|
{
|
||||||
|
return c1.index < c2.index;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ntk.level( ntk.get_node( c1 ) ) < ntk.level( ntk.get_node( c2 ) );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ntk& ntk;
|
||||||
|
xmg_expand_rewriting_params const& ps;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template<class Ntk>
|
||||||
|
void xmg_expand_rewriting( Ntk& ntk, xmg_expand_rewriting_params const& ps )
|
||||||
|
{
|
||||||
|
detail::xmg_expand_rewriting_impl<Ntk> p( ntk, ps );
|
||||||
|
p.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace mockturtle */
|
|
@ -0,0 +1,66 @@
|
||||||
|
#ifndef XMG_EXTRACT_HPP
|
||||||
|
#define XMG_EXTRACT_HPP
|
||||||
|
|
||||||
|
#include <mockturtle/algorithms/circuit_validator.hpp>
|
||||||
|
#include <mockturtle/views/topo_view.hpp>
|
||||||
|
|
||||||
|
#include "utils.hpp"
|
||||||
|
|
||||||
|
using namespace mockturtle;
|
||||||
|
|
||||||
|
namespace phyLS
|
||||||
|
{
|
||||||
|
|
||||||
|
std::vector<unsigned> xmg_extract( xmg_network const& xmg )
|
||||||
|
{
|
||||||
|
std::vector<unsigned> xors;
|
||||||
|
topo_view topo{ xmg };
|
||||||
|
circuit_validator v( xmg );
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
topo.foreach_node( [&]( auto n ) {
|
||||||
|
if( xmg.is_xor3( n ) )
|
||||||
|
{
|
||||||
|
auto children = get_children( xmg, n );
|
||||||
|
|
||||||
|
//print_children( children );
|
||||||
|
|
||||||
|
if( xmg.get_node( children[0] ) == 0
|
||||||
|
&& !xmg.is_pi( xmg.get_node( children[1] ) )
|
||||||
|
&& !xmg.is_pi( xmg.get_node( children[2] ) ) )
|
||||||
|
{
|
||||||
|
auto result1 = v.validate( children[1], children[2] );
|
||||||
|
auto result2 = v.validate( children[1], !children[2] );
|
||||||
|
|
||||||
|
if( result1 == std::nullopt || result2 == std::nullopt )
|
||||||
|
{
|
||||||
|
//std::cout << "UNKNOWN status\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( result1 || result2 )
|
||||||
|
{
|
||||||
|
if( *result1 )
|
||||||
|
{
|
||||||
|
std::cout << "XOR node " << n << " can be removed as constant 0\n";
|
||||||
|
xors.push_back( n * 2 );
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
else if( *result2 )
|
||||||
|
{
|
||||||
|
std::cout << "XOR node " << n << " can be removed as constant 1\n";
|
||||||
|
xors.push_back( n * 2 + 1 );
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
std::cout << "[xmgrw -u] Find " << count << " XOR constant nodes\n";
|
||||||
|
return xors;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,925 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#include <mockturtle/mockturtle.hpp>
|
||||||
|
|
||||||
|
namespace mockturtle
|
||||||
|
{
|
||||||
|
|
||||||
|
/*! \brief Parameters for xmg_depth_rewriting.
|
||||||
|
*
|
||||||
|
* The data structure `xmg_depth_rewriting_params` holds configurable
|
||||||
|
* parameters with default arguments for `xmg_depth_rewriting`.
|
||||||
|
*/
|
||||||
|
struct xmg_depth_rewriting_params
|
||||||
|
{
|
||||||
|
/*! \brief Rewriting strategy. */
|
||||||
|
enum strategy_t
|
||||||
|
{
|
||||||
|
/*! \brief DFS rewriting strategy.
|
||||||
|
*
|
||||||
|
* Applies depth rewriting once to all output cones whose drivers have
|
||||||
|
* maximum levels
|
||||||
|
*/
|
||||||
|
dfs,
|
||||||
|
/*! \brief Aggressive rewriting strategy.
|
||||||
|
*
|
||||||
|
* Applies depth reduction multiple times until the number of nodes, which
|
||||||
|
* cannot be rewritten, matches the number of nodes, in the current
|
||||||
|
* network; or the new network size is larger than the initial size w.r.t.
|
||||||
|
* to an `overhead`.
|
||||||
|
*/
|
||||||
|
aggressive,
|
||||||
|
/*! \brief Selective rewriting strategy.
|
||||||
|
*
|
||||||
|
* Like `aggressive`, but only applies rewriting to nodes on critical paths
|
||||||
|
* and without `overhead`.
|
||||||
|
*/
|
||||||
|
selective,
|
||||||
|
/*! \brief Selective rewriting strategy.
|
||||||
|
*
|
||||||
|
* Like `dfs`, rewrite XOR( a, XOR( b, c ) ) as XOR3(a, b, c )
|
||||||
|
*/
|
||||||
|
qca
|
||||||
|
} strategy = dfs;
|
||||||
|
|
||||||
|
/*! \brief Overhead factor in aggressive rewriting strategy.
|
||||||
|
*
|
||||||
|
* When comparing to the initial size in aggressive depth rewriting, also the
|
||||||
|
* number of dangling nodes are taken into account.
|
||||||
|
*/
|
||||||
|
float overhead{2.0f};
|
||||||
|
|
||||||
|
/*! \brief Allow area increase while optimizing depth. */
|
||||||
|
bool allow_area_increase{true};
|
||||||
|
|
||||||
|
/*! \brief xor3 to two xor2s that compatiable with old cirkit */
|
||||||
|
bool apply_xor3_to_xor2{false};
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template<class Ntk>
|
||||||
|
class xmg_depth_rewriting_impl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
xmg_depth_rewriting_impl( Ntk& ntk, xmg_depth_rewriting_params const& ps )
|
||||||
|
: ntk( ntk ), ps( ps )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void run()
|
||||||
|
{
|
||||||
|
switch ( ps.strategy )
|
||||||
|
{
|
||||||
|
case xmg_depth_rewriting_params::dfs:
|
||||||
|
run_dfs();
|
||||||
|
break;
|
||||||
|
case xmg_depth_rewriting_params::selective:
|
||||||
|
run_selective();
|
||||||
|
break;
|
||||||
|
case xmg_depth_rewriting_params::aggressive:
|
||||||
|
run_aggressive();
|
||||||
|
break;
|
||||||
|
case xmg_depth_rewriting_params::qca:
|
||||||
|
run_qca();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ps.apply_xor3_to_xor2 )
|
||||||
|
{
|
||||||
|
run_xor3_flatten();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void run_qca()
|
||||||
|
{
|
||||||
|
/* reduce depth */
|
||||||
|
ntk.foreach_po( [this]( auto po ) {
|
||||||
|
const auto driver = ntk.get_node( po );
|
||||||
|
if ( ntk.level( driver ) < ntk.depth() )
|
||||||
|
return;
|
||||||
|
topo_view topo{ntk, po};
|
||||||
|
topo.foreach_node( [this]( auto n ) {
|
||||||
|
reduce_depth_ultimate( n );
|
||||||
|
return true;
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
|
||||||
|
/* rewrite xor2 to xor3 */
|
||||||
|
ntk.foreach_po( [this]( auto po ) {
|
||||||
|
topo_view topo{ntk, po};
|
||||||
|
topo.foreach_node( [this]( auto n ) {
|
||||||
|
reduce_depth_xor2_to_xor3( n );
|
||||||
|
return true;
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_dfs()
|
||||||
|
{
|
||||||
|
ntk.foreach_po( [this]( auto po ) {
|
||||||
|
const auto driver = ntk.get_node( po );
|
||||||
|
if ( ntk.level( driver ) < ntk.depth() )
|
||||||
|
return;
|
||||||
|
topo_view topo{ntk, po};
|
||||||
|
topo.foreach_node( [this]( auto n ) {
|
||||||
|
reduce_depth_ultimate( n );
|
||||||
|
return true;
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_selective()
|
||||||
|
{
|
||||||
|
uint32_t counter{0};
|
||||||
|
while ( true )
|
||||||
|
{
|
||||||
|
mark_critical_paths();
|
||||||
|
|
||||||
|
topo_view topo{ntk};
|
||||||
|
topo.foreach_node( [this, &counter]( auto n ) {
|
||||||
|
if ( ntk.fanout_size( n ) == 0 || ntk.value( n ) == 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( reduce_depth_ultimate( n ) )
|
||||||
|
{
|
||||||
|
mark_critical_paths();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++counter;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
if ( counter > ntk.size() )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_aggressive()
|
||||||
|
{
|
||||||
|
uint32_t counter{0}, init_size{ntk.size()};
|
||||||
|
while ( true )
|
||||||
|
{
|
||||||
|
topo_view topo{ntk};
|
||||||
|
topo.foreach_node( [this, &counter]( auto n ) {
|
||||||
|
if ( ntk.fanout_size( n ) == 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( !reduce_depth_ultimate( n ) )
|
||||||
|
{
|
||||||
|
++counter;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
if ( ntk.size() > ps.overhead * init_size )
|
||||||
|
break;
|
||||||
|
if ( counter > ntk.size() )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_xor3_flatten()
|
||||||
|
{
|
||||||
|
/* rewrite xor3 to xor2 */
|
||||||
|
ntk.foreach_po( [this]( auto po ) {
|
||||||
|
topo_view topo{ntk, po};
|
||||||
|
topo.foreach_node( [this]( auto n ) {
|
||||||
|
xor3_to_xor2( n );
|
||||||
|
return true;
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool reduce_depth_ultimate( node<Ntk> const& n )
|
||||||
|
{
|
||||||
|
auto b_1 = reduce_depth( n );
|
||||||
|
auto b2 = reduce_depth_xor_associativity( n );
|
||||||
|
auto b3 = reduce_depth_xor_complementary_associativity( n );
|
||||||
|
auto b4 = reduce_depth_xor_distribute( n );
|
||||||
|
|
||||||
|
if( !( b_1 | b2 | b3 | b4 ) ) { return false; }
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool xor3_to_xor2( node<Ntk> const& n )
|
||||||
|
{
|
||||||
|
if ( !ntk.is_xor3( n ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( ntk.level( n ) == 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* get children of top node, ordered by node level (ascending) */
|
||||||
|
const auto ocs = ordered_children( n );
|
||||||
|
|
||||||
|
/* if the first child is constant, return */
|
||||||
|
if( ocs[0].index == 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto opt = ntk.create_xor( ocs[2], ntk.create_xor( ocs[0], ocs[1] ) );
|
||||||
|
ntk.substitute_node( n, opt );
|
||||||
|
ntk.update_levels();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool reduce_depth_xor2_to_xor3( node<Ntk> const& n )
|
||||||
|
{
|
||||||
|
if ( !ntk.is_xor3( n ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( ntk.level( n ) == 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* get children of top node, ordered by node level (ascending) */
|
||||||
|
const auto ocs = ordered_children( n );
|
||||||
|
|
||||||
|
/* if the first child is not constant, return */
|
||||||
|
if( ocs[0].index != 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* if there are no XOR children, return */
|
||||||
|
if ( !ntk.is_xor3( ntk.get_node( ocs[2] ) ) && !ntk.is_xor3( ntk.get_node( ocs[1] ) ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( ntk.is_xor3( ntk.get_node( ocs[2] ) ) )
|
||||||
|
{
|
||||||
|
/* size optimization, do not allow area increase */
|
||||||
|
if( ntk.fanout_size( ntk.get_node( ocs[2] ) ) == 1 )
|
||||||
|
{
|
||||||
|
/* get children of last child */
|
||||||
|
auto ocs2 = ordered_children( ntk.get_node( ocs[2] ) );
|
||||||
|
|
||||||
|
/* propagate inverter if necessary */
|
||||||
|
if ( ntk.is_complemented( ocs[2] ) )
|
||||||
|
{
|
||||||
|
/* complement the constants */
|
||||||
|
ocs2[0] = !ocs2[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ocs2[0].index == 0 )
|
||||||
|
{
|
||||||
|
auto opt = ntk.create_xor3( ocs[1], ocs2[1], ocs2[2] );
|
||||||
|
ntk.substitute_node( n, opt );
|
||||||
|
ntk.update_levels();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ntk.is_xor3( ntk.get_node( ocs[1] ) ) )
|
||||||
|
{
|
||||||
|
/* size optimization, do not allow area increase */
|
||||||
|
if( ntk.fanout_size( ntk.get_node( ocs[1] ) ) == 1 )
|
||||||
|
{
|
||||||
|
/* get children of second child */
|
||||||
|
auto ocs2 = ordered_children( ntk.get_node( ocs[1] ) );
|
||||||
|
|
||||||
|
/* propagate inverter if necessary */
|
||||||
|
if ( ntk.is_complemented( ocs[1] ) )
|
||||||
|
{
|
||||||
|
/* complement the constants */
|
||||||
|
ocs2[0] = !ocs2[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ocs2[0].index == 0 )
|
||||||
|
{
|
||||||
|
auto opt = ntk.create_xor3( ocs[2], ocs2[1], ocs2[2] );
|
||||||
|
ntk.substitute_node( n, opt );
|
||||||
|
ntk.update_levels();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool reduce_depth( node<Ntk> const& n )
|
||||||
|
{
|
||||||
|
if ( !ntk.is_maj( n ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( ntk.level( n ) == 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* get children of top node, ordered by node level (ascending) */
|
||||||
|
const auto ocs = ordered_children( n );
|
||||||
|
|
||||||
|
if ( !ntk.is_maj( ntk.get_node( ocs[2] ) ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* depth of last child must be (significantly) higher than depth of second child */
|
||||||
|
if ( ntk.level( ntk.get_node( ocs[2] ) ) <= ntk.level( ntk.get_node( ocs[1] ) ) + 1 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* child must have single fanout, if no area overhead is allowed */
|
||||||
|
if ( !ps.allow_area_increase && ntk.fanout_size( ntk.get_node( ocs[2] ) ) != 1 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* get children of last child */
|
||||||
|
auto ocs2 = ordered_children( ntk.get_node( ocs[2] ) );
|
||||||
|
|
||||||
|
/* depth of last grand-child must be higher than depth of second grand-child */
|
||||||
|
if ( ntk.level( ntk.get_node( ocs2[2] ) ) == ntk.level( ntk.get_node( ocs2[1] ) ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* propagate inverter if necessary */
|
||||||
|
if ( ntk.is_complemented( ocs[2] ) )
|
||||||
|
{
|
||||||
|
ocs2[0] = !ocs2[0];
|
||||||
|
ocs2[1] = !ocs2[1];
|
||||||
|
ocs2[2] = !ocs2[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( auto cand = associativity_candidate( ocs[0], ocs[1], ocs2[0], ocs2[1], ocs2[2] ); cand )
|
||||||
|
{
|
||||||
|
const auto& [x, y, z, u, assoc] = *cand;
|
||||||
|
auto opt = ntk.create_maj( z, assoc ? u : x, ntk.create_maj( x, y, u ) );
|
||||||
|
ntk.substitute_node( n, opt );
|
||||||
|
ntk.update_levels();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* distributivity */
|
||||||
|
if ( ps.allow_area_increase )
|
||||||
|
{
|
||||||
|
auto opt = ntk.create_maj( ocs2[2],
|
||||||
|
ntk.create_maj( ocs[0], ocs[1], ocs2[0] ),
|
||||||
|
ntk.create_maj( ocs[0], ocs[1], ocs2[1] ) );
|
||||||
|
ntk.substitute_node( n, opt );
|
||||||
|
ntk.update_levels();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
using candidate_t = std::tuple<signal<Ntk>, signal<Ntk>, signal<Ntk>, signal<Ntk>, bool>;
|
||||||
|
std::optional<candidate_t> associativity_candidate( signal<Ntk> const& v, signal<Ntk> const& w, signal<Ntk> const& x, signal<Ntk> const& y, signal<Ntk> const& z ) const
|
||||||
|
{
|
||||||
|
if ( v.index == x.index )
|
||||||
|
{
|
||||||
|
return candidate_t{w, y, z, v, v.complement == x.complement};
|
||||||
|
}
|
||||||
|
if ( v.index == y.index )
|
||||||
|
{
|
||||||
|
return candidate_t{w, x, z, v, v.complement == y.complement};
|
||||||
|
}
|
||||||
|
if ( w.index == x.index )
|
||||||
|
{
|
||||||
|
return candidate_t{v, y, z, w, w.complement == x.complement};
|
||||||
|
}
|
||||||
|
if ( w.index == y.index )
|
||||||
|
{
|
||||||
|
return candidate_t{v, x, z, w, w.complement == y.complement};
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool reduce_depth_xor_associativity( node<Ntk> const& n )
|
||||||
|
{
|
||||||
|
if ( !ntk.is_xor3( n ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( ntk.level( n ) == 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* get children of top node, ordered by node level (ascending) */
|
||||||
|
const auto ocs = ordered_children( n );
|
||||||
|
|
||||||
|
if ( !ntk.is_xor3( ntk.get_node( ocs[2] ) ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* depth of last child must be (significantly) higher than depth of second child */
|
||||||
|
if ( ntk.level( ntk.get_node( ocs[2] ) ) <= ntk.level( ntk.get_node( ocs[1] ) ) + 1 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* child must have single fanout, if no area overhead is allowed */
|
||||||
|
if ( !ps.allow_area_increase && ntk.fanout_size( ntk.get_node( ocs[2] ) ) != 1 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* get children of last child */
|
||||||
|
auto ocs2 = ordered_children( ntk.get_node( ocs[2] ) );
|
||||||
|
|
||||||
|
/* depth of last grand-child must be higher than depth of second child */
|
||||||
|
if ( ntk.level( ntk.get_node( ocs2[2] ) ) + 1 <= ntk.level( ntk.get_node( ocs[1] ) ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* propagate inverter if necessary */
|
||||||
|
if ( ntk.is_complemented( ocs[2] ) )
|
||||||
|
{
|
||||||
|
ocs2[2] = !ocs2[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ocs[0] == ocs2[0] && ocs[0].index == 0 && ntk.fanout_size( ntk.get_node( ocs[2] ) ) == 1)
|
||||||
|
{
|
||||||
|
auto opt = ntk.create_xor3( ocs[0], ocs2[2],
|
||||||
|
ntk.create_xor3( ocs2[0], ocs2[1], ocs[1] ) );
|
||||||
|
ntk.substitute_node( n, opt );
|
||||||
|
ntk.update_levels();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XOR complementary associativity <xy[!yz]> = <xy[xz]> */
|
||||||
|
bool reduce_depth_xor_complementary_associativity( node<Ntk> const& n )
|
||||||
|
{
|
||||||
|
if ( !ntk.is_maj( n ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( ntk.level( n ) == 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* get children of top node, ordered by node level (ascending) */
|
||||||
|
const auto ocs = ordered_children( n );
|
||||||
|
|
||||||
|
if ( !ntk.is_xor3( ntk.get_node( ocs[2] ) ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* depth of last child must be (significantly) higher than depth of second child */
|
||||||
|
/* depth of last child must be higher than depth of second child */
|
||||||
|
if ( ntk.level( ntk.get_node( ocs[2] ) ) < ntk.level( ntk.get_node( ocs[1] ) ) + 1 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* multiple child fanout is allowable */
|
||||||
|
if ( !ps.allow_area_increase && ntk.fanout_size( ntk.get_node( ocs[2] ) ) != 1 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* get children of last child */
|
||||||
|
auto ocs2 = ordered_children( ntk.get_node( ocs[2] ) );
|
||||||
|
|
||||||
|
/* depth of last grand-child must be higher than depth of second grand-child */
|
||||||
|
if ( ntk.level( ntk.get_node( ocs2[2] ) ) == ntk.level( ntk.get_node( ocs2[1] ) ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* propagate inverter if necessary */
|
||||||
|
if ( ntk.is_complemented( ocs[2] ) )
|
||||||
|
{
|
||||||
|
if ( ntk.is_complemented( ocs2[0] ) )
|
||||||
|
{
|
||||||
|
ocs2[0] = !ocs2[0];
|
||||||
|
}
|
||||||
|
else if ( ntk.is_complemented( ocs2[1] ) )
|
||||||
|
{
|
||||||
|
ocs2[1] = !ocs2[1];
|
||||||
|
}
|
||||||
|
else if ( ntk.is_complemented( ocs2[2] ) )
|
||||||
|
{
|
||||||
|
ocs2[2] = !ocs2[2];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ocs2[0] = !ocs2[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( auto cand = xor_compl_associativity_candidate( ocs[0], ocs[1], ocs2[0], ocs2[1], ocs2[2] ); cand )
|
||||||
|
{
|
||||||
|
const auto& [x, y, z, u, assoc] = *cand;
|
||||||
|
auto opt = ntk.create_maj( x, u, ntk.create_xor3( assoc ? !x : x, y, z ) );
|
||||||
|
ntk.substitute_node( n, opt );
|
||||||
|
ntk.update_levels();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<candidate_t> xor_compl_associativity_candidate( signal<Ntk> const& v, signal<Ntk> const& w, signal<Ntk> const& x, signal<Ntk> const& y, signal<Ntk> const& z ) const
|
||||||
|
{
|
||||||
|
if ( v.index == x.index )
|
||||||
|
{
|
||||||
|
return candidate_t{w, y, z, v, v.complement == x.complement};
|
||||||
|
}
|
||||||
|
if ( v.index == y.index )
|
||||||
|
{
|
||||||
|
return candidate_t{w, x, z, v, v.complement == y.complement};
|
||||||
|
}
|
||||||
|
if ( v.index == z.index )
|
||||||
|
{
|
||||||
|
return candidate_t{w, x, y, v, v.complement == z.complement};
|
||||||
|
}
|
||||||
|
if ( w.index == x.index )
|
||||||
|
{
|
||||||
|
return candidate_t{v, y, z, w, w.complement == x.complement};
|
||||||
|
}
|
||||||
|
if ( w.index == y.index )
|
||||||
|
{
|
||||||
|
return candidate_t{v, x, z, w, w.complement == y.complement};
|
||||||
|
}
|
||||||
|
if ( w.index == z.index )
|
||||||
|
{
|
||||||
|
return candidate_t{v, x, y, w, w.complement == z.complement};
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XOR distribute over MAJ */
|
||||||
|
bool reduce_depth_xor_distribute( node<Ntk> const& n )
|
||||||
|
{
|
||||||
|
if ( !ntk.is_maj( n ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( ntk.level( n ) == 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* get children of top node, ordered by node level (ascending) */
|
||||||
|
const auto ocs = ordered_children( n );
|
||||||
|
|
||||||
|
std::vector<unsigned> xor_index;
|
||||||
|
for( auto i = 0; i <= 2; i++ )
|
||||||
|
{
|
||||||
|
if( ntk.is_xor3( ntk.get_node( ocs[i] ) ) )
|
||||||
|
{
|
||||||
|
xor_index.push_back( i );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* consider at least two xor child nodes */
|
||||||
|
if ( xor_index.size() < 2 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* depth of last child must be (significantly) higher than depth of second child */
|
||||||
|
if ( ntk.level( ntk.get_node( ocs[2] ) ) <= ntk.level( ntk.get_node( ocs[1] ) ) + 1 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* child must have single fanout, if no area overhead is allowed */
|
||||||
|
if( !ps.allow_area_increase )
|
||||||
|
{
|
||||||
|
for( const auto& index : xor_index )
|
||||||
|
{
|
||||||
|
if( ntk.fanout_size( ntk.get_node( ocs[index] ) ) != 1 )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* propagate inverter if necessary */
|
||||||
|
for( const auto& index : xor_index )
|
||||||
|
{
|
||||||
|
if( ntk.is_complemented( ntk.get_node( ocs[index] ) ) )
|
||||||
|
{
|
||||||
|
auto ocs_next = ordered_children( ntk.get_node( ocs[index] ) );
|
||||||
|
ocs_next[2] = !ocs_next[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( xor_index.size() == 3u )
|
||||||
|
{
|
||||||
|
auto ocs1 = ordered_children( ntk.get_node( ocs[0] ) );
|
||||||
|
auto ocs2 = ordered_children( ntk.get_node( ocs[1] ) );
|
||||||
|
auto ocs3 = ordered_children( ntk.get_node( ocs[2] ) );
|
||||||
|
|
||||||
|
if ( auto cand = find_common_grand_child_three( ocs1, ocs2, ocs3 ); cand )
|
||||||
|
{
|
||||||
|
auto r = *cand;
|
||||||
|
auto opt = ntk.create_xor3( r.a, r.b, ntk.create_maj( r.x, r.y, r.z ) );
|
||||||
|
ntk.substitute_node( n, opt );
|
||||||
|
ntk.update_levels();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if( xor_index.size() == 2u )
|
||||||
|
{
|
||||||
|
auto ocs2 = ordered_children( ntk.get_node( ocs[1] ) );
|
||||||
|
auto ocs3 = ordered_children( ntk.get_node( ocs[2] ) );
|
||||||
|
|
||||||
|
if ( auto cand = find_common_grand_child_two( ocs[0], ocs2, ocs3 ); cand )
|
||||||
|
{
|
||||||
|
auto r = *cand;
|
||||||
|
auto opt = ntk.create_xor3( r.a, r.b, ntk.create_maj( r.x, r.y, r.z ) );
|
||||||
|
ntk.substitute_node( n, opt );
|
||||||
|
ntk.update_levels();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_signal_equal( const signal<Ntk>& a, const signal<Ntk>& b )
|
||||||
|
{
|
||||||
|
return ( a == b ? true : false );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_three_signal_equal( const signal<Ntk>& a, const signal<Ntk>& b, const signal<Ntk>& c )
|
||||||
|
{
|
||||||
|
return ( a == b ? ( b == c ? true : false ): false );
|
||||||
|
}
|
||||||
|
|
||||||
|
using children_t = std::array< signal<Ntk>, 3 >;
|
||||||
|
std::bitset<9> get_pair_pattern( const children_t& c1, const children_t& c2 )
|
||||||
|
{
|
||||||
|
std::bitset<9> equals;
|
||||||
|
|
||||||
|
equals.set( 0u, is_signal_equal( c1[0], c2[0] ) );
|
||||||
|
equals.set( 1u, is_signal_equal( c1[0], c2[1] ) );
|
||||||
|
equals.set( 2u, is_signal_equal( c1[0], c2[2] ) );
|
||||||
|
equals.set( 3u, is_signal_equal( c1[1], c2[0] ) );
|
||||||
|
equals.set( 4u, is_signal_equal( c1[1], c2[1] ) );
|
||||||
|
equals.set( 5u, is_signal_equal( c1[1], c2[2] ) );
|
||||||
|
equals.set( 6u, is_signal_equal( c1[2], c2[0] ) );
|
||||||
|
equals.set( 7u, is_signal_equal( c1[2], c2[1] ) );
|
||||||
|
equals.set( 8u, is_signal_equal( c1[2], c2[2] ) );
|
||||||
|
|
||||||
|
return equals;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* struct for representing grand chiledren */
|
||||||
|
struct grand_children_pair_t
|
||||||
|
{
|
||||||
|
signal<Ntk> x;
|
||||||
|
signal<Ntk> y;
|
||||||
|
signal<Ntk> z;
|
||||||
|
signal<Ntk> a; //common grand child a
|
||||||
|
signal<Ntk> b; //common grand child b
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<size_t> equal_idx( const std::bitset<9> pattern )
|
||||||
|
{
|
||||||
|
std::vector<size_t> r;
|
||||||
|
for( size_t idx = 0; idx < pattern.size(); idx++ )
|
||||||
|
{
|
||||||
|
if( pattern.test( idx ) )
|
||||||
|
{
|
||||||
|
r.push_back( idx );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find common grand children in three children */
|
||||||
|
std::optional<grand_children_pair_t> find_common_grand_child_three( const children_t& c1, const children_t& c2, const children_t& c3 )
|
||||||
|
{
|
||||||
|
grand_children_pair_t r;
|
||||||
|
|
||||||
|
auto p1 = get_pair_pattern( c1, c2 );
|
||||||
|
auto p2 = get_pair_pattern( c1, c3 );
|
||||||
|
auto p3 = get_pair_pattern( c2, c3 );
|
||||||
|
|
||||||
|
auto s1 = equal_idx( p1 );
|
||||||
|
auto s2 = equal_idx( p2 );
|
||||||
|
auto s3 = equal_idx( p3 );
|
||||||
|
|
||||||
|
if( s1.size() != 2u || s2.size() != 2u || s3.size() != 2u )
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
auto c11 = c1[ s1[0u] / 3 ];
|
||||||
|
auto c12 = c1[ s1[1u] / 3 ];
|
||||||
|
auto c21 = c2[ s3[0u] / 3 ];
|
||||||
|
auto c22 = c2[ s3[1u] / 3 ];
|
||||||
|
auto c31 = c3[ s2[0u] % 3 ];
|
||||||
|
auto c32 = c3[ s2[1u] % 3 ];
|
||||||
|
|
||||||
|
std::bitset<8> equals;
|
||||||
|
|
||||||
|
equals.set( 0u, is_three_signal_equal( c11, c21, c31 ) );
|
||||||
|
equals.set( 1u, is_three_signal_equal( c11, c21, c32 ) );
|
||||||
|
equals.set( 2u, is_three_signal_equal( c11, c22, c31 ) );
|
||||||
|
equals.set( 3u, is_three_signal_equal( c11, c22, c32 ) );
|
||||||
|
equals.set( 4u, is_three_signal_equal( c12, c21, c31 ) );
|
||||||
|
equals.set( 5u, is_three_signal_equal( c12, c21, c32 ) );
|
||||||
|
equals.set( 6u, is_three_signal_equal( c12, c22, c31 ) );
|
||||||
|
equals.set( 7u, is_three_signal_equal( c12, c22, c32 ) );
|
||||||
|
|
||||||
|
std::vector<signal<Ntk>> common;
|
||||||
|
for( size_t idx = 0; idx < 8; idx++ )
|
||||||
|
{
|
||||||
|
if( equals.test( idx ) )
|
||||||
|
{
|
||||||
|
if( idx < 4 )
|
||||||
|
{
|
||||||
|
common.push_back( c11 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
common.push_back( c12 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( common.size() != 2 )
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
r.a = common[0u];
|
||||||
|
r.b = common[1u];
|
||||||
|
|
||||||
|
for( auto i = 0u; i < 3u; i++ )
|
||||||
|
{
|
||||||
|
if( c1[i] != common[0u] && c1[i] != common[1u] )
|
||||||
|
{
|
||||||
|
r.x = c1[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if( c2[i] != common[0u] && c2[i] != common[1u] )
|
||||||
|
{
|
||||||
|
r.y = c2[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if( c3[i] != common[0u] && c3[i] != common[1u] )
|
||||||
|
{
|
||||||
|
r.z = c3[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find common grand children in two children */
|
||||||
|
std::optional<grand_children_pair_t> find_common_grand_child_two( const signal<Ntk>& v, const children_t& c1, const children_t& c2 )
|
||||||
|
{
|
||||||
|
grand_children_pair_t r;
|
||||||
|
auto p = get_pair_pattern( c1, c2 );
|
||||||
|
|
||||||
|
std::vector<signal<Ntk>> common;
|
||||||
|
|
||||||
|
for( size_t idx = 0; idx < p.size(); idx++ )
|
||||||
|
{
|
||||||
|
if( p.test(idx) )
|
||||||
|
{
|
||||||
|
assert( c1[idx / 3] == c2[ idx % 3 ] );
|
||||||
|
common.push_back( c1[ idx / 3] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//std::cout << "common size: " << common.size() << std::endl;
|
||||||
|
//std::cout << "common 0 index: " << common[0].index << std::endl;
|
||||||
|
//std::cout << "common 1 index: " << common[1].index << std::endl;
|
||||||
|
//std::cout << "v index: " << v.index << std::endl;
|
||||||
|
/* for xor children, require at least two common children */
|
||||||
|
if( common.size() != 2u )
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
/* the signal v index must equal one of the common signal index, and one common signal is
|
||||||
|
* constant 1 or 0 */
|
||||||
|
if( v.index != common[0u].index && v.index != common[1u].index )
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
if( common[0u].index != 0 && common[1u].index != 0 )
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
/* save the records */
|
||||||
|
r.a = common[0u];
|
||||||
|
r.b = common[1u];
|
||||||
|
|
||||||
|
for( auto i = 0u; i < 3u; i++ )
|
||||||
|
{
|
||||||
|
if( c1[i] != common[0u] && c1[i] != common[1u] )
|
||||||
|
{
|
||||||
|
r.x = c1[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if( c2[i] != common[0u] && c2[i] != common[1u] )
|
||||||
|
{
|
||||||
|
r.y = c2[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( v == !common[0u] || v == !common[1u] )
|
||||||
|
{
|
||||||
|
r.z = ntk.get_constant( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( v == common[0u] || v == common[1u] )
|
||||||
|
{
|
||||||
|
r.z = ntk.get_constant( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<signal<Ntk>, 3> ordered_children( node<Ntk> const& n ) const
|
||||||
|
{
|
||||||
|
std::array<signal<Ntk>, 3> children;
|
||||||
|
ntk.foreach_fanin( n, [&children]( auto const& f, auto i ) { children[i] = f; } );
|
||||||
|
std::sort( children.begin(), children.end(), [this]( auto const& c1, auto const& c2 ) {
|
||||||
|
if( ntk.level( ntk.get_node( c1 ) ) == ntk.level( ntk.get_node( c2 ) ) )
|
||||||
|
{
|
||||||
|
return c1.index < c2.index;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ntk.level( ntk.get_node( c1 ) ) < ntk.level( ntk.get_node( c2 ) );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mark_critical_path( node<Ntk> const& n )
|
||||||
|
{
|
||||||
|
if ( ntk.is_pi( n ) || ntk.is_constant( n ) || ntk.value( n ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto level = ntk.level( n );
|
||||||
|
ntk.set_value( n, 1 );
|
||||||
|
ntk.foreach_fanin( n, [this, level]( auto const& f ) {
|
||||||
|
if ( ntk.level( ntk.get_node( f ) ) == level - 1 )
|
||||||
|
{
|
||||||
|
mark_critical_path( ntk.get_node( f ) );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
void mark_critical_paths()
|
||||||
|
{
|
||||||
|
ntk.clear_values();
|
||||||
|
ntk.foreach_po( [this]( auto const& f ) {
|
||||||
|
if ( ntk.level( ntk.get_node( f ) ) == ntk.depth() )
|
||||||
|
{
|
||||||
|
mark_critical_path( ntk.get_node( f ) );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ntk& ntk;
|
||||||
|
xmg_depth_rewriting_params const& ps;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
/*! \brief XMG algebraic depth rewriting.
|
||||||
|
*
|
||||||
|
* This algorithm tries to rewrite a network with majority gates for depth
|
||||||
|
* optimization using the associativity and distributivity rule in
|
||||||
|
* majority-of-3 logic. It can be applied to networks other than XMGs, but
|
||||||
|
* only considers pairs of nodes which both implement the majority-of-3
|
||||||
|
* function and the XOR function.
|
||||||
|
*
|
||||||
|
* **Required network functions:**
|
||||||
|
* - `get_node`
|
||||||
|
* - `level`
|
||||||
|
* - `update_levels`
|
||||||
|
* - `create_maj`
|
||||||
|
* - `substitute_node`
|
||||||
|
* - `foreach_node`
|
||||||
|
* - `foreach_po`
|
||||||
|
* - `foreach_fanin`
|
||||||
|
* - `is_maj`
|
||||||
|
* - `clear_values`
|
||||||
|
* - `set_value`
|
||||||
|
* - `value`
|
||||||
|
* - `fanout_size`
|
||||||
|
*
|
||||||
|
\verbatim embed:rst
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The implementation of this algorithm was heavily inspired by an
|
||||||
|
implementation from Luca Amarù.
|
||||||
|
\endverbatim
|
||||||
|
*/
|
||||||
|
template<class Ntk>
|
||||||
|
void xmg_depth_rewriting( Ntk& ntk, xmg_depth_rewriting_params const& ps = {} )
|
||||||
|
{
|
||||||
|
static_assert( is_network_type_v<Ntk>, "Ntk is not a network type" );
|
||||||
|
static_assert( has_get_node_v<Ntk>, "Ntk does not implement the get_node method" );
|
||||||
|
static_assert( has_level_v<Ntk>, "Ntk does not implement the level method" );
|
||||||
|
static_assert( has_create_maj_v<Ntk>, "Ntk does not implement the create_maj method" );
|
||||||
|
static_assert( has_create_xor_v<Ntk>, "Ntk does not implement the create_maj method" );
|
||||||
|
static_assert( has_substitute_node_v<Ntk>, "Ntk does not implement the substitute_node method" );
|
||||||
|
static_assert( has_update_levels_v<Ntk>, "Ntk does not implement the update_levels method" );
|
||||||
|
static_assert( has_foreach_node_v<Ntk>, "Ntk does not implement the foreach_node method" );
|
||||||
|
static_assert( has_foreach_po_v<Ntk>, "Ntk does not implement the foreach_po method" );
|
||||||
|
static_assert( has_foreach_fanin_v<Ntk>, "Ntk does not implement the foreach_fanin method" );
|
||||||
|
static_assert( has_is_maj_v<Ntk>, "Ntk does not implement the is_maj method" );
|
||||||
|
static_assert( has_is_xor3_v<Ntk>, "Ntk does not implement the is_maj method" );
|
||||||
|
static_assert( has_clear_values_v<Ntk>, "Ntk does not implement the clear_values method" );
|
||||||
|
static_assert( has_set_value_v<Ntk>, "Ntk does not implement the set_value method" );
|
||||||
|
static_assert( has_value_v<Ntk>, "Ntk does not implement the value method" );
|
||||||
|
static_assert( has_fanout_size_v<Ntk>, "Ntk does not implement the fanout_size method" );
|
||||||
|
|
||||||
|
detail::xmg_depth_rewriting_impl<Ntk> p( ntk, ps );
|
||||||
|
p.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace mockturtle */
|
|
@ -70,5 +70,11 @@
|
||||||
#include "commands/abc/balance.hpp"
|
#include "commands/abc/balance.hpp"
|
||||||
#include "commands/abc/refactor.hpp"
|
#include "commands/abc/refactor.hpp"
|
||||||
#include "commands/abc/rewrite.hpp"
|
#include "commands/abc/rewrite.hpp"
|
||||||
|
#include "commands/xag/rm.hpp"
|
||||||
|
#include "commands/xag/rm2.hpp"
|
||||||
|
#include "commands/xag/xagrw.hpp"
|
||||||
|
#include "commands/xag/xagrs.hpp"
|
||||||
|
#include "commands/xmg/xmgrs.hpp"
|
||||||
|
#include "commands/xmg/xmgrw.hpp"
|
||||||
|
|
||||||
ALICE_MAIN(phyLS)
|
ALICE_MAIN(phyLS)
|
Loading…
Reference in New Issue