Compare commits

...

4 Commits
master ... aig

Author SHA1 Message Date
panhongyang0 577a280b2e doc 2024-05-10 16:36:43 +08:00
panhongyang0 a29f90f9f2 update readme 2024-05-10 15:29:43 +08:00
panhongyang0 7686d75739 aig synthesis framework 2024-05-10 15:18:09 +08:00
panhongyang0 b46512b41b AIG based logic synthesis framework 2024-05-09 16:10:23 +08:00
117 changed files with 302 additions and 363189 deletions

3
.gitmodules vendored
View File

@ -4,6 +4,3 @@
[submodule "lib/mockturtle"]
path = lib/mockturtle
url = https://github.com/panhomyoung/mockturtle.git
[submodule "lib/abc"]
path = lib/abc
url = https://github.com/panhomyoung/abc.git

View File

@ -11,7 +11,7 @@ Compiled successfully with Clang 6.0.1, Clang 12.0.0, GCC 7.3.0, and GCC 8.2.0.
## How to Compile
```bash
git clone --recursive https://github.com/panhongyang0/phyLS.git
git clone -b aig --recursive https://github.com/panhongyang0/phyLS.git
cd phyLS
mkdir build
cd build
@ -19,3 +19,15 @@ cmake ..
make
./bin/phyLS
```
## baseline scripts
```bash
read_aiger ../benchmarks/adder.aig;
ps -a;
resub;
balance;
rewrite;
read_genlib ../src/mcnc.genlib;
techmap;
quit;
```

View File

@ -1,8 +1,3 @@
# Add alice and mockturtle sub directories
add_subdirectory(alice)
add_subdirectory(mockturtle)
set(ABC_USE_NAMESPACE "pabc")
add_subdirectory(abc EXCLUDE_FROM_ALL)
target_compile_definitions(libabc-pic PUBLIC "LIN64")
add_subdirectory(mockturtle)

@ -1 +0,0 @@
Subproject commit 9434b7438599b2fe94ec518946d0e1b6b2de3172

BIN
src/.DS_Store vendored

Binary file not shown.

View File

@ -5,4 +5,4 @@ file(GLOB_RECURSE FILENAMES *.cpp)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
add_executable(phyLS phyLS.cpp ${FILENAMES})
target_link_libraries(phyLS alice mockturtle libabc-pic)
target_link_libraries(phyLS alice mockturtle)

View File

@ -1,80 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file &fraig.hpp
*
* @brief performs combinational SAT sweeping
*
* @author Homyoung
* @since 2023/03/14
*/
#ifndef AFRAIG_HPP
#define AFRAIG_HPP
#include "aig/gia/gia.h"
#include "proof/cec/cec.h"
using namespace std;
using namespace mockturtle;
namespace alice {
class Afraig_command : public command {
public:
explicit Afraig_command(const environment::ptr &env)
: command(env, "performs combinational SAT sweeping") {
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
begin = clock();
if (store<pabc::Gia_Man_t *>().size() == 0u)
std::cerr << "Error: Empty GIA network.\n";
else {
pabc::Gia_Man_t *pNtk, *pTemp;
pNtk = store<pabc::Gia_Man_t *>().current();
pabc::Cec_ParFra_t ParsFra, *pPars = &ParsFra;
// set defaults
memset(pPars, 0, sizeof(pabc::Cec_ParFra_t));
pPars->jType = 2; // solver type
pPars->fSatSweeping = 1; // conflict limit at a node
pPars->nWords = 4; // simulation words
pPars->nRounds = 10; // simulation rounds
pPars->nItersMax = 2000; // this is a miter
pPars->nBTLimit = 1000000; // use logic cones
pPars->nBTLimitPo = 0; // use logic outputs
pPars->nSatVarMax =
1000; // the max number of SAT variables before recycling SAT solver
pPars->nCallsRecycle =
500; // calls to perform before recycling SAT solver
pPars->nGenIters = 100; // pattern generation iterations
pTemp = Cec_ManSatSweeping(pNtk, pPars, 0);
store<pabc::Gia_Man_t *>().extend();
store<pabc::Gia_Man_t *>().current() = pTemp;
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
};
ALICE_ADD_COMMAND(Afraig, "Gia")
} // namespace alice
#endif

View File

@ -1,70 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file &get.hpp
*
* @brief converts the current network into GIA
*
* @author Homyoung
* @since 2023/03/14
*/
#ifndef AGET_HPP
#define AGET_HPP
#include "aig/gia/giaAig.h"
#include "base/abc/abc.h"
#include "base/abci/abcDar.c"
using namespace std;
using namespace mockturtle;
namespace alice {
class Aget_command : public command {
public:
explicit Aget_command(const environment::ptr &env)
: command(env, "converts the current network into GIA") {}
protected:
void execute() {
clock_t begin, end;
double totalTime;
begin = clock();
if (store<pabc::Abc_Ntk_t *>().size() == 0u)
std::cerr << "Error: Empty ABC AIG network\n";
else {
pabc::Abc_Ntk_t *pNtk = store<pabc::Abc_Ntk_t *>().current();
pabc::Aig_Man_t *pAig;
pabc::Gia_Man_t *pGia;
if (pabc::Abc_NtkGetChoiceNum(pNtk))
pAig = Abc_NtkToDarChoices(pNtk);
else
pAig = Abc_NtkToDar(pNtk, 0, 1);
pGia = Gia_ManFromAig(pAig);
pabc::Aig_ManStop(pAig);
store<pabc::Gia_Man_t *>().extend();
store<pabc::Gia_Man_t *>().current() = pGia;
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
};
ALICE_ADD_COMMAND(Aget, "Gia")
} // namespace alice
#endif

View File

@ -1,92 +0,0 @@
/* LogicMap: powerful technology-mapping tool in logic synthesis
* Copyright (C) 2023 */
/**
* @file &if.hpp
*
* @brief performs FPGA mapping of the GIA
*
* @author Homyoung
* @since 2023/11/16
*/
#ifndef ABC_GIA_IF_HPP
#define ABC_GIA_IF_HPP
#include "aig/gia/gia.h"
#include "base/abc/abc.h"
using namespace mockturtle;
using namespace std;
using namespace pabc;
namespace alice {
class Aif_command : public command {
public:
explicit Aif_command(const environment::ptr &env)
: command(env, "performs FPGA mapping of the AIG") {
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
begin = clock();
Gia_Man_t *pGia, *pNew;
If_Par_t Pars, *pPars = &Pars;
Gia_ManSetIfParsDefault(pPars);
if (store<pabc::Gia_Man_t *>().size() == 0u)
std::cerr << "Error: Empty GIA network.\n";
else {
pGia = store<pabc::Gia_Man_t *>().current();
// set defaults
pPars->pLutLib = (If_LibLut_t *)Abc_FrameReadLibLut();
if (Gia_ManHasMapping(pGia)) {
printf("Current AIG has mapping. Run \"&st\".\n");
return;
}
if (pPars->nLutSize == -1) {
if (pPars->pLutLib == NULL) {
printf("The LUT library is not given.\n");
return;
}
pPars->nLutSize = pPars->pLutLib->LutMax;
}
if (pPars->nLutSize < 2 || pPars->nLutSize > IF_MAX_LUTSIZE) {
printf("Incorrect LUT size (%d).\n", pPars->nLutSize);
return;
}
if (pPars->nCutsMax < 1 || pPars->nCutsMax >= (1 << 12)) {
printf("Incorrect number of cuts.\n");
return;
}
// get the new network
pNew = Gia_ManPerformMapping(pGia, pPars);
if (pNew == NULL) {
printf("Mapping of GIA has failed..\n");
return;
}
store<pabc::Gia_Man_t *>().extend();
store<pabc::Gia_Man_t *>().current() = pNew;
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
};
ALICE_ADD_COMMAND(Aif, "Gia")
} // namespace alice
#endif

View File

@ -1,72 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file &nf.hpp
*
* @brief performs technology-independent mapping of the GIA
*
* @author Homyoung
* @since 2023/11/16
*/
#ifndef ABC_NF_HPP
#define ABC_NF_HPP
#include "aig/gia/gia.h"
#include "base/abc/abc.h"
#include "aig/gia/giaNf.c"
using namespace mockturtle;
using namespace std;
using namespace pabc;
namespace alice {
class Anf_command : public command {
public:
explicit Anf_command(const environment::ptr &env)
: command(env, "performs technology mapping of the GIA network") {
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
begin = clock();
char Buffer[200];
pabc::Jf_Par_t Pars, *pPars = &Pars;
pabc::Gia_Man_t *pGia, *pNew;
pabc::Nf_ManSetDefaultPars(pPars);
if (store<pabc::Gia_Man_t *>().size() == 0u)
std::cerr << "Error: Empty GIA network.\n";
else {
pGia = store<pabc::Gia_Man_t *>().current();
if (pabc::Abc_FrameReadLibGen() == NULL) {
pabc::Abc_Print(-1, "Current library is not available.\n");
return;
}
pNew = pabc::Nf_ManPerformMapping(pGia, pPars);
store<pabc::Gia_Man_t *>().extend();
store<pabc::Gia_Man_t *>().current() = pNew;
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
};
ALICE_ADD_COMMAND(Anf, "Gia")
} // namespace alice
#endif

View File

@ -1,105 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file amap.hpp
*
* @brief performs technology-independent mapping of the AIG
*
* @author Homyoung
* @since 2023/11/16
*/
#ifndef ABC_AMAP_HPP
#define ABC_AMAP_HPP
#include "map/amap/amap.h"
#include "base/abc/abc.h"
#include "base/abci/abcSweep.c"
using namespace mockturtle;
using namespace std;
using namespace pabc;
namespace alice {
class amap_command : public command {
public:
explicit amap_command(const environment::ptr &env)
: command(env, "performs standard cell mapping of the current network") {
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
begin = clock();
if (store<pabc::Abc_Ntk_t *>().size() == 0u)
std::cerr << "Error: Empty ABC AIG network\n";
else {
Abc_Ntk_t *pNtk = store<pabc::Abc_Ntk_t *>().current();
// set defaults
Amap_Par_t Pars, *pPars = &Pars;
Abc_Ntk_t *pNtkRes;
int fSweep = 0;
Amap_ManSetDefaultParams(pPars);
if (!Abc_NtkIsStrash(pNtk)) {
pNtk = Abc_NtkStrash(pNtk, 0, 0, 0);
if (pNtk == NULL) {
printf("Strashing before mapping has failed.\n");
return;
}
pNtk = Abc_NtkBalance(pNtkRes = pNtk, 0, 0, 1);
Abc_NtkDelete(pNtkRes);
if (pNtk == NULL) {
printf("Balancing before mapping has failed.\n");
return;
}
printf("The network was strashed and balanced before mapping.\n");
// get the new network
pNtkRes = Abc_NtkDarAmap(pNtk, pPars);
if (pNtkRes == NULL) {
Abc_NtkDelete(pNtk);
printf("Mapping has failed.\n");
return;
}
Abc_NtkDelete(pNtk);
} else {
// get the new network
pNtkRes = Abc_NtkDarAmap(pNtk, pPars);
if (pNtkRes == NULL) {
printf("Mapping has failed.\n");
return;
}
}
if (fSweep) {
Abc_NtkFraigSweep(pNtkRes, 0, 0, 0, 0);
if (Abc_NtkHasMapping(pNtkRes)) {
pNtkRes = Abc_NtkDupDfs(pNtk = pNtkRes);
Abc_NtkDelete(pNtk);
}
}
store<pabc::Abc_Ntk_t *>().extend();
store<pabc::Abc_Ntk_t *>().current() = pNtkRes;
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
};
ALICE_ADD_COMMAND(amap, "ABC")
} // namespace alice
#endif

View File

@ -1,107 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file balance.hpp
*
* @brief transforms the current network into a well-balanced AIG
*
* @author Homyoung
* @since 2023/11/16
*/
#ifndef ABC_BALANCE_HPP
#define ABC_BALANCE_HPP
// #include "base/abci/abc.c"
#include "base/abc/abc.h"
#include "base/abci/abcBalance.c"
using namespace std;
using namespace mockturtle;
using namespace pabc;
namespace alice {
class abalance_command : public command {
public:
explicit abalance_command(const environment::ptr &env)
: command(env,
"transforms the current network into a well-balanced AIG") {
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
begin = clock();
if (store<pabc::Abc_Ntk_t *>().size() == 0u)
std::cerr << "Error: Empty AIG network.\n";
else {
Abc_Ntk_t *pNtk, *pNtkRes, *pNtkTemp;
pNtk = store<pabc::Abc_Ntk_t *>().current();
int c;
int fDuplicate;
int fSelective;
int fUpdateLevel;
int fExor;
int fVerbose;
// set defaults
fDuplicate = 0;
fSelective = 0;
fUpdateLevel = 1;
fExor = 0;
fVerbose = 0;
Extra_UtilGetoptReset();
if (pNtk == NULL) {
Abc_Print(-1, "Empty network.\n");
return;
}
// get the new network
if (Abc_NtkIsStrash(pNtk)) {
if (fExor)
pNtkRes = Abc_NtkBalanceExor(pNtk, fUpdateLevel, fVerbose);
else
pNtkRes = Abc_NtkBalance(pNtk, fDuplicate, fSelective, fUpdateLevel);
} else {
pNtkTemp = Abc_NtkStrash(pNtk, 0, 0, 0);
if (pNtkTemp == NULL) {
Abc_Print(-1, "Strashing before balancing has failed.\n");
return;
}
if (fExor)
pNtkRes = Abc_NtkBalanceExor(pNtkTemp, fUpdateLevel, fVerbose);
else
pNtkRes =
Abc_NtkBalance(pNtkTemp, fDuplicate, fSelective, fUpdateLevel);
Abc_NtkDelete(pNtkTemp);
}
// check if balancing worked
if (pNtkRes == NULL) {
Abc_Print(-1, "Balancing has failed.\n");
return;
}
// replace the current network
// Abc_FrameReplaceCurrentNetwork(pAbc, pNtkRes);
store<pabc::Abc_Ntk_t *>().extend();
store<pabc::Abc_Ntk_t *>().current() = pNtkRes;
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
};
ALICE_ADD_COMMAND(abalance, "ABC")
} // namespace alice
#endif

View File

@ -1,84 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2022 */
/**
* @file cec.hpp
*
* @brief performs combinational equivalence checking
*
* @author Homyoung
* @since 2022/12/14
*/
#ifndef CEC2_HPP
#define CEC2_HPP
#include <vector>
#include "base/abc/abc.h"
#include "base/abci/abcVerify.c"
using namespace std;
using namespace mockturtle;
namespace alice {
class acec_command : public command {
public:
explicit acec_command(const environment::ptr &env)
: command(env, "performs combinational equivalence checking") {
add_option("file1, -f", filename_1, "the input file name");
add_option("file2, -b", filename_2, "the input file name");
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
begin = clock();
pabc::Abc_Ntk_t *pNtk;
int fDelete1 = 0, fDelete2 = 0;
int nArgcNew = 0;
char **pArgvNew;
int fCheck = 1, fBarBufs = 0;
pabc::Abc_Ntk_t *pNtk1 = pabc::Io_Read(
(char *)(filename_1.c_str()),
pabc::Io_ReadFileType((char *)(filename_1.c_str())), fCheck, fBarBufs);
end = clock();
pabc::Abc_Ntk_t *pNtk2 = pabc::Io_Read(
(char *)(filename_2.c_str()),
pabc::Io_ReadFileType((char *)(filename_2.c_str())), fCheck, fBarBufs);
// set defaults
int fSat = 0;
int fVerbose = 0;
int nSeconds = 20;
int nPartSize = 0;
int nConfLimit = 10000;
int nInsLimit = 0;
int fPartition = 0;
int fIgnoreNames = 0;
pabc::Abc_NtkCecFraig(pNtk1, pNtk2, nSeconds, fVerbose);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
string filename_1;
string filename_2;
};
ALICE_ADD_COMMAND(acec, "ABC")
} // namespace alice
#endif

View File

@ -1,72 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file comb.hpp
*
* @brief converts comb network into seq, and vice versa
*
* @author Homyoung
* @since 2023/03/21
*/
#ifndef COMB_HPP
#define COMB_HPP
#include "base/abc/abc.h"
using namespace std;
using namespace mockturtle;
namespace alice {
class comb_command : public command {
public:
explicit comb_command(const environment::ptr &env)
: command(env, "converts comb network into seq, and vice versa") {
add_flag(
"--convert, -c",
"converting latches to PIs/POs or removing them [default = convert]");
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
begin = clock();
if (store<pabc::Abc_Ntk_t *>().size() == 0u)
std::cerr << "Error: Empty ABC AIG network.\n";
else {
pabc::Abc_Ntk_t *pNtk, *pNtkRes;
pNtk = store<pabc::Abc_Ntk_t *>().current();
if (pabc::Abc_NtkIsComb(pNtk))
std::cerr << "The network is already combinational.\n";
int fRemoveLatches = 0;
if (is_set("convert")) fRemoveLatches ^= 1;
pNtkRes = pabc::Abc_NtkDup(pNtk);
pabc::Abc_NtkMakeComb(pNtkRes, fRemoveLatches);
store<pabc::Abc_Ntk_t *>().extend();
store<pabc::Abc_Ntk_t *>().current() = pNtkRes;
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
};
ALICE_ADD_COMMAND(comb, "ABC")
} // namespace alice
#endif

View File

@ -1,290 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file compress2rs.hpp
*
* @brief combination optimization script
*
* @author Homyoung
* @since 2023/11/16
*/
#ifndef COMPRESS2RS_HPP
#define COMPRESS2RS_HPP
// #include "base/abci/abc.c"
#include "base/abc/abc.h"
// #include "base/abci/abcDar.c"
#include "base/abci/abcResub.c"
using namespace std;
using namespace mockturtle;
using namespace pabc;
namespace alice {
class compress2rs_command : public command {
public:
explicit compress2rs_command(const environment::ptr &env)
: command(env, "combination optimization script") {
add_flag("--verbose, -v", "print the information");
}
public:
void Dar_ManDefaultResParams(Dar_ResPar_t *pPars) {
memset(pPars, 0, sizeof(Dar_ResPar_t));
pPars->nCutsMax = 8; // 8
pPars->nNodesMax = 1;
pPars->nLevelsOdc = 0;
pPars->fUpdateLevel = 1;
pPars->fUseZeros = 0;
pPars->fVerbose = 0;
pPars->fVeryVerbose = 0;
}
Aig_Man_t *Dar_ManCompress2rs(Abc_Ntk_t *pNtk, Aig_Man_t *pAig, int fBalance,
int fUpdateLevel, int fFanout, int fPower,
int fVerbose, int nMinSaved) {
// alias compress2rs "b -l; rs -K 6 -l; rw -l; rs -K 6 -N 2 -l; rf -l; rs
// -K 8 -l; b -l; rs -K 8 -N 2 -l; rw -l; rs -K 10 -l; rwz -l; rs -K 10
// -N 2 -l; b -l; rs -K 12 -l; rfz -l; rs -K 12 -N 2 -l; rwz -l; b -l"
Aig_Man_t *pTemp;
Abc_Ntk_t *pNtkAig;
Dar_RwrPar_t ParsRwr, *pParsRwr = &ParsRwr;
Dar_RefPar_t ParsRef, *pParsRef = &ParsRef;
Dar_ResPar_t ParsRes, *pParsRes = &ParsRes;
Dar_ManDefaultRwrParams(pParsRwr);
Dar_ManDefaultRefParams(pParsRef);
Dar_ManDefaultResParams(pParsRes);
pParsRwr->fUpdateLevel = fUpdateLevel;
pParsRef->fUpdateLevel = fUpdateLevel;
pParsRes->fUpdateLevel = fUpdateLevel;
// pParsRes->nCutsMax = nCutsMax;
// pParsRes->nNodesMax = nNodesMax;
pParsRwr->fFanout = fFanout;
pParsRwr->fPower = fPower;
pParsRwr->fVerbose = 0; // fVerbose;
pParsRef->fVerbose = 0; // fVerbose;
pParsRes->fVerbose = 0; // fVerbose;
pAig = Aig_ManDupDfs(pAig);
if (fVerbose) printf("Starting: "), Aig_ManPrintStats(pAig);
// b -l;
fUpdateLevel = 0;
pAig = Dar_ManBalance(pTemp = pAig, fUpdateLevel);
Aig_ManStop(pTemp);
if (fVerbose) printf("Balance: "), Aig_ManPrintStats(pAig);
// rs -K 6 -l;
pNtkAig = Abc_NtkFromDar(pNtk, pAig);
pParsRes->nCutsMax = 6;
pParsRes->fUpdateLevel = 0;
pParsRes->nNodesMax = 1;
Abc_NtkResubstitute(pNtkAig, pParsRes->nCutsMax, pParsRes->nNodesMax,
nMinSaved, pParsRes->nLevelsOdc, fUpdateLevel, fVerbose,
pParsRes->fVeryVerbose);
pAig = Abc_NtkToDar(pNtkAig, 0, 0);
if (fVerbose) printf("Resub: "), Aig_ManPrintStats(pAig);
// rw -l;
pParsRwr->fUpdateLevel = 0;
Dar_ManRewrite(pAig, pParsRwr);
pAig = Aig_ManDupDfs(pTemp = pAig);
Aig_ManStop(pTemp);
if (fVerbose) printf("Rewrite: "), Aig_ManPrintStats(pAig);
// rs -K 6 -N 2 -l;
pNtkAig = Abc_NtkFromDar(pNtk, pAig);
pParsRes->nCutsMax = 6;
pParsRes->fUpdateLevel = 0;
pParsRes->nNodesMax = 2;
Abc_NtkResubstitute(pNtkAig, pParsRes->nCutsMax, pParsRes->nNodesMax,
nMinSaved, pParsRes->nLevelsOdc, fUpdateLevel, fVerbose,
pParsRes->fVeryVerbose);
pAig = Abc_NtkToDar(pNtkAig, 0, 0);
if (fVerbose) printf("Resub: "), Aig_ManPrintStats(pAig);
// rf -l;
pParsRef->fUpdateLevel = 0;
Dar_ManRefactor(pAig, pParsRef);
pAig = Aig_ManDupDfs(pTemp = pAig);
Aig_ManStop(pTemp);
if (fVerbose) printf("Refactor: "), Aig_ManPrintStats(pAig);
// rs -K 8 -l;
pNtkAig = Abc_NtkFromDar(pNtk, pAig);
pParsRes->nCutsMax = 8;
pParsRes->fUpdateLevel = 0;
pParsRes->nNodesMax = 1;
Abc_NtkResubstitute(pNtkAig, pParsRes->nCutsMax, pParsRes->nNodesMax,
nMinSaved, pParsRes->nLevelsOdc, fUpdateLevel, fVerbose,
pParsRes->fVeryVerbose);
pAig = Abc_NtkToDar(pNtkAig, 0, 0);
if (fVerbose) printf("Resub: "), Aig_ManPrintStats(pAig);
// b -l;
fUpdateLevel = 0;
pAig = Dar_ManBalance(pTemp = pAig, fUpdateLevel);
Aig_ManStop(pTemp);
if (fVerbose) printf("Balance: "), Aig_ManPrintStats(pAig);
// rs -K 8 -N 2 -l;
pNtkAig = Abc_NtkFromDar(pNtk, pAig);
pParsRes->nCutsMax = 8;
pParsRes->fUpdateLevel = 0;
pParsRes->nNodesMax = 2;
Abc_NtkResubstitute(pNtkAig, pParsRes->nCutsMax, pParsRes->nNodesMax,
nMinSaved, pParsRes->nLevelsOdc, fUpdateLevel, fVerbose,
pParsRes->fVeryVerbose);
pAig = Abc_NtkToDar(pNtkAig, 0, 0);
if (fVerbose) printf("Resub: "), Aig_ManPrintStats(pAig);
// rw -l;
pParsRwr->fUpdateLevel = 0;
Dar_ManRewrite(pAig, pParsRwr);
pAig = Aig_ManDupDfs(pTemp = pAig);
Aig_ManStop(pTemp);
if (fVerbose) printf("Rewrite: "), Aig_ManPrintStats(pAig);
// rs -K 10 -l;
pNtkAig = Abc_NtkFromDar(pNtk, pAig);
pParsRes->nCutsMax = 10;
pParsRes->fUpdateLevel = 0;
pParsRes->nNodesMax = 1;
Abc_NtkResubstitute(pNtkAig, pParsRes->nCutsMax, pParsRes->nNodesMax,
nMinSaved, pParsRes->nLevelsOdc, fUpdateLevel, fVerbose,
pParsRes->fVeryVerbose);
pAig = Abc_NtkToDar(pNtkAig, 0, 0);
if (fVerbose) printf("Resub: "), Aig_ManPrintStats(pAig);
// rwz -l;
pParsRwr->fUpdateLevel = 0;
pParsRwr->fUseZeros = 1;
Dar_ManRewrite(pAig, pParsRwr);
pAig = Aig_ManDupDfs(pTemp = pAig);
Aig_ManStop(pTemp);
if (fVerbose) printf("Rewrite_zerocost: "), Aig_ManPrintStats(pAig);
// rs -K 10 -N 2 -l;
pNtkAig = Abc_NtkFromDar(pNtk, pAig);
pParsRes->nCutsMax = 10;
pParsRes->fUpdateLevel = 0;
pParsRes->nNodesMax = 2;
Abc_NtkResubstitute(pNtkAig, pParsRes->nCutsMax, pParsRes->nNodesMax,
nMinSaved, pParsRes->nLevelsOdc, fUpdateLevel, fVerbose,
pParsRes->fVeryVerbose);
pAig = Abc_NtkToDar(pNtkAig, 0, 0);
if (fVerbose) printf("Resub: "), Aig_ManPrintStats(pAig);
// b -l;
fUpdateLevel = 0;
pAig = Dar_ManBalance(pTemp = pAig, fUpdateLevel);
Aig_ManStop(pTemp);
if (fVerbose) printf("Balance: "), Aig_ManPrintStats(pAig);
// rs -K 12 -l;
pNtkAig = Abc_NtkFromDar(pNtk, pAig);
pParsRes->nCutsMax = 12;
pParsRes->fUpdateLevel = 0;
pParsRes->nNodesMax = 1;
Abc_NtkResubstitute(pNtkAig, pParsRes->nCutsMax, pParsRes->nNodesMax,
nMinSaved, pParsRes->nLevelsOdc, fUpdateLevel, fVerbose,
pParsRes->fVeryVerbose);
pAig = Abc_NtkToDar(pNtkAig, 0, 0);
if (fVerbose) printf("Resub: "), Aig_ManPrintStats(pAig);
// rfz -l;
pParsRef->fUpdateLevel = 0;
pParsRef->fUseZeros = 1;
Dar_ManRefactor(pAig, pParsRef);
pAig = Aig_ManDupDfs(pTemp = pAig);
Aig_ManStop(pTemp);
if (fVerbose) printf("Refactor_zerocost: "), Aig_ManPrintStats(pAig);
// rs -K 12 -N 2 -l;
pNtkAig = Abc_NtkFromDar(pNtk, pAig);
pParsRes->nCutsMax = 12;
pParsRes->fUpdateLevel = 0;
pParsRes->nNodesMax = 2;
Abc_NtkResubstitute(pNtkAig, pParsRes->nCutsMax, pParsRes->nNodesMax,
nMinSaved, pParsRes->nLevelsOdc, fUpdateLevel, fVerbose,
pParsRes->fVeryVerbose);
pAig = Abc_NtkToDar(pNtkAig, 0, 0);
if (fVerbose) printf("Resub: "), Aig_ManPrintStats(pAig);
// rwz -l;
pParsRwr->fUpdateLevel = 0;
pParsRwr->fUseZeros = 1;
Dar_ManRewrite(pAig, pParsRwr);
pAig = Aig_ManDupDfs(pTemp = pAig);
Aig_ManStop(pTemp);
if (fVerbose) printf("Rewrite_zerocost: "), Aig_ManPrintStats(pAig);
// b -l;
fUpdateLevel = 0;
pAig = Dar_ManBalance(pTemp = pAig, fUpdateLevel);
Aig_ManStop(pTemp);
if (fVerbose) printf("Balance: "), Aig_ManPrintStats(pAig);
return pAig;
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
begin = clock();
if (store<pabc::Abc_Ntk_t *>().size() == 0u)
std::cerr << "Error: Empty AIG network.\n";
else {
Abc_Ntk_t *pNtk, *pNtkAig;
pNtk = store<pabc::Abc_Ntk_t *>().current();
int fVerbose;
int fUpdateLevel;
int fFanout;
int fPower;
int c;
int fBalance;
int nMinSaved;
// set defaults
fVerbose = 0;
fUpdateLevel = 0;
fFanout = 1;
fPower = 0;
fBalance = 0;
nMinSaved = 1;
Extra_UtilGetoptReset();
if (is_set("verbose")) {
fVerbose = 1;
}
if (pNtk == NULL) {
Abc_Print(-1, "Empty network.\n");
return;
}
if (!Abc_NtkIsStrash(pNtk)) {
Abc_Print(-1, "This command works only for strashed networks.\n");
return;
}
Aig_Man_t *pMan, *pTemp;
abctime clk;
assert(Abc_NtkIsStrash(pNtk));
pMan = Abc_NtkToDar(pNtk, 0, 0);
if (pMan == NULL) return;
clk = Abc_Clock();
pMan = Dar_ManCompress2rs(pNtk, pTemp = pMan, fBalance, fUpdateLevel,
fFanout, fPower, fVerbose, nMinSaved);
Aig_ManStop(pTemp);
pNtkAig = Abc_NtkFromDar(pNtk, pMan);
Aig_ManStop(pMan);
if (pNtkAig == NULL) {
Abc_Print(-1, "Command has failed.\n");
return;
}
store<pabc::Abc_Ntk_t *>().extend();
store<pabc::Abc_Ntk_t *>().current() = pNtkAig;
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
};
ALICE_ADD_COMMAND(compress2rs, "ABC")
} // namespace alice
#endif

View File

@ -1,86 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file dc2.hpp
*
* @brief combination optimization script
*
* @author Homyoung
* @since 2023/11/16
*/
#ifndef DC2_HPP
#define DC2_HPP
// #include "base/abci/abc.c"
#include "base/abc/abc.h"
// #include "base/abci/abcDar.c"
using namespace std;
using namespace mockturtle;
using namespace pabc;
namespace alice {
class dc2_command : public command {
public:
explicit dc2_command(const environment::ptr &env)
: command(env, "usage: dc2 [-blfpvh]") {
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
begin = clock();
if (store<pabc::Abc_Ntk_t *>().size() == 0u)
std::cerr << "Error: Empty AIG network.\n";
else {
Abc_Ntk_t *pNtk, *pNtkRes;
int fBalance, fVerbose, fUpdateLevel, fFanout, fPower, c;
pNtk = store<pabc::Abc_Ntk_t *>().current();
// set defaults
fBalance = 0;
fVerbose = 0;
fUpdateLevel = 0;
fFanout = 1;
fPower = 0;
Extra_UtilGetoptReset();
if (pNtk == NULL) {
Abc_Print(-1, "Empty network.\n");
return;
}
if (!Abc_NtkIsStrash(pNtk)) {
Abc_Print(-1, "This command works only for strashed networks.\n");
return;
}
pNtkRes =
Abc_NtkDC2(pNtk, fBalance, fUpdateLevel, fFanout, fPower, fVerbose);
if (pNtkRes == NULL) {
Abc_Print(-1, "Command has failed.\n");
return;
}
// replace the current network
// Abc_FrameReplaceCurrentNetwork(pAbc, pNtkRes);
store<pabc::Abc_Ntk_t *>().extend();
store<pabc::Abc_Ntk_t *>().current() = pNtkRes;
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
};
ALICE_ADD_COMMAND(dc2, "ABC")
} // namespace alice
#endif

View File

@ -1,97 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file fraig.hpp
*
* @brief transforms a logic network into a functionally reduced AIG
*
* @author Homyoung
* @since 2023/03/14
*/
#ifndef FRAIG_HPP
#define FRAIG_HPP
#include "base/abc/abc.h"
#include "proof/fraig/fraig.h"
using namespace std;
using namespace mockturtle;
namespace alice {
class fraig_command : public command {
public:
explicit fraig_command(const environment::ptr &env)
: command(env,
"transforms a logic network into a functionally reduced AIG") {
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
begin = clock();
if (store<pabc::Abc_Ntk_t *>().size() == 0u)
std::cerr << "Error: Empty ABC AIG network.\n";
else {
pabc::Abc_Ntk_t *pNtk, *pNtkRes;
pNtk = store<pabc::Abc_Ntk_t *>().current();
if (!pabc::Abc_NtkIsLogic(pNtk) && !pabc::Abc_NtkIsStrash(pNtk))
std::cerr << "Can only fraig a logic network or an AIG.\n";
pabc::Fraig_Params_t Params, *pParams = &Params;
// set defaults
int fAllNodes = 0, fExdc = 0;
memset(pParams, 0, sizeof(pabc::Fraig_Params_t));
pParams->nPatsRand =
2048; // the number of words of random simulation info
pParams->nPatsDyna =
2048; // the number of words of dynamic simulation info
pParams->nBTLimit = 100; // the max number of backtracks to perform
pParams->fFuncRed = 1; // performs only one level hashing
pParams->fFeedBack = 1; // enables solver feedback
pParams->fDist1Pats = 1; // enables distance-1 patterns
pParams->fDoSparse = 1; // performs equiv tests for sparse functions
pParams->fChoicing = 0; // enables recording structural choices
pParams->fTryProve = 0; // tries to solve the final miter
pParams->fVerbose = 0; // the verbosiness flag
pParams->fVerboseP = 0; // the verbosiness flag
if (is_set("verbose")) pParams->fVerbose ^= 1;
if (pabc::Abc_NtkIsStrash(pNtk))
pNtkRes = pabc::Abc_NtkFraig(pNtk, &Params, fAllNodes, fExdc);
else {
pNtk = pabc::Abc_NtkStrash(pNtk, fAllNodes, !fAllNodes, 0);
pNtkRes = pabc::Abc_NtkFraig(pNtk, &Params, fAllNodes, fExdc);
pabc::Abc_NtkDelete(pNtk);
}
if (pNtkRes == NULL) std::cerr << "Fraiging has failed.\n";
store<pabc::Abc_Ntk_t *>().extend();
store<pabc::Abc_Ntk_t *>().current() = pNtkRes;
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
};
ALICE_ADD_COMMAND(fraig, "ABC")
} // namespace alice
#endif

View File

@ -1,115 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file if.hpp
*
* @brief performs FPGA technology mapping of the network
*
* @author Homyoung
* @since 2023/08/03
*/
#ifndef ABC_IF_HPP
#define ABC_IF_HPP
#include "base/abc/abc.h"
#include "base/abci/abcIf.c"
#include "base/main/main.h"
#include "map/if/if.h"
using namespace mockturtle;
using namespace std;
using namespace pabc;
namespace alice {
class if_command : public command {
public:
explicit if_command(const environment::ptr &env)
: command(env, "performs FPGA mapping of the AIG") {
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
begin = clock();
if (store<pabc::Abc_Ntk_t *>().size() == 0u)
std::cerr << "Error: Empty ABC AIG network\n";
else {
Abc_Ntk_t *pNtk = store<pabc::Abc_Ntk_t *>().current();
// set defaults
Abc_Ntk_t *pNtkRes;
If_Par_t Pars, *pPars = &Pars;
If_ManSetDefaultPars(pPars);
pPars->pLutLib = (If_LibLut_t *)Abc_FrameReadLibLut();
if (pPars->nLutSize == -1) {
if (pPars->pLutLib == NULL) {
printf("The LUT library is not given.\n");
return;
}
pPars->nLutSize = pPars->pLutLib->LutMax;
}
if (pPars->nLutSize < 2 || pPars->nLutSize > IF_MAX_LUTSIZE) {
printf("Incorrect LUT size (%d).\n", pPars->nLutSize);
return;
}
if (pPars->nCutsMax < 1 || pPars->nCutsMax >= (1 << 12)) {
printf("Incorrect number of cuts.\n");
return;
}
if (!Abc_NtkIsStrash(pNtk)) {
// strash and balance the network
pNtk = Abc_NtkStrash(pNtk, 0, 0, 0);
if (pNtk == NULL) {
printf("Strashing before FPGA mapping has failed.\n");
return;
}
pNtk = Abc_NtkBalance(pNtkRes = pNtk, 0, 0, 1);
Abc_NtkDelete(pNtkRes);
if (pNtk == NULL) {
printf("Balancing before FPGA mapping has failed.\n");
return;
}
if (!Abc_FrameReadFlag("silentmode"))
printf(
"The network was strashed and balanced before FPGA mapping.\n");
// get the new network
pNtkRes = Abc_NtkIf(pNtk, pPars);
if (pNtkRes == NULL) {
Abc_NtkDelete(pNtk);
printf("FPGA mapping has failed.\n");
return;
}
Abc_NtkDelete(pNtk);
} else {
// get the new network
pNtkRes = Abc_NtkIf(pNtk, pPars);
if (pNtkRes == NULL) {
printf("FPGA mapping has failed.\n");
return;
}
}
store<pabc::Abc_Ntk_t *>().extend();
store<pabc::Abc_Ntk_t *>().current() = pNtkRes;
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
};
ALICE_ADD_COMMAND(if, "ABC")
} // namespace alice
#endif

View File

@ -1,95 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file map.hpp
*
* @brief performs technology-independent mapping of the AIG
*
* @author Homyoung
* @since 2023/11/16
*/
#ifndef ABC_MAP_HPP
#define ABC_MAP_HPP
#include "base/abc/abc.h"
#include "base/abci/abcMap.c"
using namespace mockturtle;
using namespace std;
namespace alice {
class map_command : public command {
public:
explicit map_command(const environment::ptr &env)
: command(env, "performs standard cell mapping of the current network") {
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
begin = clock();
pabc::Abc_Ntk_t *pNtkRes;
double DelayTarget;
double AreaMulti;
double DelayMulti;
float LogFan = 0;
float Slew = 0; // choose based on the library
float Gain = 250;
int nGatesMin = 0;
int fAreaOnly;
int fRecovery;
int fSweep;
int fSwitching;
int fSkipFanout;
int fUseProfile;
int fUseBuffs;
int fVerbose;
if (store<pabc::Abc_Ntk_t *>().size() == 0u)
std::cerr << "Error: Empty ABC AIG network\n";
else {
pabc::Abc_Ntk_t *pNtk = store<pabc::Abc_Ntk_t *>().current();
// set defaults
DelayTarget = -1;
AreaMulti = 0;
DelayMulti = 0;
fAreaOnly = 0;
fRecovery = 1;
fSweep = 0;
fSwitching = 0;
fSkipFanout = 0;
fUseProfile = 0;
fUseBuffs = 0;
fVerbose = 0;
if (is_set("verbose")) fVerbose ^= 1;
pNtkRes = Abc_NtkMap(pNtk, DelayTarget, AreaMulti, DelayMulti, LogFan,
Slew, Gain, nGatesMin, fRecovery, fSwitching,
fSkipFanout, fUseProfile, fUseBuffs, fVerbose);
store<pabc::Abc_Ntk_t *>().extend();
store<pabc::Abc_Ntk_t *>().current() = pNtkRes;
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
};
ALICE_ADD_COMMAND(map, "ABC")
} // namespace alice
#endif

View File

@ -1,163 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file put.hpp
*
* @brief converts the current GIA network into Ntk
*
* @author Homyoung
* @since 2023/11/16
*/
#ifndef ABC_PUT_HPP
#define ABC_PUT_HPP
#include "base/abc/abc.h"
// #include "base/abci/abcDar.c"
// #include "aig/gia/gia.h"
#include "aig/gia/giaAig.h"
using namespace std;
using namespace mockturtle;
using namespace pabc;
namespace alice {
class put_command : public command {
public:
explicit put_command(const environment::ptr &env)
: command(env, "converts the current network into AIG") {}
protected:
void execute() {
clock_t begin, end;
double totalTime;
begin = clock();
Aig_Man_t *pMan;
Abc_Ntk_t *pNtk;
if (store<pabc::Abc_Ntk_t *>().size() == 0u)
std::cerr << "Error: Empty ABC AIG network\n";
else
pNtk = store<pabc::Abc_Ntk_t *>().current();
if (store<pabc::Gia_Man_t *>().size() == 0u)
std::cerr << "Error: Empty ABC GIA network\n";
else {
Gia_Man_t *pGia = store<pabc::Gia_Man_t *>().current();
int fStatusClear = 1;
int fUseBuffs = 0;
int fFindEnables = 0;
int fVerbose = 0;
if (fFindEnables)
pNtk = Abc_NtkFromMappedGia(pGia, 1, fUseBuffs);
else if (Gia_ManHasCellMapping(pGia))
pNtk = Abc_NtkFromCellMappedGia(pGia, fUseBuffs);
else if (Gia_ManHasMapping(pGia) || pGia->pMuxes)
pNtk = Abc_NtkFromMappedGia(pGia, 0, fUseBuffs);
else if (Gia_ManHasDangling(pGia) == 0) {
pMan = Gia_ManToAig(pGia, 0);
pNtk = Abc_NtkFromAigPhase(pMan);
pNtk->pName = Extra_UtilStrsav(pMan->pName);
Aig_ManStop(pMan);
} else {
Abc_Ntk_t *pNtkNoCh;
Abc_Print(-1, "Transforming AIG with %d choice nodes.\n",
Gia_ManEquivCountClasses(pGia));
// create network without choices
pMan = Gia_ManToAig(pGia, 0);
pNtkNoCh = Abc_NtkFromAigPhase(pMan);
pNtkNoCh->pName = Extra_UtilStrsav(pMan->pName);
Aig_ManStop(pMan);
// derive network with choices
pMan = Gia_ManToAig(pGia, 1);
pNtk = Abc_NtkFromDarChoices(pNtkNoCh, pMan);
Abc_NtkDelete(pNtkNoCh);
Aig_ManStop(pMan);
}
// transfer PI names to pNtk
// if ( pGia->vNamesIn )
// {
// Abc_Obj_t * pObj;
// int i;
// Abc_NtkForEachCi( pNtk, pObj, i ) {
// if (i < Vec_PtrSize(pGia->vNamesIn)) {
// Nm_ManDeleteIdName(pNtk->pManName, pObj->Id);
// Abc_ObjAssignName( pObj, (char
// *)Vec_PtrEntry(pGia->vNamesIn, i), NULL );
// }
// }
// }
// transfer PO names to pNtk
// if ( pGia->vNamesOut )
// {
// char pSuffix[100];
// Abc_Obj_t * pObj;
// int i, nDigits = Abc_Base10Log( Abc_NtkLatchNum(pNtk) );
// Abc_NtkForEachCo( pNtk, pObj, i ) {
// if (i < Vec_PtrSize(pGia->vNamesOut)) {
// Nm_ManDeleteIdName(pNtk->pManName, pObj->Id);
// if ( Abc_ObjIsPo(pObj) )
// Abc_ObjAssignName( pObj, (char
// *)Vec_PtrEntry(pGia->vNamesOut, i), NULL );
// else
// {
// assert( i >= Abc_NtkPoNum(pNtk) );
// sprintf( pSuffix, "_li%0*d", nDigits,
// i-Abc_NtkPoNum(pNtk) ); Abc_ObjAssignName( pObj, (char
// *)Vec_PtrEntry(pGia->vNamesOut, i), pSuffix );
// }
// }
// }
// }
// if ( pGia->vNamesNode )
// Abc_Print( 0, "Internal nodes names are not transferred.\n" );
// // decouple CI/CO with the same name
// if ( pGia->vNamesIn || pGia->vNamesOut )
// Abc_NtkRedirectCiCo( pNtk );
// // transfer timing information
// if ( pGia->vInArrs || pGia->vOutReqs )
// {
// Abc_Obj_t * pObj; int i;
// Abc_NtkTimeInitialize( pNtk, NULL );
// Abc_NtkTimeSetDefaultArrival( pNtk, pGia->DefInArrs,
// pGia->DefInArrs ); Abc_NtkTimeSetDefaultRequired( pNtk,
// pGia->DefOutReqs, pGia->DefOutReqs ); if ( pGia->vInArrs )
// Abc_NtkForEachCi( pNtk, pObj, i )
// Abc_NtkTimeSetArrival( pNtk, Abc_ObjId(pObj),
// Vec_FltEntry(pGia->vInArrs, i), Vec_FltEntry(pGia->vInArrs,
// i) );
// if ( pGia->vOutReqs )
// Abc_NtkForEachCo( pNtk, pObj, i )
// Abc_NtkTimeSetRequired( pNtk, Abc_ObjId(pObj),
// Vec_FltEntry(pGia->vOutReqs, i),
// Vec_FltEntry(pGia->vOutReqs, i) );
// }
// replace the current network
// Abc_FrameReplaceCurrentNetwork( pAbc, pNtk );
// if ( fStatusClear )
// Abc_FrameClearVerifStatus( pAbc );
store<pabc::Abc_Ntk_t *>().extend();
store<pabc::Abc_Ntk_t *>().current() = pNtk;
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
}
private:
};
ALICE_ADD_COMMAND(put, "ABC")
} // namespace alice
#endif

View File

@ -1,64 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file read.hpp
*
* @brief replaces the current network by the network read from file
*
* @author Homyoung
* @since 2023/03/14
*/
#ifndef READ_HPP
#define READ_HPP
#include "base/abc/abc.h"
using namespace std;
using namespace mockturtle;
namespace alice {
class read_command : public command {
public:
explicit read_command(const environment::ptr &env)
: command(env,
"replaces the current network by the network read from file by "
"ABC parser") {
add_option("filename,-f", file_name, "name of input file");
add_flag("--check, -c", "Disable network check after reading");
add_flag("--buffer, -b", "Reading barrier buffers");
}
protected:
void execute() override {
int fCheck = 1, fBarBufs = 0;
if (is_set("check")) fCheck ^= 1;
if (is_set("buffer")) fBarBufs ^= 1;
// fix the wrong symbol
for (auto &x : file_name) {
if (x == '>' || x == '\\') x = '/';
}
assert(strlen((char *)(file_name.c_str())) < 900);
pabc::Abc_Ntk_t *pNtk = pabc::Io_Read(
(char *)(file_name.c_str()),
pabc::Io_ReadFileType((char *)(file_name.c_str())), fCheck, fBarBufs);
if (pNtk == NULL) std::cerr << "Error: Empty input format.\n";
store<pabc::Abc_Ntk_t *>().extend();
store<pabc::Abc_Ntk_t *>().current() = pNtk;
}
private:
std::string file_name;
};
ALICE_ADD_COMMAND(read, "I/O")
} // namespace alice
#endif

View File

@ -1,108 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file read_genlib.hpp
*
* @brief read the library from a genlib file
*
* @author Homyoung
* @since 2023/11/16
*/
#ifndef ABC_READ_GENLIB_HPP
#define ABC_READ_GENLIB_HPP
#include "base/abc/abc.h"
#include "base/io/ioAbc.h"
#include "base/main/abcapis.h"
#include "base/main/main.h"
#include "map/amap/amap.h"
#include "map/mapper/mapper.h"
#include "map/mio/mio.h"
#include "misc/extra/extra.h"
using namespace std;
using namespace mockturtle;
namespace alice {
class read_agenlib_command : public command {
public:
explicit read_agenlib_command(const environment::ptr &env)
: command(env, "read the library from a genlib file") {
add_option("filename,-f", file_name, "name of input file");
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
begin = clock();
pabc::Abc_Frame_t *pAbc;
pAbc = pabc::Abc_FrameGetGlobalFrame();
// set defaults
FILE *pFile;
// FILE * pOut, * pErr;
pabc::Mio_Library_t *pLib;
pabc::Amap_Lib_t *pLib2;
char *pFileName;
char *pExcludeFile = NULL;
int fVerbose = 1;
// get the input file name
pFileName = (char *)malloc(file_name.length() + 1);
if (pFileName != NULL) {
strcpy(pFileName, file_name.c_str());
} else {
printf("Memory allocation failed\n");
}
// if ( (pFile = pabc::Io_FileOpen( pFileName, "open_path", "r", 0 )) ==
// NULL )
// {
// printf("Cannot open input file \"%s\". ", pFileName );
// if ( (pFileName = pabc::Extra_FileGetSimilarName( pFileName,
// ".genlib", ".lib", ".scl", ".g", NULL )) )
// printf( "Did you mean \"%s\"?", pFileName );
// printf( "\n" );
// return;
// }
// fclose( pFile );
// set the new network
pLib = pabc::Mio_LibraryRead(pFileName, NULL, pExcludeFile, fVerbose);
if (pLib == NULL) {
// fprintf( pErr, "Reading genlib library has failed.\n" );
printf("Reading genlib library has failed.\n");
return;
}
if (fVerbose)
printf("Entered genlib library with %d gates from file \"%s\".\n",
Mio_LibraryReadGateNum(pLib), pFileName);
// prepare libraries
pabc::Mio_UpdateGenlib(pLib);
// replace the current library
pLib2 = pabc::Amap_LibReadAndPrepare(pFileName, NULL, 0, 0);
if (pLib2 == NULL) {
// fprintf( pErr, "Reading second genlib library has failed.\n" );
printf("Reading second genlib library has failed.\n");
return;
}
Abc_FrameSetLibGen2(pLib2);
}
private:
std::string file_name;
};
ALICE_ADD_COMMAND(read_agenlib, "I/O")
} // namespace alice
#endif

View File

@ -1,124 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file refactor.hpp
*
* @brief performs technology-independent refactoring of the AIG
*
* @author Homyoung
* @since 2023/11/16
*/
#ifndef ABC_REFACTOR_HPP
#define ABC_REFACTOR_HPP
#include "base/abc/abc.h"
#include "base/abci/abc.c"
#include "base/abci/abcRefactor.c"
using namespace std;
using namespace mockturtle;
using namespace pabc;
namespace alice {
class arefactor_command : public command {
public:
explicit arefactor_command(const environment::ptr &env)
: command(env, "performs technology-independent refactoring of the AIG") {
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
begin = clock();
if (store<pabc::Abc_Ntk_t *>().size() == 0u)
std::cerr << "Error: Empty AIG network.\n";
else {
pabc::Abc_Ntk_t *pNtk, *pDup;
pNtk = store<pabc::Abc_Ntk_t *>().current();
int c, RetValue;
int nNodeSizeMax;
int nConeSizeMax;
int fUpdateLevel;
int fUseZeros;
int fUseDcs;
int fVerbose;
int nMinSaved;
// set defaults
nNodeSizeMax = 10;
nConeSizeMax = 16;
fUpdateLevel = 1;
fUseZeros = 0;
fUseDcs = 0;
fVerbose = 0;
nMinSaved = 1;
Extra_UtilGetoptReset();
if (pNtk == NULL) {
Abc_Print(-1, "Empty network.\n");
return;
}
if (!Abc_NtkIsStrash(pNtk)) {
Abc_Print(
-1,
"This command can only be applied to an AIG (run \"strash\").\n");
return;
}
if (Abc_NtkGetChoiceNum(pNtk)) {
Abc_Print(
-1,
"AIG resynthesis cannot be applied to AIGs with choice nodes.\n");
return;
}
if (nNodeSizeMax > 15) {
Abc_Print(-1, "The cone size cannot exceed 15.\n");
return;
}
if (fUseDcs && nNodeSizeMax >= nConeSizeMax) {
Abc_Print(-1,
"For don't-care to work, containing cone should be larger "
"than collapsed node.\n");
return;
}
// modify the current network
pDup = Abc_NtkDup(pNtk);
RetValue = Abc_NtkRefactor(pNtk, nNodeSizeMax, nMinSaved, nConeSizeMax,
fUpdateLevel, fUseZeros, fUseDcs, fVerbose);
if (RetValue == -1) {
// Abc_FrameReplaceCurrentNetwork(pAbc, pDup);
printf(
"An error occurred during computation. The original network is "
"restored.\n");
} else {
Abc_NtkDelete(pDup);
if (RetValue == 0) {
Abc_Print(0, "Refactoring has failed.\n");
return;
}
}
store<pabc::Abc_Ntk_t *>().extend();
store<pabc::Abc_Ntk_t *>().current() = pNtk;
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
};
ALICE_ADD_COMMAND(arefactor, "ABC")
} // namespace alice
#endif

View File

@ -1,67 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file resub.hpp
*
* @brief performs technology-independent restructuring of the AIG
*
* @author Homyoung
* @since 2023/02/28
*/
#ifndef ABC_RESUB_HPP
#define ABC_RESUB_HPP
#include "base/abci/abcRestruct.c"
using namespace std;
using namespace mockturtle;
namespace alice {
class aresub_command : public command {
public:
explicit aresub_command(const environment::ptr &env)
: command(env,
"performs technology-independent restructuring of the AIG") {
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
begin = clock();
if (store<pabc::Abc_Ntk_t *>().size() == 0u)
std::cerr << "Error: Empty ABC AIG network\n";
else {
pabc::Abc_Ntk_t *pNtk = store<pabc::Abc_Ntk_t *>().current();
// set defaults
int nCutsMax = 5, fUpdateLevel = 0, fUseZeros = 0, fVerbose = 0;
if (is_set("verbose")) fVerbose ^= 1;
Abc_NtkRestructure(pNtk, nCutsMax, fUpdateLevel, fUseZeros, fVerbose);
store<pabc::Abc_Ntk_t *>().extend();
store<pabc::Abc_Ntk_t *>().current() = pNtk;
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
};
ALICE_ADD_COMMAND(aresub, "ABC")
} // namespace alice
#endif

View File

@ -1,291 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file resyn2rs.hpp
*
* @brief combination optimization script
*
* @author Homyoung
* @since 2023/11/16
*/
#ifndef RESYN2RS_HPP
#define RESYN2RS_HPP
// #include "base/abci/abc.c"
#include "base/abc/abc.h"
// #include "base/abci/abcDar.c"
// #include "base/abci/abcResub.c"
using namespace std;
using namespace mockturtle;
using namespace pabc;
namespace alice {
class resyn2rs_command : public command {
public:
explicit resyn2rs_command(const environment::ptr &env)
: command(env, "combination optimization script") {
add_flag("--verbose, -v", "print the information");
}
public:
void Dar_ManDefaultResParams(Dar_ResPar_t *pPars) {
memset(pPars, 0, sizeof(Dar_ResPar_t));
pPars->nCutsMax = 8; // 8
pPars->nNodesMax = 1;
pPars->nLevelsOdc = 0;
pPars->fUpdateLevel = 1;
pPars->fUseZeros = 0;
pPars->fVerbose = 0;
pPars->fVeryVerbose = 0;
}
Aig_Man_t *Dar_ManResyn2rs(Abc_Ntk_t *pNtk, Aig_Man_t *pAig, int fBalance,
int fUpdateLevel, int fFanout, int fPower,
int fVerbose, int nMinSaved) {
// alias resyn2rs "b; rs -K 6; rw; rs -K 6 -N 2; rf; rs -K 8; b; rs -K
// 8 -N 2; rw; rs -K 10; rwz; rs -K 10 -N 2; b; rs -K 12; rfz; rs -K 12
// -N 2; rwz; b"
Aig_Man_t *pTemp;
Abc_Ntk_t *pNtkAig;
Dar_RwrPar_t ParsRwr, *pParsRwr = &ParsRwr;
Dar_RefPar_t ParsRef, *pParsRef = &ParsRef;
Dar_ResPar_t ParsRes, *pParsRes = &ParsRes;
Dar_ManDefaultRwrParams(pParsRwr);
Dar_ManDefaultRefParams(pParsRef);
Dar_ManDefaultResParams(pParsRes);
pParsRwr->fUpdateLevel = fUpdateLevel;
pParsRef->fUpdateLevel = fUpdateLevel;
pParsRes->fUpdateLevel = fUpdateLevel;
// pParsRes->nCutsMax = nCutsMax;
// pParsRes->nNodesMax = nNodesMax;
pParsRwr->fFanout = fFanout;
pParsRwr->fPower = fPower;
pParsRwr->fVerbose = 0; // fVerbose;
pParsRef->fVerbose = 0; // fVerbose;
pParsRes->fVerbose = 0; // fVerbose;
pAig = Aig_ManDupDfs(pAig);
if (fVerbose) printf("Starting: "), Aig_ManPrintStats(pAig);
// b;
fUpdateLevel = 1;
pAig = Dar_ManBalance(pTemp = pAig, fUpdateLevel);
Aig_ManStop(pTemp);
if (fVerbose) printf("Balance: "), Aig_ManPrintStats(pAig);
// rs -K 6;
pNtkAig = Abc_NtkFromDar(pNtk, pAig);
pParsRes->nCutsMax = 6;
pParsRes->fUpdateLevel = 1;
pParsRes->nNodesMax = 1;
Abc_NtkResubstitute(pNtkAig, pParsRes->nCutsMax, pParsRes->nNodesMax,
nMinSaved, pParsRes->nLevelsOdc, fUpdateLevel, fVerbose,
pParsRes->fVeryVerbose);
pAig = Abc_NtkToDar(pNtkAig, 0, 0);
if (fVerbose) printf("Resub: "), Aig_ManPrintStats(pAig);
// rw;
pParsRwr->fUpdateLevel = 1;
Dar_ManRewrite(pAig, pParsRwr);
pAig = Aig_ManDupDfs(pTemp = pAig);
Aig_ManStop(pTemp);
if (fVerbose) printf("Rewrite: "), Aig_ManPrintStats(pAig);
// rs -K 6 -N 2;
pNtkAig = Abc_NtkFromDar(pNtk, pAig);
pParsRes->nCutsMax = 6;
pParsRes->fUpdateLevel = 1;
pParsRes->nNodesMax = 2;
Abc_NtkResubstitute(pNtkAig, pParsRes->nCutsMax, pParsRes->nNodesMax,
nMinSaved, pParsRes->nLevelsOdc, fUpdateLevel, fVerbose,
pParsRes->fVeryVerbose);
pAig = Abc_NtkToDar(pNtkAig, 0, 0);
if (fVerbose) printf("Resub: "), Aig_ManPrintStats(pAig);
// rf;
pParsRef->fUpdateLevel = 1;
Dar_ManRefactor(pAig, pParsRef);
pAig = Aig_ManDupDfs(pTemp = pAig);
Aig_ManStop(pTemp);
if (fVerbose) printf("Refactor: "), Aig_ManPrintStats(pAig);
// rs -K 8;
pNtkAig = Abc_NtkFromDar(pNtk, pAig);
pParsRes->nCutsMax = 8;
pParsRes->fUpdateLevel = 1;
pParsRes->nNodesMax = 1;
Abc_NtkResubstitute(pNtkAig, pParsRes->nCutsMax, pParsRes->nNodesMax,
nMinSaved, pParsRes->nLevelsOdc, fUpdateLevel, fVerbose,
pParsRes->fVeryVerbose);
pAig = Abc_NtkToDar(pNtkAig, 0, 0);
if (fVerbose) printf("Resub: "), Aig_ManPrintStats(pAig);
// b;
fUpdateLevel = 1;
pAig = Dar_ManBalance(pTemp = pAig, fUpdateLevel);
Aig_ManStop(pTemp);
if (fVerbose) printf("Balance: "), Aig_ManPrintStats(pAig);
// rs -K 8 -N 2;
pNtkAig = Abc_NtkFromDar(pNtk, pAig);
pParsRes->nCutsMax = 8;
pParsRes->fUpdateLevel = 1;
pParsRes->nNodesMax = 2;
Abc_NtkResubstitute(pNtkAig, pParsRes->nCutsMax, pParsRes->nNodesMax,
nMinSaved, pParsRes->nLevelsOdc, fUpdateLevel, fVerbose,
pParsRes->fVeryVerbose);
pAig = Abc_NtkToDar(pNtkAig, 0, 0);
if (fVerbose) printf("Resub: "), Aig_ManPrintStats(pAig);
// rw;
pParsRwr->fUpdateLevel = 1;
Dar_ManRewrite(pAig, pParsRwr);
pAig = Aig_ManDupDfs(pTemp = pAig);
Aig_ManStop(pTemp);
if (fVerbose) printf("Rewrite: "), Aig_ManPrintStats(pAig);
// rs -K 10;
pNtkAig = Abc_NtkFromDar(pNtk, pAig);
pParsRes->nCutsMax = 10;
pParsRes->fUpdateLevel = 1;
pParsRes->nNodesMax = 1;
Abc_NtkResubstitute(pNtkAig, pParsRes->nCutsMax, pParsRes->nNodesMax,
nMinSaved, pParsRes->nLevelsOdc, fUpdateLevel, fVerbose,
pParsRes->fVeryVerbose);
pAig = Abc_NtkToDar(pNtkAig, 0, 0);
if (fVerbose) printf("Resub: "), Aig_ManPrintStats(pAig);
// rwz;
pParsRwr->fUpdateLevel = 1;
pParsRwr->fUseZeros = 1;
Dar_ManRewrite(pAig, pParsRwr);
pAig = Aig_ManDupDfs(pTemp = pAig);
Aig_ManStop(pTemp);
if (fVerbose) printf("Rewrite_zerocost: "), Aig_ManPrintStats(pAig);
// rs -K 10 -N 2;
pNtkAig = Abc_NtkFromDar(pNtk, pAig);
pParsRes->nCutsMax = 10;
pParsRes->fUpdateLevel = 1;
pParsRes->nNodesMax = 2;
Abc_NtkResubstitute(pNtkAig, pParsRes->nCutsMax, pParsRes->nNodesMax,
nMinSaved, pParsRes->nLevelsOdc, fUpdateLevel, fVerbose,
pParsRes->fVeryVerbose);
pAig = Abc_NtkToDar(pNtkAig, 0, 0);
if (fVerbose) printf("Resub: "), Aig_ManPrintStats(pAig);
// b;
fUpdateLevel = 1;
pAig = Dar_ManBalance(pTemp = pAig, fUpdateLevel);
Aig_ManStop(pTemp);
if (fVerbose) printf("Balance: "), Aig_ManPrintStats(pAig);
// rs -K 12;
pNtkAig = Abc_NtkFromDar(pNtk, pAig);
pParsRes->nCutsMax = 12;
pParsRes->fUpdateLevel = 1;
pParsRes->nNodesMax = 1;
Abc_NtkResubstitute(pNtkAig, pParsRes->nCutsMax, pParsRes->nNodesMax,
nMinSaved, pParsRes->nLevelsOdc, fUpdateLevel, fVerbose,
pParsRes->fVeryVerbose);
pAig = Abc_NtkToDar(pNtkAig, 0, 0);
if (fVerbose) printf("Resub: "), Aig_ManPrintStats(pAig);
// rfz;
pParsRef->fUpdateLevel = 1;
pParsRef->fUseZeros = 1;
Dar_ManRefactor(pAig, pParsRef);
pAig = Aig_ManDupDfs(pTemp = pAig);
Aig_ManStop(pTemp);
if (fVerbose) printf("Refactor_zerocost: "), Aig_ManPrintStats(pAig);
// rs -K 12 -N 2;
pNtkAig = Abc_NtkFromDar(pNtk, pAig);
pParsRes->nCutsMax = 12;
pParsRes->fUpdateLevel = 1;
pParsRes->nNodesMax = 2;
Abc_NtkResubstitute(pNtkAig, pParsRes->nCutsMax, pParsRes->nNodesMax,
nMinSaved, pParsRes->nLevelsOdc, fUpdateLevel, fVerbose,
pParsRes->fVeryVerbose);
pAig = Abc_NtkToDar(pNtkAig, 0, 0);
if (fVerbose) printf("Resub: "), Aig_ManPrintStats(pAig);
// rwz;
pParsRwr->fUpdateLevel = 1;
pParsRwr->fUseZeros = 1;
Dar_ManRewrite(pAig, pParsRwr);
pAig = Aig_ManDupDfs(pTemp = pAig);
Aig_ManStop(pTemp);
if (fVerbose) printf("Rewrite_zerocost: "), Aig_ManPrintStats(pAig);
// b;
fUpdateLevel = 1;
pAig = Dar_ManBalance(pTemp = pAig, fUpdateLevel);
Aig_ManStop(pTemp);
if (fVerbose) printf("Balance: "), Aig_ManPrintStats(pAig);
return pAig;
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
begin = clock();
if (store<pabc::Abc_Ntk_t *>().size() == 0u)
std::cerr << "Error: Empty AIG network.\n";
else {
Abc_Ntk_t *pNtk, *pNtkAig;
pNtk = store<pabc::Abc_Ntk_t *>().current();
int fVerbose;
int fUpdateLevel;
int fFanout;
int fPower;
int c;
int fBalance;
int nMinSaved;
// set defaults
fVerbose = 0;
fUpdateLevel = 1;
fFanout = 1;
fPower = 0;
fBalance = 0;
nMinSaved = 1;
Extra_UtilGetoptReset();
if (is_set("verbose")) {
fVerbose = 1;
}
if (pNtk == NULL) {
Abc_Print(-1, "Empty network.\n");
return;
}
if (!Abc_NtkIsStrash(pNtk)) {
Abc_Print(-1, "This command works only for strashed networks.\n");
return;
}
Aig_Man_t *pMan, *pTemp;
abctime clk;
assert(Abc_NtkIsStrash(pNtk));
pMan = Abc_NtkToDar(pNtk, 0, 0);
if (pMan == NULL) return;
clk = Abc_Clock();
pMan = Dar_ManResyn2rs(pNtk, pTemp = pMan, fBalance, fUpdateLevel,
fFanout, fPower, fVerbose, nMinSaved);
Aig_ManStop(pTemp);
pNtkAig = Abc_NtkFromDar(pNtk, pMan);
Aig_ManStop(pMan);
if (pNtkAig == NULL) {
Abc_Print(-1, "Command has failed.\n");
return;
}
store<pabc::Abc_Ntk_t *>().extend();
store<pabc::Abc_Ntk_t *>().current() = pNtkAig;
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
};
ALICE_ADD_COMMAND(resyn2rs, "ABC")
} // namespace alice
#endif

View File

@ -1,111 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file rewrite.hpp
*
* @brief performs technology-independent rewriting of the AIG
*
* @author Homyoung
* @since 2023/11/16
*/
#ifndef ABC_REWRITE_HPP
#define ABC_REWRITE_HPP
#include "base/abc/abc.h"
#include "base/abci/abcRewrite.c"
using namespace std;
using namespace mockturtle;
using namespace pabc;
namespace alice {
class arewrite_command : public command {
public:
explicit arewrite_command(const environment::ptr &env)
: command(env, "performs technology-independent rewriting of the AIG") {
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
begin = clock();
if (store<pabc::Abc_Ntk_t *>().size() == 0u)
std::cerr << "Error: Empty AIG network.\n";
else {
Abc_Ntk_t *pNtk, *pDup;
pNtk = store<pabc::Abc_Ntk_t *>().current();
int c, RetValue;
int fUpdateLevel;
int fPrecompute;
int fUseZeros;
int fVerbose;
int fVeryVerbose;
int fPlaceEnable;
// set defaults
fUpdateLevel = 1;
fUseZeros = 0;
fVerbose = 0;
fVeryVerbose = 0;
fPlaceEnable = 0;
Extra_UtilGetoptReset();
if (pNtk == NULL) {
Abc_Print(-1, "Empty network.\n");
return;
}
if (!Abc_NtkIsStrash(pNtk)) {
Abc_Print(
-1,
"This command can only be applied to an AIG (run \"strash\").\n");
return;
}
if (Abc_NtkGetChoiceNum(pNtk)) {
Abc_Print(
-1,
"AIG resynthesis cannot be applied to AIGs with choice nodes.\n");
return;
}
// modify the current network
pDup = Abc_NtkDup(pNtk);
RetValue = Abc_NtkRewrite(pNtk, fUpdateLevel, fUseZeros, fVerbose,
fVeryVerbose, fPlaceEnable);
if (RetValue == -1) {
// Abc_FrameReplaceCurrentNetwork(pAbc, pDup);
printf(
"An error occurred during computation. The original network is "
"restored.\n");
} else {
Abc_NtkDelete(pDup);
if (RetValue == 0) {
Abc_Print(0, "Rewriting has failed.\n");
return;
}
}
store<pabc::Abc_Ntk_t *>().extend();
store<pabc::Abc_Ntk_t *>().current() = pNtk;
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
};
ALICE_ADD_COMMAND(arewrite, "ABC")
} // namespace alice
#endif

View File

@ -1,84 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file sop.hpp
*
* @brief converts node functions to SOP
*
* @author Homyoung
* @since 2023/11/16
*/
#ifndef SOP_HPP
#define SOP_HPP
// #include "base/abci/abc.c"
#include "base/abc/abc.h"
#include "base/abc/abcFunc.c"
using namespace std;
using namespace mockturtle;
using namespace pabc;
namespace alice {
class sop_command : public command {
public:
explicit sop_command(const environment::ptr &env)
: command(env, "converts node functions to SOP") {
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
begin = clock();
if (store<pabc::Abc_Ntk_t *>().size() == 0u)
std::cerr << "Error: Empty AIG network.\n";
else {
Abc_Ntk_t *pNtk;
pNtk = store<pabc::Abc_Ntk_t *>().current();
int c, fCubeSort = 1, fMode = -1, nCubeLimit = 1000000;
// set defaults
Extra_UtilGetoptReset();
if (pNtk == NULL) {
Abc_Print(-1, "Empty network.\n");
return;
}
if (!Abc_NtkIsLogic(pNtk)) {
Abc_Print(-1,
"Converting to SOP is possible only for logic networks.\n");
return;
}
if (!fCubeSort && Abc_NtkHasBdd(pNtk) &&
!Abc_NtkBddToSop(pNtk, -1, ABC_INFINITY, 0)) {
Abc_Print(-1, "Converting to SOP has failed.\n");
return;
}
if (!Abc_NtkToSop(pNtk, fMode, nCubeLimit)) {
Abc_Print(-1, "Converting to SOP has failed.\n");
return;
}
store<pabc::Abc_Ntk_t *>().extend();
store<pabc::Abc_Ntk_t *>().current() = pNtk;
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
};
ALICE_ADD_COMMAND(sop, "ABC")
} // namespace alice
#endif

View File

@ -1,66 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2022 */
/**
* @file strash.hpp
*
* @brief transforms combinational logic into an AIG
*
* @author Homyoung
* @since 2023/03/01
*/
#ifndef STRASH_HPP
#define STRASH_HPP
#include "base/abc/abc.h"
using namespace std;
using namespace mockturtle;
namespace alice {
class strash_command : public command {
public:
explicit strash_command(const environment::ptr &env)
: command(env, "transforms combinational logic into an AIG") {}
protected:
void execute() {
clock_t begin, end;
double totalTime;
begin = clock();
if (store<pabc::Abc_Ntk_t *>().size() == 0u)
std::cerr << "Error: Empty ABC AIG network\n";
else {
pabc::Abc_Ntk_t *pNtk = store<pabc::Abc_Ntk_t *>().current();
// set defaults
int fAllNodes = 0;
int fRecord = 1;
int fCleanup = 0;
pabc::Abc_Ntk_t *pNtkRes;
pNtkRes = Abc_NtkStrash(pNtk, fAllNodes, fCleanup, fRecord);
store<pabc::Abc_Ntk_t *>().extend();
store<pabc::Abc_Ntk_t *>().current() = pNtkRes;
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
};
ALICE_ADD_COMMAND(strash, "ABC")
} // namespace alice
#endif

View File

@ -1,51 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file write.hpp
*
* @brief writes the current network into file
*
* @author Homyoung
* @since 2023/03/14
*/
#ifndef WRITE_HPP
#define WRITE_HPP
#include "base/abc/abc.h"
using namespace std;
using namespace mockturtle;
namespace alice {
class write_command : public command {
public:
explicit write_command(const environment::ptr &env)
: command(env, "writes the current network into file by ABC parser") {
add_option("filename,-f", file_name, "name of output file");
}
protected:
void execute() override {
assert(strlen((char *)(file_name.c_str())) < 900);
if (store<pabc::Abc_Ntk_t *>().size() == 0u)
std::cerr << "Error: Empty network.\n";
else {
auto pNtk = store<pabc::Abc_Ntk_t *>().current();
pabc::Io_Write(pNtk, (char *)(file_name.c_str()),
pabc::Io_ReadFileType((char *)(file_name.c_str())));
}
}
private:
std::string file_name;
};
ALICE_ADD_COMMAND(write, "I/O")
} // namespace alice
#endif

View File

@ -1,101 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2022 */
/**
* @file algebraic_rewriting.hpp
*
* @brief algebraic depth rewriting
*
* @author Homyoung
* @since 2022/12/14
*/
#ifndef ALGEBRAIC_REWRITING_HPP
#define ALGEBRAIC_REWRITING_HPP
#include <mockturtle/algorithms/mig_algebraic_rewriting.hpp>
#include <mockturtle/algorithms/xag_algebraic_rewriting.hpp>
#include <mockturtle/algorithms/xmg_algebraic_rewriting.hpp>
#include <mockturtle/networks/mig.hpp>
#include <mockturtle/networks/xag.hpp>
#include <mockturtle/networks/xmg.hpp>
#include <mockturtle/traits.hpp>
#include <mockturtle/views/depth_view.hpp>
using namespace std;
using namespace mockturtle;
namespace alice {
class algebraic_rewriting_command : public command {
public:
explicit algebraic_rewriting_command(const environment::ptr& env)
: command(env, "algebraic depth rewriting [default = MIG]") {
add_flag("--xag, -g", "refactoring for XAG");
add_flag("--xmg, -x", "refactoring for XMG");
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
begin = clock();
if (is_set("xag")) {
if (store<xag_network>().size() == 0u)
std::cerr << "Error: Empty XAG network\n";
else {
auto xag = store<xag_network>().current();
depth_view depth_xag{xag};
xag_algebraic_depth_rewriting_params ps;
ps.allow_rare_rules = true;
xag_algebraic_depth_rewriting(depth_xag, ps);
depth_xag = cleanup_dangling(depth_xag);
phyLS::print_stats(depth_xag);
store<xag_network>().extend();
store<xag_network>().current() = depth_xag;
}
} else if (is_set("xmg")) {
if (store<xmg_network>().size() == 0u)
std::cerr << "Error: Empty XMG network\n";
else {
auto xmg = store<xmg_network>().current();
depth_view depth_xmg{xmg};
xmg_algebraic_depth_rewriting_params ps;
ps.strategy = xmg_algebraic_depth_rewriting_params::selective;
xmg_algebraic_depth_rewriting(depth_xmg, ps);
depth_xmg = cleanup_dangling(depth_xmg);
phyLS::print_stats(depth_xmg);
store<xmg_network>().extend();
store<xmg_network>().current() = depth_xmg;
}
} else {
if (store<mig_network>().size() == 0u)
std::cerr << "Error: Empty MIG network\n";
else {
auto mig = store<mig_network>().current();
depth_view depth_mig{mig};
mig_algebraic_depth_rewriting_params ps;
mig_algebraic_depth_rewriting(depth_mig, ps);
depth_mig = cleanup_dangling(depth_mig);
phyLS::print_stats(depth_mig);
store<mig_network>().extend();
store<mig_network>().current() = depth_mig;
}
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
};
ALICE_ADD_COMMAND(algebraic_rewriting, "Logic synthesis")
} // namespace alice
#endif

View File

@ -13,15 +13,8 @@
#ifndef BALANCE_HPP
#define BALANCE_HPP
#include <algorithm>
#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/views/depth_view.hpp>
#include <vector>
#include "../core/misc.hpp"
#include "../core/balance.hpp"
using namespace std;
using namespace mockturtle;
@ -33,56 +26,21 @@ class balance_command : public command {
explicit balance_command(const environment::ptr& env)
: command(env,
"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("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
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)
std::cerr << "Error: Empty AIG network\n";
else {
auto aig = store<aig_network>().current();
if (is_set("strash")) {
begin = clock();
aig_balancing_params ps;
ps.minimize_levels = false;
aig_balance(aig, ps);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
} else {
begin = clock();
aig_balance(aig);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
}
phyLS::print_stats(aig);
store<aig_network>().extend();
store<aig_network>().current() = aig;
}
if (store<aig_network>().size() == 0u)
std::cerr << "Error: Empty AIG network\n";
else {
auto aig = store<aig_network>().current();
phyLS::aig_balancing(aig);
phyLS::print_stats(aig);
store<aig_network>().extend();
store<aig_network>().current() = aig;
}
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
};
ALICE_ADD_COMMAND(balance, "Synthesis")

View File

@ -1,79 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2022 */
/**
* @file cec.hpp
*
* @brief performs combinational equivalence checking
*
* @author Homyoung
* @since 2022/12/14
*/
#ifndef CEC_HPP
#define CEC_HPP
#include <mockturtle/algorithms/equivalence_checking.hpp>
#include <mockturtle/algorithms/miter.hpp>
#include <mockturtle/networks/aig.hpp>
#include <mockturtle/networks/xag.hpp>
#include <vector>
using namespace std;
using namespace mockturtle;
namespace alice {
class cec_command : public command {
public:
explicit cec_command(const environment::ptr& env)
: command(env, "combinational equivalence checking for AIG network") {
add_option("file_1, -a", filename_1, "the input file name");
add_option("file_2, -b", filename_2, "the input file name");
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
begin = clock();
aig_network aig1, aig2;
if ((lorina::read_aiger(filename_1, mockturtle::aiger_reader(aig1)) ==
lorina::return_code::success) &&
(lorina::read_aiger(filename_2, mockturtle::aiger_reader(aig2)) ==
lorina::return_code::success)) {
if (aig1.num_pis() != aig2.num_pis())
std::cerr << "Networks have different number of primary inputs."
<< std::endl
<< "Miter computation has failed." << std::endl;
else {
const auto miter_ntk = *miter<aig_network>(aig1, aig2);
equivalence_checking_stats st;
const auto result = equivalence_checking(miter_ntk, {}, &st);
if (result)
std::cout << "Networks are equivalent." << std::endl;
else
std::cout << "Networks are NOT EQUIVALENT." << std::endl;
}
} else {
std::cerr << "[w] parse error" << std::endl;
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
string filename_1;
string filename_2;
};
ALICE_ADD_COMMAND(cec, "Verification")
} // namespace alice
#endif

View File

@ -1,104 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2022 */
/**
* @file convert_graph.hpp
*
* @brief performs decomposable function for resynthesis graph
*
* @author Homyoung
* @since 2022/12/20
*/
#ifndef CONVERT_GRAPH_HPP
#define CONVERT_GRAPH_HPP
#include <iostream>
#include <mockturtle/algorithms/klut_to_graph.hpp>
using namespace std;
using namespace mockturtle;
namespace alice {
class create_graph_command : public command {
public:
explicit create_graph_command(const environment::ptr& env)
: command(env, "functional reduction [default = AIG]") {
add_option("-e,--expression", expression,
"creates new graph from expression");
add_flag("--mig, -m", "functional reduction for MIG");
add_flag("--xag, -g", "functional reduction for XAG");
add_flag("--xmg, -x", "functional reduction for XMG");
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
begin = clock();
auto& opt_ntks = store<optimum_network>();
if (opt_ntks.empty()) opt_ntks.extend();
uint32_t num_vars{0u};
for (auto c : expression) {
if (c >= 'a' && c <= 'p')
num_vars = std::max<uint32_t>(num_vars, c - 'a' + 1u);
}
kitty::dynamic_truth_table tt(num_vars);
kitty::create_from_expression(tt, expression);
klut_network kLUT_ntk;
vector<klut_network::signal> children;
for (auto i = 0; i < num_vars; i++) {
const auto x = kLUT_ntk.create_pi();
children.push_back(x);
}
auto fn = [&](kitty::dynamic_truth_table const& remainder,
std::vector<klut_network::signal> const& children) {
return kLUT_ntk.create_node(children, remainder);
};
kLUT_ntk.create_po(dsd_decomposition(kLUT_ntk, tt, children, fn));
if (is_set("mig")) {
auto mig = convert_klut_to_graph<mig_network>(kLUT_ntk);
phyLS::print_stats(mig);
store<mig_network>().extend();
store<mig_network>().current() = mig;
} else if (is_set("xmg")) {
auto xmg = convert_klut_to_graph<xmg_network>(kLUT_ntk);
phyLS::print_stats(xmg);
store<xmg_network>().extend();
store<xmg_network>().current() = xmg;
} else if (is_set("xag")) {
auto xag = convert_klut_to_graph<xag_network>(kLUT_ntk);
phyLS::print_stats(xag);
store<xag_network>().extend();
store<xag_network>().current() = xag;
} else {
auto aig = convert_klut_to_graph<aig_network>(kLUT_ntk);
phyLS::print_stats(aig);
store<aig_network>().extend();
store<aig_network>().current() = aig;
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
string expression = "";
};
ALICE_ADD_COMMAND(create_graph, "Synthesis")
} // namespace alice
#endif

View File

@ -1,249 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2022 */
/**
* @file cut_rewriting.hpp
*
* @brief on-the-fly DAG-aware logic rewriting
*
* @author Homyoung
* @since 2022/12/15
*/
#ifndef CUT_REWRITING_HPP
#define CUT_REWRITING_HPP
#include <time.h>
#include <mockturtle/algorithms/cut_rewriting.hpp>
#include <mockturtle/algorithms/node_resynthesis/akers.hpp>
#include <mockturtle/algorithms/node_resynthesis/exact.hpp>
#include <mockturtle/algorithms/node_resynthesis/mig_npn.hpp>
#include <mockturtle/algorithms/node_resynthesis/xag_minmc2.hpp>
#include <mockturtle/algorithms/node_resynthesis/xag_npn.hpp>
#include <mockturtle/algorithms/node_resynthesis/xmg3_npn.hpp>
#include <mockturtle/networks/aig.hpp>
#include <mockturtle/networks/klut.hpp>
#include <mockturtle/networks/mig.hpp>
#include <mockturtle/networks/xag.hpp>
#include <mockturtle/networks/xmg.hpp>
#include <mockturtle/properties/mccost.hpp>
#include <mockturtle/traits.hpp>
#include <mockturtle/utils/cost_functions.hpp>
#include <mockturtle/views/fanout_view.hpp>
#include "../core/misc.hpp"
#include "../networks/aoig/xag_lut_npn.hpp"
#include "../networks/stp/stp_npn.hpp"
using namespace std;
using namespace mockturtle;
namespace alice {
class rewrite_command : public command {
public:
explicit rewrite_command(const environment::ptr& env)
: command(env, "on-the-fly DAG-aware logic rewriting [default = AIG]") {
add_flag("--xmg, -x", "rewriting for XMG");
add_flag("--mig, -m", "rewriting for MIG");
add_flag("--xag, -g", "rewriting for XAG");
add_flag("--klut, -l", "rewriting for k-LUT");
add_flag("--klut_npn, -n", "cut rewriting based on k-LUT NPN network");
add_flag("--xag_npn_lut, -u",
"cut rewriting based on XAG NPN based LUT network");
add_flag("--xag_npn, -p", "cut rewriting based on XAG NPN network");
add_flag("--akers, -a", "Cut rewriting with Akers synthesis for MIG");
add_flag("--compatibility_graph, -c", "In-place cut rewriting");
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime = 0.0;
if (is_set("xmg")) {
if (store<xmg_network>().size() == 0u)
std::cerr << "Error: Empty XMG network\n";
else {
auto xmg = store<xmg_network>().current();
begin = clock();
xmg_npn_resynthesis resyn;
cut_rewriting_params ps;
ps.cut_enumeration_ps.cut_size = 4u;
if (is_set("compatibility_graph"))
cut_rewriting_with_compatibility_graph(xmg, resyn, ps);
else
xmg = cut_rewriting(xmg, resyn, ps);
xmg = cleanup_dangling(xmg);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
phyLS::print_stats(xmg);
store<xmg_network>().extend();
store<xmg_network>().current() = xmg;
}
} else if (is_set("mig")) {
if (store<mig_network>().size() == 0u)
std::cerr << "Error: Empty MIG network\n";
else {
auto mig = store<mig_network>().current();
begin = clock();
if (is_set("akers")) {
akers_resynthesis<mig_network> resyn;
cut_rewriting_params ps;
ps.cut_enumeration_ps.cut_size = 4u;
if (is_set("compatibility_graph"))
cut_rewriting_with_compatibility_graph(mig, resyn, ps);
else
mig = cut_rewriting(mig, resyn, ps);
} else {
mig_npn_resynthesis resyn;
cut_rewriting_params ps;
ps.cut_enumeration_ps.cut_size = 4u;
if (is_set("compatibility_graph"))
cut_rewriting_with_compatibility_graph(mig, resyn, ps);
else
mig = cut_rewriting(mig, resyn, ps);
}
mig = cleanup_dangling(mig);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
phyLS::print_stats(mig);
store<mig_network>().extend();
store<mig_network>().current() = mig;
}
} else if (is_set("xag")) {
if (store<xag_network>().size() == 0u)
std::cerr << "Error: Empty XAG network\n";
else {
auto xag = store<xag_network>().current();
begin = clock();
xag_npn_resynthesis<xag_network> resyn;
cut_rewriting_params ps;
ps.cut_enumeration_ps.cut_size = 4u;
ps.min_cand_cut_size = 2;
ps.min_cand_cut_size_override = 3;
if (is_set("compatibility_graph")) {
cut_rewriting_with_compatibility_graph(xag, resyn, ps, nullptr,
mc_cost<xag_network>());
} else {
xag = cut_rewriting(xag, resyn, ps);
}
xag = cleanup_dangling(xag);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
phyLS::print_stats(xag);
store<xag_network>().extend();
store<xag_network>().current() = xag;
}
} else if (is_set("klut")) {
if (store<klut_network>().size() == 0u)
std::cerr << "Error: Empty k-LUT network\n";
else {
auto klut = store<klut_network>().current();
begin = clock();
exact_resynthesis resyn(3u);
if (is_set("compatibility_graph"))
cut_rewriting_with_compatibility_graph(klut, resyn);
else
klut = cut_rewriting(klut, resyn);
klut = cleanup_dangling(klut);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
phyLS::print_stats(klut);
store<klut_network>().extend();
store<klut_network>().current() = klut;
}
} else if (is_set("xag_npn_lut")) {
xag_network xag = store<xag_network>().current();
phyLS::print_stats(xag);
begin = clock();
xag_npn_lut_resynthesis resyn;
cut_rewriting_params ps;
ps.cut_enumeration_ps.cut_size = 4u;
xag = cut_rewriting(xag, resyn, ps);
xag = cleanup_dangling(xag);
// bidecomposition refactoring
bidecomposition_resynthesis<xag_network> resyn2;
refactoring(xag, resyn2);
xag = cleanup_dangling(xag);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
phyLS::print_stats(xag);
store<xag_network>().extend();
store<xag_network>().current() = cleanup_dangling(xag);
} else if (is_set("xag_npn")) {
xag_network xag = store<xag_network>().current();
phyLS::print_stats(xag);
begin = clock();
xag_npn_resynthesis<xag_network> resyn;
cut_rewriting_params ps;
ps.cut_enumeration_ps.cut_size = 4u;
ps.min_cand_cut_size = 2;
ps.min_cand_cut_size_override = 3;
xag = cut_rewriting(xag, resyn, ps);
xag = cleanup_dangling(xag);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
phyLS::print_stats(xag);
store<xag_network>().extend();
store<xag_network>().current() = cleanup_dangling(xag);
} else if (is_set("klut_npn")) {
klut_network klut = store<klut_network>().current();
phyLS::print_stats(klut);
begin = clock();
stp_npn_resynthesis resyn;
cut_rewriting_params ps;
ps.cut_enumeration_ps.cut_size = 4u;
ps.allow_zero_gain = false;
if (is_set("compatibility_graph"))
cut_rewriting_with_compatibility_graph(klut, resyn);
else
klut = cut_rewriting(klut, resyn, ps);
klut = cleanup_dangling(klut);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
phyLS::print_stats(klut);
store<klut_network>().extend();
store<klut_network>().current() = cleanup_dangling(klut);
} else {
if (store<aig_network>().size() == 0u)
std::cerr << "Error: Empty AIG network\n";
else {
auto aig = store<aig_network>().current();
begin = clock();
xag_npn_resynthesis<aig_network> resyn;
cut_rewriting_params ps;
ps.cut_enumeration_ps.cut_size = 4;
aig = cut_rewriting(aig, resyn, ps);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
phyLS::print_stats(aig);
store<aig_network>().extend();
store<aig_network>().current() = aig;
}
}
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
};
ALICE_ADD_COMMAND(rewrite, "Synthesis")
} // namespace alice
#endif

View File

@ -1,660 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file exact_lut.hpp
*
* @brief STP based exact synthesis
*
* @author Homyoung
* @since 2022/11/23
*/
#ifndef EXACTLUT_HPP
#define EXACTLUT_HPP
#include <time.h>
#include <alice/alice.hpp>
#include <mockturtle/mockturtle.hpp>
#include <percy/percy.hpp>
#include "../../core/exact/exact_dag.hpp"
#include "../../core/exact/exact_lut.hpp"
#include "../core/exact/lut_rewriting.hpp"
using namespace std;
using namespace percy;
using namespace mockturtle;
using kitty::dynamic_truth_table;
namespace alice {
class exact_command : public command {
public:
explicit exact_command(const environment::ptr& env)
: command(env, "exact synthesis to find optimal 2-LUTs") {
add_option("function, -f", tt, "exact synthesis of function in hex");
add_flag("--cegar_dag, -c", "cegar encoding and partial DAG structure");
add_flag("--stp_cegar_dag, -s",
"stp based cegar encoding and partial DAG structure");
add_flag("--dag_depth, -t",
"cegar encoding and partial DAG structure for Delay");
add_flag("--decomposition, -p",
"using decomposition before exact synthesis");
add_option("--output, -o", filename, "the verilog filename");
add_flag("--enumeration, -e", "enumerate all solutions");
add_flag("--new_entry, -w", "adds k-LUT store entry");
add_flag("--map, -m", "ASIC map each k-LUT");
add_flag("--aig, -a", "enable exact synthesis for AIG, default = false");
add_flag("--xag, -g", "enable exact synthesis for XAG, default = false");
add_flag("--npn, -n", "print result for NPN storing, default = false");
add_flag("--depth, -d", "print the depth of each result, default = false");
add_flag("--parallel, -l", "parallel exact synthesis");
add_flag("--verbose, -v", "verbose results, default = true");
}
protected:
string binary_to_hex() {
string t_temp;
for (int i = 0; i < tt.length(); i++) {
switch (tt[i]) {
case '0':
t_temp += "0000";
continue;
case '1':
t_temp += "0001";
continue;
case '2':
t_temp += "0010";
continue;
case '3':
t_temp += "0011";
continue;
case '4':
t_temp += "0100";
continue;
case '5':
t_temp += "0101";
continue;
case '6':
t_temp += "0110";
continue;
case '7':
t_temp += "0111";
continue;
case '8':
t_temp += "1000";
continue;
case '9':
t_temp += "1001";
continue;
case 'a':
t_temp += "1010";
continue;
case 'b':
t_temp += "1011";
continue;
case 'c':
t_temp += "1100";
continue;
case 'd':
t_temp += "1101";
continue;
case 'e':
t_temp += "1110";
continue;
case 'f':
t_temp += "1111";
continue;
case 'A':
t_temp += "1010";
continue;
case 'B':
t_temp += "1011";
continue;
case 'C':
t_temp += "1100";
continue;
case 'D':
t_temp += "1101";
continue;
case 'E':
t_temp += "1110";
continue;
case 'F':
t_temp += "1111";
continue;
}
}
return t_temp;
}
void enu_es(int nr_in, list<chain>& chains) {
int node = nr_in - 1;
bool target = false;
while (true) {
spec spec;
bsat_wrapper solver;
partial_dag_encoder encoder2(solver);
encoder2.reset_sim_tts(nr_in);
spec.add_alonce_clauses = false;
spec.add_nontriv_clauses = false;
spec.add_lex_func_clauses = false;
spec.add_colex_clauses = false;
spec.add_noreapply_clauses = false;
spec.add_symvar_clauses = false;
spec.verbosity = 0;
kitty::dynamic_truth_table f(nr_in);
kitty::create_from_hex_string(f, tt);
spec[0] = f;
auto dags = pd_generate_filter(node, nr_in);
spec.preprocess();
for (auto& dag : dags) {
chain c;
synth_result status;
status = pd_cegar_synthesize(spec, c, dag, solver, encoder2);
if (status == success) {
chains.push_back(c);
target = true;
}
}
if (target) break;
node++;
}
}
void es(int nr_in, chain& result) {
int node = nr_in - 1;
bool target = false;
while (true) {
spec spec;
bsat_wrapper solver;
partial_dag_encoder encoder2(solver);
encoder2.reset_sim_tts(nr_in);
spec.add_alonce_clauses = false;
spec.add_nontriv_clauses = false;
spec.add_lex_func_clauses = false;
spec.add_colex_clauses = false;
spec.add_noreapply_clauses = false;
spec.add_symvar_clauses = false;
spec.verbosity = 0;
kitty::dynamic_truth_table f(nr_in);
kitty::create_from_hex_string(f, tt);
spec[0] = f;
auto dags = pd_generate_filter(node, nr_in);
spec.preprocess();
for (auto& dag : dags) {
chain c;
synth_result status;
status = pd_cegar_synthesize(spec, c, dag, solver, encoder2);
if (status == success) {
result.copy(c);
target = true;
break;
}
}
if (target) break;
node++;
}
}
void es_parallel(int nr_in, chain& result) {
spec spec;
chain c;
spec.add_alonce_clauses = false;
spec.add_nontriv_clauses = false;
spec.add_lex_func_clauses = false;
spec.add_colex_clauses = false;
spec.add_noreapply_clauses = false;
spec.add_symvar_clauses = false;
spec.verbosity = 0;
kitty::dynamic_truth_table f(nr_in);
kitty::create_from_hex_string(f, tt);
spec[0] = f;
spec.preprocess();
auto res = pd_ser_synthesize_parallel(spec, c, 4, "../src/pd/");
// auto res = pf_fence_synthesize(spec, c, 8);
if (res == success) result.copy(c);
}
void es_delay(int nr_in, list<chain>& chains) {
int node = nr_in - 1, max_level = 0, count = 0;
bool target = false;
while (true) {
spec spec;
spec.add_alonce_clauses = false;
spec.add_nontriv_clauses = false;
spec.add_lex_func_clauses = false;
spec.add_colex_clauses = false;
spec.add_noreapply_clauses = false;
spec.add_symvar_clauses = false;
spec.verbosity = 0;
bsat_wrapper solver;
partial_dag_encoder encoder2(solver);
encoder2.reset_sim_tts(nr_in);
kitty::dynamic_truth_table f(nr_in);
kitty::create_from_hex_string(f, tt);
spec[0] = f;
auto dags = pd_generate_filter(node, nr_in);
spec.preprocess();
for (auto dag : dags) {
chain c;
const auto status = pd_cegar_synthesize(spec, c, dag, solver, encoder2);
if (status == success) {
target = true;
int level_temp = c.get_nr_level();
if (max_level == 0) {
chains.push_back(c);
max_level = level_temp;
} else if (level_temp == max_level) {
chains.push_back(c);
} else if (level_temp < max_level) {
chains.clear();
chains.push_back(c);
max_level = level_temp;
}
}
}
if (target) break;
node++;
}
while (true) {
if (max_level == 2 || count > 2) break;
bool target_count = false;
spec spec;
spec.add_alonce_clauses = false;
spec.add_nontriv_clauses = false;
spec.add_lex_func_clauses = false;
spec.add_colex_clauses = false;
spec.add_noreapply_clauses = false;
spec.add_symvar_clauses = false;
spec.verbosity = 0;
bsat_wrapper solver;
partial_dag_encoder encoder2(solver);
encoder2.reset_sim_tts(nr_in);
kitty::dynamic_truth_table f(nr_in);
kitty::create_from_hex_string(f, tt);
spec[0] = f;
node++;
auto dags = pd_generate_filter(node, nr_in);
spec.preprocess();
for (auto dag : dags) {
if (dag.nr_level() > max_level) continue;
chain c;
const auto status = pd_cegar_synthesize(spec, c, dag, solver, encoder2);
if (status == success) {
int level_temp = c.get_nr_level();
if (level_temp == max_level) {
chains.push_back(c);
} else if (level_temp < max_level) {
max_level = level_temp;
chains.clear();
chains.push_back(c);
target_count = true;
}
}
}
if (!target_count) count++;
}
}
klut_network create_network(chain& c) {
klut_network klut;
c.store_bench(0);
std::string filename = "r_0.bench";
if (lorina::read_bench(filename, mockturtle::bench_reader(klut)) !=
lorina::return_code::success) {
std::cout << "[w] parse error\n";
}
return klut;
}
bool compare_min_area(double area_temp, double delay_temp, int gate) {
bool target = false;
if (min_area == 0.00 && min_delay == 0.00) {
min_area = area_temp;
min_delay = delay_temp;
mapping_gate = gate;
target = true;
} else if (area_temp < min_area) {
min_area = area_temp;
min_delay = delay_temp;
mapping_gate = gate;
target = true;
} else if (area_temp == min_area) {
if (delay_temp < min_delay) {
min_delay = delay_temp;
mapping_gate = gate;
target = true;
}
}
return target;
}
bool compare_min_delay(double area_temp, double delay_temp, int gate) {
bool target = false;
if (min_area == 0.00 && min_delay == 0.00) {
min_area = area_temp;
min_delay = delay_temp;
mapping_gate = gate;
target = true;
} else if (delay_temp < min_delay) {
min_area = area_temp;
min_delay = delay_temp;
mapping_gate = gate;
target = true;
} else if (delay_temp == min_delay) {
if (area_temp < min_area) {
min_area = area_temp;
mapping_gate = gate;
target = true;
}
}
return target;
}
void es_after_decomposition() {
dec_network = store<mockturtle::klut_network>().current();
phyLS::lut_rewriting_params ps;
dec_network = phyLS::lut_rewriting_c(dec_network, ps);
}
void execute() {
t.clear();
t.push_back(binary_to_hex());
vector<string>& tt_h = t;
int nr_in = 0, value = 0;
while (value < tt.size()) {
value = pow(2, nr_in);
if (value == tt.size()) break;
nr_in++;
}
nr_in += 2;
cout << "Running exact synthesis for " << nr_in << "-input function."
<< endl
<< endl;
clock_t begin, end;
double totalTime = 0.0;
phyLS::exact_lut_params ps;
if (is_set("verbose")) ps.verbose = false;
if (is_set("aig")) ps.aig = true;
if (is_set("xag")) ps.xag = true;
if (is_set("npn")) ps.npn = true;
if (is_set("depth")) ps.depth = true;
if (is_set("map")) ps.map = true;
if (is_set("cegar_dag")) {
if (is_set("enumeration")) {
begin = clock();
list<chain> chains;
enu_es(nr_in, chains);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
int count = 0;
chain best_chain;
for (auto x : chains) {
count += 1;
if (ps.verbose) {
x.print_bench();
if (ps.depth)
std::cout << "level = " << x.get_nr_level() << std::endl;
}
if (ps.npn) {
x.print_npn();
if (ps.depth) {
std::cout << ": l{" << x.get_nr_level() << "}" << std::endl;
} else {
std::cout << std::endl;
}
}
if (is_set("map")) {
std::vector<mockturtle::gate> gates =
store<std::vector<mockturtle::gate>>().current();
mockturtle::tech_library<5> lib(gates);
mockturtle::map_params ps;
mockturtle::map_stats st;
klut_network klut = create_network(x);
auto res = mockturtle::map(klut, lib, ps, &st);
if (compare_min_area(st.area, st.delay, res.num_gates())) {
if (is_set("output")) {
write_verilog_with_binding(res, filename);
}
best_chain.copy(x);
}
}
}
if (is_set("map")) {
best_chain.print_npn();
if (ps.depth) {
std::cout << ": l{" << best_chain.get_nr_level() << "}"
<< std::endl;
} else {
std::cout << std::endl;
}
std::cout << "Mapped gates = " << mapping_gate
<< ", area = " << min_area << ", delay = " << min_delay
<< std::endl;
}
cout << "[Total realization]: " << count << endl;
} else {
begin = clock();
chain chain;
es(nr_in, chain);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
if (is_set("new_entry")) {
klut_network klut = create_network(chain);
store<klut_network>().extend();
store<klut_network>().current() = klut;
}
if (ps.verbose) {
chain.print_bench();
if (ps.depth) {
klut_network klut = create_network(chain);
mockturtle::depth_view depth_lut{klut};
std::cout << "level = " << depth_lut.depth() - 1 << std::endl;
}
}
if (ps.npn) {
chain.print_npn();
if (ps.depth) {
klut_network klut = create_network(chain);
mockturtle::depth_view depth_lut{klut};
std::cout << "l{" << depth_lut.depth() - 1 << "}" << std::endl;
} else {
std::cout << std::endl;
}
}
if (is_set("map")) {
std::vector<mockturtle::gate> gates =
store<std::vector<mockturtle::gate>>().current();
mockturtle::tech_library<5> lib(gates);
mockturtle::map_params ps;
mockturtle::map_stats st;
klut_network klut = create_network(chain);
auto res = mockturtle::map(klut, lib, ps, &st);
compare_min_area(st.area, st.delay, res.num_gates());
chain.print_npn();
if (is_set("output")) {
write_verilog_with_binding(res, filename);
}
if (is_set("depth")) {
klut_network klut = create_network(chain);
mockturtle::depth_view depth_lut{klut};
std::cout << ": l{" << depth_lut.depth() - 1 << "}" << std::endl;
} else {
std::cout << std::endl;
}
std::cout << "Mapped gates = " << mapping_gate
<< ", area = " << min_area << ", delay = " << min_delay
<< std::endl;
}
}
} else if (is_set("dag_depth")) {
begin = clock();
list<chain> chains;
es_delay(nr_in, chains);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
int count = 0;
chain best_chain;
for (auto x : chains) {
count += 1;
if (is_set("verbose")) {
x.print_bench();
if (ps.depth)
std::cout << "level = " << x.get_nr_level() << std::endl;
}
if (is_set("npn")) {
x.print_npn();
if (ps.depth) {
std::cout << ": l{" << x.get_nr_level() << "}" << std::endl;
} else {
std::cout << std::endl;
}
}
if (is_set("map")) {
std::vector<mockturtle::gate> gates =
store<std::vector<mockturtle::gate>>().current();
mockturtle::tech_library<5> lib(gates);
mockturtle::map_params ps;
mockturtle::map_stats st;
klut_network klut = create_network(x);
auto res = mockturtle::map(klut, lib, ps, &st);
if (compare_min_delay(st.area, st.delay, res.num_gates()))
best_chain.copy(x);
}
}
if (is_set("map")) {
best_chain.print_npn();
if (ps.depth) {
std::cout << ": l{" << best_chain.get_nr_level() << "}" << std::endl;
} else {
std::cout << std::endl;
}
std::cout << "Mapped gates = " << mapping_gate
<< ", area = " << min_area << ", delay = " << min_delay
<< std::endl;
}
cout << "[Total realization]: " << count << endl;
} else if (is_set("stp_cegar_dag")) {
if (is_set("map")) {
ps.gates = store<std::vector<mockturtle::gate>>().current();
begin = clock();
exact_lut_dag_enu_map(tt, nr_in, ps);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
std::cout << "Mapped gates = " << ps.mapping_gate
<< ", area = " << ps.min_area << ", delay = " << ps.min_delay
<< std::endl;
} else if (is_set("enumeration")) {
begin = clock();
exact_lut_dag_enu(tt, nr_in, ps);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout << "[Total realization]: " << nr_in << endl;
} else {
begin = clock();
exact_lut_dag(tt, nr_in, ps);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout << "[Total realization]: " << nr_in << endl;
}
} else if (is_set("decomposition")) {
begin = clock();
es_after_decomposition();
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
} else if (is_set("parallel")) {
int64_t total_elapsed = 0;
auto start = std::chrono::steady_clock::now();
chain chain;
es_parallel(nr_in, chain);
const auto elapsed1 =
std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now() - start)
.count();
total_elapsed += elapsed1;
if (ps.verbose) {
chain.print_bench();
if (ps.depth) {
klut_network klut = create_network(chain);
mockturtle::depth_view depth_lut{klut};
std::cout << "level = " << depth_lut.depth() - 1 << std::endl;
}
}
if (ps.npn) {
chain.print_npn();
if (ps.depth) {
klut_network klut = create_network(chain);
mockturtle::depth_view depth_lut{klut};
std::cout << "l{" << depth_lut.depth() - 1 << "}" << std::endl;
} else {
std::cout << std::endl;
}
}
printf("[Total CPU time] : %ldus\n", total_elapsed);
} else {
if (is_set("enumeration")) {
begin = clock();
int cut_size = 0;
phyLS::exact_lut_enu(tt_h, nr_in, cut_size);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
int count = 0;
for (auto x : tt_h) {
if (ps.verbose) cout << x << endl;
count += 1;
}
cout << "[Total realization]: " << count << endl;
} else {
begin = clock();
int cut_size = 0;
phyLS::exact_lut(tt_h, nr_in, cut_size);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
int count = 0;
for (auto x : tt_h) {
if (ps.verbose) cout << x << endl;
count += 1;
}
cout << "[Total realization]: " << count << endl;
}
}
cout.setf(ios::fixed);
cout << "[Total CPU time] : " << setprecision(3) << totalTime << " s"
<< endl;
}
private:
string tt;
vector<string> t;
double min_area = 0.00;
double min_delay = 0.00;
int mapping_gate = 0;
std::string filename = "techmap.v";
klut_network dec_network;
};
ALICE_ADD_COMMAND(exact, "Synthesis")
} // namespace alice
#endif

View File

@ -1,121 +0,0 @@
#ifndef EXACT_MULTI_HPP
#define EXACT_MULTI_HPP
#include <alice/alice.hpp>
#include <iostream>
#include <mockturtle/algorithms/klut_to_graph.hpp>
#include <mockturtle/mockturtle.hpp>
#include <percy/percy.hpp>
#include <string>
#include <vector>
#include "../store.hpp"
using namespace std;
using namespace percy;
using namespace mockturtle;
using kitty::dynamic_truth_table;
using namespace std;
namespace alice {
class exact_window_command : public command {
public:
explicit exact_window_command(const environment::ptr& env)
: command(env, "using exact synthesis to find optimal window") {
add_flag("--cegar, -c", "cegar encoding");
add_option("--num_functions, -n", num_functions,
"set the number of functions to be synthesized, default = 1");
add_option("--file, -f", filename, "input filename");
add_flag("--verbose, -v", "print the information");
}
private:
int num_functions = 1;
std::string filename;
vector<string> iTT;
aig_network create_network(chain& c) {
klut_network klut;
c.store_bench(0);
std::string filename = "r_0.bench";
if (lorina::read_bench(filename, mockturtle::bench_reader(klut)) !=
lorina::return_code::success) {
std::cout << "[w] parse error\n";
}
aig_network aig = convert_klut_to_graph<aig_network>(klut);
return aig;
}
protected:
void execute() {
spec spec;
aig_network aig;
if (is_set("file")) {
ifstream fin_bench(filename);
string tmp;
if (fin_bench.is_open()) {
while (getline(fin_bench, tmp)) {
iTT.push_back(tmp);
}
fin_bench.close();
int nr_in = 0, value = 0;
while (value < iTT[0].size()) {
value = pow(2, nr_in);
if (value == iTT[0].size()) break;
nr_in++;
}
for (int i = 0; i < iTT.size(); i++) {
kitty::dynamic_truth_table f(nr_in);
kitty::create_from_binary_string(f, iTT[i]);
spec[i] = f;
}
}
} else {
auto store_size = store<optimum_network>().size();
assert(store_size >= num_functions);
if (!is_set("num_functions")) num_functions = 1;
for (int i = 0; i < num_functions; i++) {
auto& opt = store<optimum_network>()[store_size - i - 1];
auto copy = opt.function;
spec[i] = copy;
}
}
stopwatch<>::duration time{0};
if (is_set("cegar")) {
bsat_wrapper solver;
msv_encoder encoder(solver);
chain c;
call_with_stopwatch(time, [&]() {
if (synthesize(spec, c, solver, encoder) == success) {
c.print_bench();
aig = create_network(c);
store<aig_network>().extend();
store<aig_network>().current() = aig;
}
});
} else {
bsat_wrapper solver;
ssv_encoder encoder(solver);
chain c;
call_with_stopwatch(time, [&]() {
if (synthesize(spec, c, solver, encoder) == success) {
c.print_bench();
aig = create_network(c);
store<aig_network>().extend();
store<aig_network>().current() = aig;
}
});
}
std::cout << fmt::format("[Total CPU time] : {:5.3f} seconds\n",
to_seconds(time));
}
};
ALICE_ADD_COMMAND(exact_window, "Synthesis")
} // namespace alice
#endif

View File

@ -1,94 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file lutrw.hpp
*
* @brief 2-lut rewriting with STP based exact synthesis
*
* @author Homyoung
* @since 2022/11/30
*/
#ifndef LUTRW_COMMAND_HPP
#define LUTRW_COMMAND_HPP
#include <time.h>
#include <alice/alice.hpp>
#include <mockturtle/mockturtle.hpp>
#include <mockturtle/networks/klut.hpp>
#include <percy/percy.hpp>
#include "../../core/exact/lut_rewriting.hpp"
#include "../../core/misc.hpp"
using namespace std;
using namespace percy;
using kitty::dynamic_truth_table;
namespace alice {
class lutrw_command : public command {
public:
explicit lutrw_command(const environment::ptr& env)
: command(env, "Performs 2-LUT rewriting") {
add_flag("--techmap, -t", "rewriting by the lowest cost of realization");
add_flag("--enumeration_techmap, -e",
"rewriting by the lowest cost of enumerated realization");
add_flag("--cec, -c,", "apply equivalence checking in rewriting");
add_flag("--xag, -g", "enable exact synthesis for XAG, default = false");
}
protected:
void execute() {
mockturtle::klut_network klut = store<mockturtle::klut_network>().current();
mockturtle::klut_network klut_orig, klut_opt;
klut_orig = klut;
phyLS::lut_rewriting_params ps;
if (is_set("xag")) ps.xag = true;
clock_t begin, end;
double totalTime;
if (is_set("techmap")) {
begin = clock();
klut_opt = phyLS::lut_rewriting_s(klut, ps);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
} else if (is_set("enumeration_techmap")) {
begin = clock();
klut_opt = phyLS::lut_rewriting_s_enu(klut, ps);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
} else {
begin = clock();
klut_opt = phyLS::lut_rewriting_c(klut, ps);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
}
if (is_set("cec")) {
/* equivalence checking */
const auto miter_klut = *miter<klut_network>(klut_orig, klut_opt);
equivalence_checking_stats eq_st;
const auto result = equivalence_checking(miter_klut, {}, &eq_st);
assert(*result);
}
std::cout << "[lutrw] ";
phyLS::print_stats(klut_opt);
store<mockturtle::klut_network>().extend();
store<mockturtle::klut_network>().current() = klut_opt;
cout.setf(ios::fixed);
cout << "[Total CPU time] : " << setprecision(3) << totalTime << " s"
<< endl;
}
private:
};
ALICE_ADD_COMMAND(lutrw, "Synthesis")
} // namespace alice
#endif

View File

@ -1,76 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2022 */
/**
* @file exprsim.hpp
*
* @brief simulate a expression and return a truth table
*
* @author Homyoung
* @since 2022/12/14
*/
#ifndef EXPRSIM_HPP
#define EXPRSIM_HPP
#include "../store.hpp"
using namespace std;
namespace alice {
class exprsim_command : public command {
public:
explicit exprsim_command(const environment::ptr& env)
: command(env, "expression simulation, return a truth table") {
add_flag("--verbose, -v", "print the information");
add_option("-e,--expression", expression,
"creates truth table from expression");
add_flag("-n,--new", "adds new store entry");
add_option("-m,--max_num_vars", max_num_vars,
"set the maximum number of variables");
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
auto& opt_ntks = store<optimum_network>();
begin = clock();
if (opt_ntks.empty() || is_set("new")) opt_ntks.extend();
/* find max var */
uint32_t num_vars{0u};
for (auto c : expression) {
if (c >= 'a' && c <= 'p')
num_vars = std::max<uint32_t>(num_vars, c - 'a' + 1u);
}
if (is_set("max_num_vars"))
num_vars = max_num_vars > num_vars ? max_num_vars : num_vars;
kitty::dynamic_truth_table tt(num_vars);
if (kitty::create_from_expression(tt, expression)) {
optimum_network opt;
opt.function = tt;
opt.network = expression;
opt_ntks.current() = opt;
std::cout << fmt::format("tt: 0x{}", kitty::to_hex(opt.function))
<< std::endl;
store<optimum_network>().extend();
store<optimum_network>().current() = opt;
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
std::string expression = "";
uint32_t max_num_vars = 0u;
};
ALICE_ADD_COMMAND(exprsim, "Verification")
} // namespace alice
#endif

View File

@ -1,106 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2022 */
/**
* @file functional_reduction.hpp
*
* @brief performs functional reduction
*
* @author Homyoung
* @since 2022/12/20
*/
#ifndef FUCNTIONAL_REDUCTION_HPP
#define FUCNTIONAL_REDUCTION_HPP
#include <kitty/static_truth_table.hpp>
#include <mockturtle/algorithms/cleanup.hpp>
#include <mockturtle/algorithms/functional_reduction.hpp>
#include <mockturtle/algorithms/simulation.hpp>
#include <mockturtle/networks/aig.hpp>
#include <mockturtle/networks/mig.hpp>
#include <mockturtle/networks/xag.hpp>
#include <mockturtle/networks/xmg.hpp>
using namespace std;
using namespace mockturtle;
namespace alice {
class fr_command : public command {
public:
explicit fr_command(const environment::ptr& env)
: command(env, "functional reduction [default = AIG]") {
add_flag("--mig, -m", "functional reduction for MIG");
add_flag("--xag, -g", "functional reduction for XAG");
add_flag("--xmg, -x", "functional reduction for XMG");
add_option("--tfi_node, -n", max_tfi_node,
"Maximum number of nodes in the TFI to be compared");
add_option("--filename, -f", filename, "pre-generated patterns file");
add_flag("--pattern, -p",
"save the appended patterns (with CEXs) into file");
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
functional_reduction_params ps;
ps.max_iterations = 0;
if (is_set("--filename")) ps.pattern_filename = filename;
if (is_set("--tfi_node")) ps.max_TFI_nodes = max_tfi_node;
if (is_set("--pattern")) ps.save_patterns = "pattern.log";
if (is_set("--verbose")) {
ps.verbose = true;
ps.progress = true;
}
begin = clock();
if (is_set("mig")) {
auto mig = store<mig_network>().current();
functional_reduction(mig, ps);
mig = cleanup_dangling(mig);
phyLS::print_stats(mig);
store<mig_network>().extend();
store<mig_network>().current() = mig;
} else if (is_set("xmg")) {
auto xmg = store<xmg_network>().current();
functional_reduction(xmg, ps);
xmg = cleanup_dangling(xmg);
phyLS::print_stats(xmg);
store<xmg_network>().extend();
store<xmg_network>().current() = xmg;
} else if (is_set("xag")) {
auto xag = store<xag_network>().current();
functional_reduction(xag, ps);
xag = cleanup_dangling(xag);
phyLS::print_stats(xag);
store<xag_network>().extend();
store<xag_network>().current() = xag;
} else {
auto aig = store<aig_network>().current();
functional_reduction(aig, ps);
aig = cleanup_dangling(aig);
phyLS::print_stats(aig);
store<aig_network>().extend();
store<aig_network>().current() = aig;
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
int max_tfi_node = 1000;
string filename = "pattern.log";
};
ALICE_ADD_COMMAND(fr, "Synthesis")
} // namespace alice
#endif

View File

@ -1,103 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2022
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* @file load.hpp
*
* @brief load a hexdecimal string represented truth table
*
* @author Homyoung
* @since 2022/12/14
*/
#ifndef LOAD_HPP
#define LOAD_HPP
#include "../store.hpp"
namespace alice {
void add_optimum_network_entry(command &cmd,
kitty::dynamic_truth_table &function) {
if (cmd.env->variable("npn") != "") {
function = std::get<0>(kitty::exact_npn_canonization(function));
}
optimum_network entry(function);
if (!entry.exists()) {
cmd.store<optimum_network>().extend();
cmd.store<optimum_network>().current() = entry;
}
}
class load_command : public command {
public:
load_command(const environment::ptr &env) : command(env, "Load new entry") {
add_option("truth_table,--tt", truth_table, "truth table in hex format");
add_flag("--binary,-b", "read truth table as binary string");
add_option("--majn,-m", odd_inputs, "generate majority-of-n truth table ");
}
protected:
void execute() override {
auto function = [this]() {
if (is_set("binary")) {
const unsigned num_vars = ::log(truth_table.size()) / ::log(2.0);
kitty::dynamic_truth_table function(num_vars);
kitty::create_from_binary_string(function, truth_table);
return function;
} else if (is_set("majn")) {
if (!(odd_inputs & 1)) {
std::cout << " majority-of-n, n must be an odd number\n ";
assert(false);
}
kitty::dynamic_truth_table maj(odd_inputs);
kitty::create_majority(maj);
std::cout << " MAJ" << odd_inputs << " : " << kitty::to_hex(maj)
<< std::endl;
return maj;
} else {
const unsigned num_vars = ::log(truth_table.size() * 4) / ::log(2.0);
kitty::dynamic_truth_table function(num_vars);
kitty::create_from_hex_string(function, truth_table);
return function;
}
}();
add_optimum_network_entry(*this, function);
}
private:
std::string truth_table;
unsigned odd_inputs;
};
ALICE_ADD_COMMAND(load, "I/O");
} // namespace alice
#endif

View File

@ -1,140 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2022 */
/**
* @file lut_mapping.hpp
*
* @brief lut mapping for any input
*
* @author Homyoung
* @since 2022/12/14
*/
#ifndef LUT_MAPPING_HPP
#define LUT_MAPPING_HPP
#include <mockturtle/algorithms/collapse_mapped.hpp>
#include <mockturtle/algorithms/lut_mapping.hpp>
#include <mockturtle/algorithms/satlut_mapping.hpp>
#include <mockturtle/generators/arithmetic.hpp>
#include <mockturtle/networks/aig.hpp>
#include <mockturtle/networks/klut.hpp>
#include <mockturtle/networks/sequential.hpp>
#include <mockturtle/traits.hpp>
#include <mockturtle/views/mapping_view.hpp>
using namespace mockturtle;
using namespace std;
namespace alice {
class lut_mapping_command : public command {
public:
explicit lut_mapping_command(const environment::ptr &env)
: command(env, "LUT mapping [default = AIG]") {
add_option("cut_size, -k", cut_size,
"set the cut size from 2 to 8, default = 4");
add_flag("--satlut, -s", "satlut mapping");
add_flag("--xag, -g", "LUT mapping for XAG");
add_flag("--mig, -m", "LUT mapping for MIG");
add_flag("--klut, -l", "LUT mapping for k-LUT");
add_flag("--area, -a", "area-oriented mapping, default = no");
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
lut_mapping_params ps;
if (is_set("area")){
ps.rounds_ela = 4u;
}
if (is_set("mig")) {
/* derive some MIG */
assert(store<mig_network>().size() > 0);
begin = clock();
mig_network mig = store<mig_network>().current();
mapping_view<mig_network, true> mapped_mig{mig};
ps.cut_enumeration_ps.cut_size = cut_size;
lut_mapping<mapping_view<mig_network, true>, true>(mapped_mig, ps);
/* collapse into k-LUT network */
const auto klut = *collapse_mapped_network<klut_network>(mapped_mig);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
store<klut_network>().extend();
store<klut_network>().current() = klut;
} else if (is_set("xag")) {
/* derive some XAG */
assert(store<xag_network>().size() > 0);
begin = clock();
xag_network xag = store<xag_network>().current();
mapping_view<xag_network, true> mapped_xag{xag};
ps.cut_enumeration_ps.cut_size = cut_size;
lut_mapping<mapping_view<xag_network, true>, true>(mapped_xag, ps);
/* collapse into k-LUT network */
const auto klut = *collapse_mapped_network<klut_network>(mapped_xag);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
store<klut_network>().extend();
store<klut_network>().current() = klut;
} else if (is_set("klut")) {
/* derive some kLUT */
assert(store<klut_network>().size() > 0);
begin = clock();
klut_network klut = store<klut_network>().current();
mapping_view<klut_network, true> mapped_klut{klut};
ps.cut_enumeration_ps.cut_size = cut_size;
lut_mapping<mapping_view<klut_network, true>, true>(mapped_klut, ps);
/* collapse into k-LUT network */
const auto klut_new = *collapse_mapped_network<klut_network>(mapped_klut);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
store<klut_network>().extend();
store<klut_network>().current() = klut_new;
} else {
if (store<aig_network>().size() == 0) {
assert(false && "Error: Empty AIG network\n");
}
/* derive some AIG */
aig_network aig = store<aig_network>().current();
begin = clock();
mapping_view<aig_network, true> mapped_aig{aig};
/* LUT mapping */
if (is_set("satlut")) {
satlut_mapping_params ps;
ps.cut_enumeration_ps.cut_size = cut_size;
satlut_mapping<mapping_view<aig_network, true>, true>(mapped_aig, ps);
} else {
ps.cut_enumeration_ps.cut_size = cut_size;
lut_mapping<mapping_view<aig_network, true>, true,
cut_enumeration_mf_cut>(mapped_aig, ps);
}
/* collapse into k-LUT network */
const auto klut = *collapse_mapped_network<klut_network>(mapped_aig);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
store<klut_network>().extend();
store<klut_network>().current() = klut;
}
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
unsigned cut_size = 4u;
};
ALICE_ADD_COMMAND(lut_mapping, "Mapping")
} // namespace alice
#endif

View File

@ -1,157 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2022 */
/**
* @file lutmap.hpp
*
* @brief performs FPGA technology mapping of the network
*
* @author Homyoung
* @since 2022/12/21
*/
#ifndef LUTMAP_HPP
#define LUTMAP_HPP
#include <mockturtle/generators/arithmetic.hpp>
#include <mockturtle/networks/aig.hpp>
#include <mockturtle/traits.hpp>
#include <mockturtle/views/mapping_view.hpp>
#include "../core/lut_mapper.hpp"
using namespace std;
using namespace mockturtle;
namespace alice {
class lutmap_command : public command {
public:
explicit lutmap_command(const environment::ptr& env)
: command(env, "FPGA technology mapping of the network [default = AIG]") {
add_flag("--mig, -m", "FPGA technology mapping for MIG");
add_flag("--xag, -g", "FPGA technology mapping for XAG");
add_flag("--xmg, -x", "FPGA technology mapping for XMG");
add_option("--cut_size, -s", cut_size,
"Maximum number of leaves for a cut [default = 4]");
add_option(
"--cut_limit, -l", cut_limit,
"the input Maximum number of cuts for a node name [default = 25]");
add_option("--relax_required, -r", relax_required,
"delay relaxation ratio (%) [default = 0]");
add_flag("--area, -a", "toggles area-oriented mapping [default = false]");
add_flag("--recompute_cuts, -c",
"recompute cuts at each step [default = true]");
add_flag("--edge, -e", "Use edge count reduction [default = true]");
add_flag("--cost_function, -f",
"LUT map with cost function [default = false]");
add_flag("--dominated_cuts, -d",
"Remove the cuts that are contained in others [default = true]");
add_flag("--verbose, -v", "print the information");
}
protected:
struct lut_custom_cost {
std::pair<uint32_t, uint32_t> operator()(uint32_t num_leaves) const {
if (num_leaves < 2u) return {0u, 0u};
return {num_leaves, 1u}; /* area, delay */
}
std::pair<uint32_t, uint32_t> operator()(
kitty::dynamic_truth_table const& tt) const {
if (tt.num_vars() < 2u) return {0u, 0u};
return {tt.num_vars(), 1u}; /* area, delay */
}
};
void execute() {
if (is_set("mig")) {
if (store<mig_network>().size() == 0u)
std::cerr << "Error: Empty MIG network\n";
else {
auto mig = store<mig_network>().current();
mapping_view mapped_mig{mig};
phyLS::lut_map_params ps;
if (is_set("area")) ps.area_oriented_mapping = true;
if (is_set("relax_required")) ps.relax_required = relax_required;
if (is_set("cut_size")) ps.cut_enumeration_ps.cut_size = cut_size;
if (is_set("cut_limit")) ps.cut_enumeration_ps.cut_limit = cut_limit;
if (is_set("recompute_cuts")) ps.recompute_cuts = false;
if (is_set("edge")) ps.edge_optimization = false;
if (is_set("dominated_cuts")) ps.remove_dominated_cuts = false;
cout << "Mapped MIG into " << cut_size << "-LUT : ";
phyLS::lut_map(mapped_mig, ps);
mapped_mig.clear_mapping();
}
} else if (is_set("xag")) {
if (store<xag_network>().size() == 0u)
std::cerr << "Error: Empty XAG network\n";
else {
auto xag = store<xag_network>().current();
mapping_view mapped_xag{xag};
phyLS::lut_map_params ps;
if (is_set("area")) ps.area_oriented_mapping = true;
if (is_set("relax_required")) ps.relax_required = relax_required;
if (is_set("cut_size")) ps.cut_enumeration_ps.cut_size = cut_size;
if (is_set("cut_limit")) ps.cut_enumeration_ps.cut_limit = cut_limit;
if (is_set("recompute_cuts")) ps.recompute_cuts = false;
if (is_set("edge")) ps.edge_optimization = false;
if (is_set("dominated_cuts")) ps.remove_dominated_cuts = false;
cout << "Mapped XAG into " << cut_size << "-LUT : ";
phyLS::lut_map(mapped_xag, ps);
mapped_xag.clear_mapping();
}
} else if (is_set("xmg")) {
if (store<xmg_network>().size() == 0u)
std::cerr << "Error: Empty XMG network\n";
else {
auto xmg = store<xmg_network>().current();
mapping_view mapped_xmg{xmg};
phyLS::lut_map_params ps;
if (is_set("area")) ps.area_oriented_mapping = true;
if (is_set("relax_required")) ps.relax_required = relax_required;
if (is_set("cut_size")) ps.cut_enumeration_ps.cut_size = cut_size;
if (is_set("cut_limit")) ps.cut_enumeration_ps.cut_limit = cut_limit;
if (is_set("recompute_cuts")) ps.recompute_cuts = false;
if (is_set("edge")) ps.edge_optimization = false;
if (is_set("dominated_cuts")) ps.remove_dominated_cuts = false;
cout << "Mapped XMG into " << cut_size << "-LUT : ";
phyLS::lut_map(mapped_xmg, ps);
mapped_xmg.clear_mapping();
}
} else {
if (store<aig_network>().size() == 0u)
std::cerr << "Error: Empty AIG network\n";
else {
auto aig = store<aig_network>().current();
mapping_view<aig_network, true> mapped_aig{aig};
phyLS::lut_map_params ps;
if (is_set("area")) ps.area_oriented_mapping = true;
if (is_set("relax_required")) ps.relax_required = relax_required;
if (is_set("cut_size")) ps.cut_enumeration_ps.cut_size = cut_size;
if (is_set("cut_limit")) ps.cut_enumeration_ps.cut_limit = cut_limit;
if (is_set("recompute_cuts")) ps.recompute_cuts = false;
if (is_set("edge")) ps.edge_optimization = false;
if (is_set("dominated_cuts")) ps.remove_dominated_cuts = false;
cout << "Mapped AIG into " << cut_size << "-LUT : ";
if (is_set("cost_function"))
phyLS::lut_map<decltype(mapped_aig), true, lut_custom_cost>(
mapped_aig, ps);
else
phyLS::lut_map(mapped_aig, ps);
mapped_aig.clear_mapping();
}
}
}
private:
uint32_t cut_size{6u};
uint32_t cut_limit{8u};
uint32_t relax_required{0u};
};
ALICE_ADD_COMMAND(lutmap, "Mapping")
} // namespace alice
#endif

View File

@ -1,127 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2022 */
/**
* @file node_resynthesis.hpp
*
* @brief Node resynthesis
*
* @author Homyoung
* @since 2022/12/14
*/
#ifndef NODE_RESYNTHESIS_HPP
#define NODE_RESYNTHESIS_HPP
#include <time.h>
#include <algorithm>
#include <kitty/constructors.hpp>
#include <kitty/dynamic_truth_table.hpp>
#include <mockturtle/algorithms/node_resynthesis.hpp>
#include <mockturtle/algorithms/node_resynthesis/akers.hpp>
#include <mockturtle/algorithms/node_resynthesis/direct.hpp>
#include <mockturtle/algorithms/node_resynthesis/mig_npn.hpp>
#include <mockturtle/algorithms/node_resynthesis/xmg_npn.hpp>
#include <mockturtle/algorithms/simulation.hpp>
#include <mockturtle/networks/aig.hpp>
#include <mockturtle/networks/klut.hpp>
#include <mockturtle/networks/mig.hpp>
#include <mockturtle/networks/xag.hpp>
#include <mockturtle/networks/xmg.hpp>
#include "../core/misc.hpp"
using namespace std;
using namespace mockturtle;
namespace alice {
class resyn_command : public command {
public:
explicit resyn_command(const environment::ptr& env)
: command(env,
"performs technology-independent restructuring [default = MIG]") {
add_flag("--xmg, -x", "Resubstitution for XMG");
add_flag("--xag, -g", "Resubstitution for XAG");
add_flag("--aig, -a", "Resubstitution for AIG");
add_flag("--direct, -d", "Node resynthesis with direct synthesis");
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
if (store<klut_network>().size() == 0u)
std::cerr << "Error: Empty k-LUT network\n";
else {
auto klut = store<klut_network>().current();
if (is_set("xmg")) {
begin = clock();
if (is_set("direct")) {
direct_resynthesis<xmg_network> xmg_resyn;
const auto xmg = node_resynthesis<xmg_network>(klut, xmg_resyn);
store<xmg_network>().extend();
store<xmg_network>().current() = cleanup_dangling(xmg);
phyLS::print_stats(xmg);
} else {
xmg_npn_resynthesis resyn;
const auto xmg = node_resynthesis<xmg_network>(klut, resyn);
store<xmg_network>().extend();
store<xmg_network>().current() = cleanup_dangling(xmg);
phyLS::print_stats(xmg);
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
} else if (is_set("xag")) {
begin = clock();
xag_npn_resynthesis<xag_network> resyn;
const auto xag = node_resynthesis<xag_network>(klut, resyn);
store<xag_network>().extend();
store<xag_network>().current() = cleanup_dangling(xag);
phyLS::print_stats(xag);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
} else if (is_set("aig")) {
begin = clock();
exact_resynthesis_params ps;
ps.cache = std::make_shared<exact_resynthesis_params::cache_map_t>();
exact_aig_resynthesis<aig_network> exact_resyn(false, ps);
node_resynthesis_stats nrst;
dsd_resynthesis<aig_network, decltype(exact_resyn)> resyn(exact_resyn);
const auto aig = node_resynthesis<aig_network>(klut, resyn, {}, &nrst);
store<aig_network>().extend();
store<aig_network>().current() = cleanup_dangling(aig);
phyLS::print_stats(aig);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
} else {
begin = clock();
if (is_set("direct")) {
direct_resynthesis<mig_network> mig_resyn;
const auto mig = node_resynthesis<mig_network>(klut, mig_resyn);
store<mig_network>().extend();
store<mig_network>().current() = cleanup_dangling(mig);
phyLS::print_stats(mig);
} else {
mig_npn_resynthesis resyn;
const auto mig = node_resynthesis<mig_network>(klut, resyn);
store<mig_network>().extend();
store<mig_network>().current() = cleanup_dangling(mig);
phyLS::print_stats(mig);
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
}
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(3) << totalTime << " s" << endl;
}
}
};
ALICE_ADD_COMMAND(resyn, "Synthesis")
} // namespace alice
#endif

View File

@ -1,515 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file ps2.hpp
*
* @brief Show statistics in the stored network
*
* @author Homyoung
* @since 2023/11/16
*/
#ifndef PS2_HPP
#define PS2_HPP
#include <../core/ps2.hpp>
namespace alice {
using namespace mockturtle;
class ps2_command : public command {
public:
explicit ps2_command(const environment::ptr& env)
: command(env, "Show statistics in the stored network.") {
add_flag("--aig,-a", "Display stats for stored AIG");
add_flag("--mig,-m", "Display stats for stored MIG");
add_flag("--xag,-g", "Display stats for stored XAG");
add_flag("--xmg,-x", "Display stats for stored XMG");
add_flag("--criti,-c", "Display critical path node index and gate");
add_flag("--fanout,-f", "Display fanout histogram");
add_flag("--cone,-o", "Dispaly logic cones from PO to PI(only for AIG)");
add_flag("--level,-l", "Display level histigram");
add_flag("--skip,-k", "Display skip histogram");
}
template <typename network>
void dump_stats(std::string name) {
if (store<network>().empty()) {
env->err() << "[e] " << name << " network not stored\n";
return;
}
auto ntk = store<network>().current();
mockturtle::depth_view dag_depth{ntk};
/*critical_path*/
phyLS::critical_node_view<mockturtle::names_view<network>> critical{ntk};
auto critical_path = critical.get_critical_path();
auto critical_nums = critical.get_critical_nums();
phyLS::function_counts counts;
for (auto curr_node : critical_path) {
update_counts(counts, ntk, curr_node);
}
/*fanin_histogram*/
mockturtle::fanout_view<network> fanout{ntk};
uint32_t times = 0;
fanout.foreach_node([&](auto node) {
bool pure = true;
fanout.foreach_fanin(node, [&](auto fi) {
uint32_t focount = 0;
auto node = fanout.get_node(fi);
fanout.foreach_fanout(node, [&](auto fo) { focount++; });
bool isolated_fanin = (focount == 1) ? 1 : 0;
pure = pure && (fanout.is_constant(node) || isolated_fanin);
});
if (!pure) times++;
});
/*fanout_histogram*/
std::vector<int> fanout_vec;
double average_fanout = 0;
fanout.foreach_node([&](auto node) {
uint32_t foc = 0;
if (ntk.is_constant(node)) return;
fanout.foreach_fanout(node, [&](auto fo) { foc++; });
fanout_vec.emplace_back(foc);
if (foc > max_fanout) {
max_fanout = foc;
}
});
int po = 0;
fanout.foreach_po([&](auto o) { po++; });
average_fanout = std::accumulate(fanout_vec.begin(), fanout_vec.end(), 0.0,
[](double acc, int i) {
return acc + static_cast<double>(i);
}) /
(fanout_vec.size() - 1 - po);
/*function_stats*/
phyLS::function_counts counts1 = phyLS::node_functions(ntk);
/*skip_histogram*/
std::vector<uint32_t> skip_histogram(dag_depth.depth(), 0);
uint32_t mismatch_levels = 0;
fanout.foreach_node([&](auto node) {
uint32_t last_level = 0;
bool mismatched = false;
fanout.foreach_fanout(node, [&](auto f) {
if (last_level != 0 && last_level != dag_depth.level(f)) {
mismatched = true;
}
last_level = dag_depth.level(f);
uint32_t skip = dag_depth.level(f) - dag_depth.level(node);
skip_histogram[skip]++;
});
if (mismatched) {
mismatch_levels++;
}
});
int max_skip = 0;
double average_skip = 0.0;
double dividend = 0.0;
double divisor = 0.0;
for (int i = 0; i < skip_histogram.size(); i++) {
dividend += i * skip_histogram[i];
divisor += skip_histogram[i];
}
average_skip = dividend / divisor;
max_skip = skip_histogram.size() - 1;
env->out() << "************************************************************"
"*******************\n"
<< "* Statistic information "
" *\n"
<< "************************************************************"
"*******************\n"
<< std::setw(2) << std::left << " " << std::setw(70) << std::left
<< "Total size of critical path nodes : " << std::setw(5)
<< std::left << critical_path.size() << "\n"
<< std::setw(2) << std::left << " " << std::setw(70) << std::left
<< "Number of critical paths : " << std::setw(5) << std::left
<< critical_nums << "\n"
<< std::setw(2) << std::left << " " << std::setw(70) << std::left
<< "Number of pure nodes (at least one child node has multiple "
"fanouts) : "
<< std::setw(5) << std::left << times << "\n"
<< "------------------------------------------------------------"
"-------------------\n"
<< " +Node fanout : "
<< "\n"
<< std::setw(3) << std::left << " "
<< "| Max Fanout | = " << max_fanout << std::setw(10) << " "
<< "| Average Fanout | = " << average_fanout << "\n"
<< "------------------------------------------------------------"
"-------------------\n"
<< " +Function_statistic : "
<< "\n";
std::cout << std::setw(3) << " " << std::setfill('-') << std::setw(61) << ""
<< std::setfill(' ') << std::endl;
std::cout << std::setw(3) << " "
<< "| " << std::left << std::setw(4) << "Name"
<< " |" << std::setw(4) << "MAJ"
<< " |" << std::setw(4) << "AND"
<< " |" << std::setw(4) << "OR"
<< " |" << std::setw(4) << "XOR3"
<< " |" << std::setw(4) << "XOR"
<< " |" << std::setw(4) << "XNOR"
<< " |" << std::setw(7) << "Unknown"
<< " |" << std::setw(7) << "Input"
<< " |" << std::endl;
std::cout << std::setw(3) << " " << std::setfill('-') << std::setw(61) << ""
<< std::setfill(' ') << std::endl;
std::cout
<< std::setw(3) << " "
<< "| " << std::left << std::setw(4) << "nums"
<< " |" << std::setw(4)
<< (counts1.maj_num == 0 ? " / " : std::to_string(counts1.maj_num))
<< " |" << std::setw(4)
<< (counts1.and_num == 0 ? " / " : std::to_string(counts1.and_num))
<< " |" << std::setw(4)
<< (counts1.or_num == 0 ? " / " : std::to_string(counts1.or_num))
<< " |" << std::setw(4)
<< (counts1.xor3_num == 0 ? " / " : std::to_string(counts1.xor3_num))
<< " |" << std::setw(4)
<< (counts1.xor_num == 0 ? " / " : std::to_string(counts1.xor_num))
<< " |" << std::setw(4)
<< (counts1.xnor_num == 0 ? " / " : std::to_string(counts1.xnor_num))
<< " |" << std::setw(7)
<< (counts1.unknown_num == 0 ? " / "
: std::to_string(counts1.unknown_num))
<< " |" << std::setw(7)
<< (counts1.input_num == 0 ? " / " : std::to_string(counts1.input_num))
<< " |" << std::endl;
std::cout << std::setw(3) << " " << std::setfill('-') << std::setw(61) << ""
<< std::setfill(' ') << std::endl;
std::cout << "-------------------------------------------------------------"
"------------------\n";
std::cout << " +Skip level : "
<< "\n"
<< " | Number of nodes with inconsistent levels of fanout "
"nodes (skip) : "
<< mismatch_levels << "\n"
<< std::setw(3) << std::left << " "
<< "| Max skip Level | = " << max_skip << std::setw(10) << " "
<< "| Average skip Level | = " << average_skip << "\n";
}
template <typename network>
void critical_path(std::string name) {
if (store<network>().empty()) return;
auto ntk = store<network>().current();
phyLS::critical_node_view<mockturtle::names_view<network>> c{ntk};
auto cp = c.get_critical_path();
phyLS::function_counts cou;
for (auto it : cp) {
update_counts(cou, ntk, it);
}
std::cout << " +Node in critical paths : "
<< "\n";
for (auto it : cp) {
std::cout << std::setw(3) << " ";
std::cout << ntk.node_to_index(it) << " ";
}
std::cout << std::endl;
std::cout << " +Node type in critical paths : "
<< "\n";
std::cout << std::setw(3) << " " << std::setfill('-') << std::setw(61) << ""
<< std::setfill(' ') << std::endl;
std::cout << std::setw(3) << " "
<< "| " << std::left << std::setw(4) << "Name"
<< " |" << std::setw(4) << "MAJ"
<< " |" << std::setw(4) << "AND"
<< " |" << std::setw(4) << "OR"
<< " |" << std::setw(4) << "XOR3"
<< " |" << std::setw(4) << "XOR"
<< " |" << std::setw(4) << "XNOR"
<< " |" << std::setw(7) << "Unknown"
<< " |" << std::setw(7) << "Input"
<< " |" << std::endl;
std::cout << std::setw(3) << " " << std::setfill('-') << std::setw(61) << ""
<< std::setfill(' ') << std::endl;
std::cout << std::setw(3) << " "
<< "| " << std::left << std::setw(4) << "nums"
<< " |" << std::setw(4)
<< (cou.maj_num == 0 ? " / " : std::to_string(cou.maj_num))
<< " |" << std::setw(4)
<< (cou.and_num == 0 ? " /" : std::to_string(cou.and_num)) << " |"
<< std::setw(4)
<< (cou.or_num == 0 ? " /" : std::to_string(cou.or_num)) << " |"
<< std::setw(4)
<< (cou.xor3_num == 0 ? " /" : std::to_string(cou.xor3_num))
<< " |" << std::setw(4)
<< (cou.xor_num == 0 ? " /" : std::to_string(cou.xor_num)) << " |"
<< std::setw(4)
<< (cou.xnor_num == 0 ? " /" : std::to_string(cou.xnor_num))
<< " |" << std::setw(7)
<< (cou.unknown_num == 0 ? " /" : std::to_string(cou.unknown_num))
<< " |" << std::setw(7)
<< (cou.input_num == 0 ? " /" : std::to_string(cou.input_num))
<< " |" << std::endl;
std::cout << std::setw(3) << " " << std::setfill('-') << std::setw(61) << ""
<< std::setfill(' ') << std::endl;
}
template <typename network>
void fanout_histogram(std::string name) {
if (store<network>().empty()) return;
auto ntk = store<network>().current();
mockturtle::fanout_view<network> fanoutP{ntk};
std::vector<uint32_t> fanout_histogram(max_fanout + 1, 0);
fanoutP.foreach_node([&](auto node) {
uint32_t foc = 0;
if (ntk.is_constant(node)) return;
fanoutP.foreach_fanout(node, [&](auto fo) { foc++; });
if (foc >= fanout_histogram.size() - 1) {
fanout_histogram[fanout_histogram.size() - 1]++;
} else {
fanout_histogram[foc]++;
}
});
std::cout << " +Node counts by number of fanouts." << std::endl;
std::cout << std::setw(3) << " " << std::setfill('-') << std::setw(22) << ""
<< std::setfill(' ') << std::endl;
std::cout << std::setw(3) << " "
<< "| " << std::left << std::setw(10) << "Fanout" << std::right
<< " | " << std::setw(5) << "Nodes"
<< " |" << std::endl;
std::cout << std::setw(3) << " " << std::setfill('-') << std::setw(22) << ""
<< std::setfill(' ') << std::endl;
for (int i = 0; i < fanout_histogram.size(); i++) {
if (fanout_histogram[i] == 0) continue;
std::cout << std::setw(3) << " "
<< "| " << std::left << std::setw(10) << i << std::right
<< " | " << std::setw(5) << fanout_histogram[i] << " |"
<< std::endl;
}
std::cout << std::setw(3) << " " << std::setfill('-') << std::setw(22) << ""
<< std::setfill(' ') << std::endl;
}
template <typename network>
void get_cones(std::string name) {
if (!store<network>().empty()) {
auto aig = store<network>().current();
// map with number of nodes in each logical cone
std::unordered_map<int, int> po_nodes;
// number of inputs for each cone
std::unordered_map<int, int> po_ins;
// first processing logical cones for POs
std::cout << " +Logic cones from PO2PI." << std::endl;
std::cout << std::setw(3) << " " << std::setfill('-') << std::setw(44)
<< "" << std::setfill(' ') << std::endl;
std::cout << std::setw(3) << " "
<< "| " << std::left << std::setw(10) << "Name" << std::right
<< " | " << std::setw(5) << "Index"
<< " |" << std::setw(5) << "Nodes"
<< " |" << std::setw(5) << "Level"
<< " |" << std::setw(6) << "Inputs"
<< " |" << std::endl;
std::cout << std::setw(3) << " " << std::setfill('-') << std::setw(44)
<< "" << std::setfill(' ') << std::endl;
for (int outIndex = 0; outIndex < aig.num_pos(); outIndex++) {
aig.foreach_node([&](auto node) {
// set all nodes as not visited
aig._storage->nodes[node].data[1].h1 = 0;
});
// start counter for a given output index
po_nodes.insert(std::make_pair(outIndex, 0));
// starting the counter of inputs
po_ins.insert(std::make_pair(outIndex, 0));
// calculate the index of the node driving the output
auto inIdx = aig._storage->outputs[outIndex].data;
if (aig._storage->outputs[outIndex].data & 1) {
inIdx = aig._storage->outputs[outIndex].data - 1;
}
inIdx = inIdx >> 1;
// call DFS
phyLS::compute_cone(aig, inIdx, po_nodes, outIndex, po_ins);
aig.foreach_node([&](auto node) {
// set all nodes as not visited
aig._storage->nodes[node].data[1].h1 = 0;
});
int level = phyLS::computeLevel<network>(aig, inIdx);
int nodes = 0;
int inputs = 0;
// for each output prints index, nodes, depth and number of inputs,
// respectively
std::unordered_map<int, int>::iterator it;
it = po_nodes.find(outIndex);
if (it != po_nodes.end()) nodes = it->second;
std::unordered_map<int, int>::iterator init;
init = po_ins.find(outIndex);
if (it != po_ins.end()) inputs = init->second;
std::cout << std::setw(3) << " "
<< "| " << std::left << std::setw(10) << "Output"
<< std::right << " | " << std::setw(5) << outIndex << " |"
<< std::setw(5) << nodes << " |" << std::setw(5) << level
<< " |" << std::setw(6) << inputs << " |" << std::endl;
}
std::cout << std::setw(3) << " " << std::setfill('-') << std::setw(44)
<< "" << std::setfill(' ') << std::endl;
} else {
env->err() << "There is not an AIG network stored.\n";
}
}
template <typename ntk>
void level_size(std::string name) {
if (store<ntk>().empty()) {
env->err() << name << " network not stored\n";
return;
}
auto dag = store<ntk>().current();
mockturtle::depth_view dag_view(dag);
std::vector<uint32_t> levels(dag_view.depth() + 1, 0);
dag_view.foreach_node([&](auto node) { levels[dag_view.level(node)]++; });
std::cout << " +Nodes per level." << std::endl;
std::cout << std::setw(3) << " " << std::setfill('-') << std::setw(22) << ""
<< std::setfill(' ') << std::endl;
std::cout << std::setw(3) << " "
<< "| " << std::left << std::setw(10) << "Level" << std::right
<< " | " << std::setw(5) << "Nodes"
<< " |" << std::endl;
std::cout << std::setw(3) << " " << std::setfill('-') << std::setw(22) << ""
<< std::setfill(' ') << std::endl;
for (int i = 0; i < levels.size(); i++) {
std::cout << std::setw(3) << " "
<< "| " << std::left << std::setw(10) << i << std::right
<< " | " << std::setw(5) << levels[i] << " |" << std::endl;
}
std::cout << std::setw(3) << " " << std::setfill('-') << std::setw(22) << ""
<< std::setfill(' ') << std::endl;
}
template <typename ntk>
void skip_histogram(std::string name) {
if (!store<ntk>().empty()) {
auto dag = store<ntk>().current();
mockturtle::depth_view dag_depth{dag};
mockturtle::fanout_view dag_fanout{dag};
std::vector<uint32_t> skip_histogram(dag_depth.depth(), 0);
uint32_t mismatch_levels = 0;
dag_fanout.foreach_node([&](auto node) {
uint32_t last_level = 0;
bool mismatched = false;
dag_fanout.foreach_fanout(node, [&](auto f) {
if (last_level != 0 && last_level != dag_depth.level(f)) {
mismatched = true;
}
last_level = dag_depth.level(f);
uint32_t skip = dag_depth.level(f) - dag_depth.level(node);
skip_histogram[skip]++;
});
if (mismatched) {
mismatch_levels++;
}
});
std::cout << " +Nodes whose fanout skip levels : " << mismatch_levels
<< std::endl;
std::cout << std::setw(3) << " " << std::setfill('-') << std::setw(22)
<< "" << std::setfill(' ') << std::endl;
std::cout << std::setw(3) << " "
<< "| " << std::left << std::setw(11) << "Skip_levels"
<< std::right << " | " << std::setw(5) << "Nodes"
<< " |" << std::endl;
std::cout << std::setw(3) << " " << std::setfill('-') << std::setw(22)
<< "" << std::setfill(' ') << std::endl;
for (int i = 0; i < skip_histogram.size(); i++) {
std::cout << std::setw(3) << " "
<< "| " << std::left << std::setw(11) << i << std::right
<< " | " << std::setw(5) << skip_histogram[i] << " |"
<< std::endl;
}
std::cout << std::setw(3) << " " << std::setfill('-') << std::setw(22)
<< "" << std::setfill(' ') << std::endl;
} else {
env->err() << "There is not an " << name << " network stored.\n";
}
}
protected:
void execute() {
if (is_set("mig")) {
dump_stats<mockturtle::mig_network>("MIG");
if (is_set("criti")) {
critical_path<mockturtle::mig_network>("MIG");
}
if (is_set("fanout")) {
fanout_histogram<mockturtle::mig_network>("MIG");
}
if (is_set("level")) {
level_size<mockturtle::mig_network>("MIG");
}
if (is_set("skip")) {
skip_histogram<mockturtle::mig_network>("MIG");
}
return;
} else if (is_set("xag")) {
dump_stats<mockturtle::xag_network>("XAG");
if (is_set("criti")) {
critical_path<mockturtle::xag_network>("XAG");
}
if (is_set("fanout")) {
fanout_histogram<mockturtle::xag_network>("XAG");
}
if (is_set("level")) {
level_size<mockturtle::xag_network>("XAG");
}
if (is_set("skip")) {
skip_histogram<mockturtle::xag_network>("XAG");
}
return;
} else if (is_set("xmg")) {
dump_stats<mockturtle::xmg_network>("XMG");
if (is_set("criti")) {
critical_path<mockturtle::xmg_network>("XMG");
}
if (is_set("fanout")) {
fanout_histogram<mockturtle::xmg_network>("XMG");
}
if (is_set("level")) {
level_size<mockturtle::xmg_network>("XMG");
}
if (is_set("skip")) {
skip_histogram<mockturtle::xmg_network>("XMG");
}
return;
} else if (is_set("aig")) {
dump_stats<mockturtle::aig_network>("AIG");
} else {
// default
dump_stats<mockturtle::aig_network>("AIG");
}
if (is_set("criti")) {
critical_path<mockturtle::aig_network>("AIG");
}
if (is_set("fanout")) {
fanout_histogram<mockturtle::aig_network>("AIG");
}
if (is_set("cone")) {
get_cones<mockturtle::aig_network>("AIG");
}
if (is_set("level")) {
level_size<mockturtle::aig_network>("AIG");
}
if (is_set("skip")) {
skip_histogram<mockturtle::aig_network>("AIG");
}
}
private:
int max_fanout = 0;
};
ALICE_ADD_COMMAND(ps2, "General");
} // namespace alice
#endif

View File

@ -1,136 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2022 */
/**
* @file aig_balancing.hpp
*
* @brief performs technology-independent refactoring
*
* @author Homyoung
* @since 2022/12/14
*/
#ifndef REFACTOR_HPP
#define REFACTOR_HPP
#include <mockturtle/algorithms/node_resynthesis/akers.hpp>
#include <mockturtle/algorithms/node_resynthesis/bidecomposition.hpp>
#include <mockturtle/algorithms/node_resynthesis/mig_npn.hpp>
#include <mockturtle/algorithms/refactoring.hpp>
#include <mockturtle/networks/mig.hpp>
#include <mockturtle/networks/xag.hpp>
#include <mockturtle/traits.hpp>
#include "../core/misc.hpp"
using namespace mockturtle;
using namespace std;
namespace alice {
class refactor_command : public command {
public:
explicit refactor_command(const environment::ptr& env)
: command(env,
"performs technology-independent refactoring [default = AIG]") {
add_flag("--mig, -m", "refactoring for MIG");
add_flag("--xag, -g", "refactoring for XAG");
add_flag("--xmg, -x", "refactoring for XMG");
add_flag("--akers, -a", "Refactoring with Akers synthesis for MIG");
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime = 0.0;
if (is_set("mig")) {
if (store<mig_network>().size() == 0u)
std::cerr << "Error: Empty MIG network\n";
else {
auto mig = store<mig_network>().current();
begin = clock();
if (is_set("akers")) {
akers_resynthesis<mig_network> resyn;
refactoring_params ps;
ps.max_pis = 4u;
refactoring(mig, resyn, ps);
} else {
mig_npn_resynthesis resyn;
refactoring_params ps;
ps.max_pis = 4u;
refactoring(mig, resyn, ps);
}
mig = cleanup_dangling(mig);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
phyLS::print_stats(mig);
store<mig_network>().extend();
store<mig_network>().current() = mig;
}
} else if (is_set("xag")) {
if (store<xag_network>().size() == 0u)
std::cerr << "Error: Empty XAG network\n";
else {
auto xag = store<xag_network>().current();
begin = clock();
bidecomposition_resynthesis<xag_network> resyn;
refactoring_params ps;
ps.max_pis = 4u;
refactoring(xag, resyn, ps);
xag = cleanup_dangling(xag);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
phyLS::print_stats(xag);
store<xag_network>().extend();
store<xag_network>().current() = xag;
}
} else if (is_set("xmg")) {
if (store<xmg_network>().size() == 0u)
std::cerr << "Error: Empty XMG network\n";
else {
auto xmg = store<xmg_network>().current();
begin = clock();
xmg_npn_resynthesis resyn;
refactoring_params ps;
ps.max_pis = 4u;
refactoring(xmg, resyn, ps);
xmg = cleanup_dangling(xmg);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
phyLS::print_stats(xmg);
store<xmg_network>().extend();
store<xmg_network>().current() = xmg;
}
} else {
if (store<aig_network>().size() == 0u)
std::cerr << "Error: Empty AIG network\n";
else {
auto aig = store<aig_network>().current();
begin = clock();
direct_resynthesis<aig_network> aig_resyn;
refactoring_params ps;
ps.max_pis = 4u;
refactoring(aig, aig_resyn, ps);
aig = cleanup_dangling(aig);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
phyLS::print_stats(aig);
store<aig_network>().extend();
store<aig_network>().current() = aig;
}
}
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
};
ALICE_ADD_COMMAND(refactor, "Synthesis")
} // namespace alice
#endif

View File

@ -13,25 +13,7 @@
#ifndef RESUB_HPP
#define RESUB_HPP
#include <time.h>
#include <kitty/static_truth_table.hpp>
#include <mockturtle/algorithms/aig_resub.hpp>
#include <mockturtle/algorithms/cleanup.hpp>
#include <mockturtle/algorithms/mig_resub.hpp>
#include <mockturtle/algorithms/resubstitution.hpp>
#include <mockturtle/algorithms/sim_resub.hpp>
#include <mockturtle/algorithms/simulation.hpp>
#include <mockturtle/algorithms/xag_resub_withDC.hpp>
#include <mockturtle/algorithms/xmg_resub.hpp>
#include <mockturtle/io/write_verilog.hpp>
#include <mockturtle/networks/aig.hpp>
#include <mockturtle/networks/mig.hpp>
#include <mockturtle/networks/xmg.hpp>
#include <mockturtle/traits.hpp>
#include <mockturtle/views/depth_view.hpp>
#include <mockturtle/views/fanout_view.hpp>
#include "../core/resub.hpp"
#include "../core/misc.hpp"
using namespace std;
@ -43,99 +25,20 @@ class resub_command : public command {
: command(
env,
"performs technology-independent restructuring [default = AIG]") {
add_flag("--xmg, -x", "Resubstitution for XMG");
add_flag("--mig, -m", "Resubstitution for MIG");
add_flag("--xag, -g", "Resubstitution for XAG");
add_flag("--simulation, -s", "Simulation-guided resubstitution for AIG");
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime = 0.0;
if (is_set("xmg")) {
if (store<xmg_network>().size() == 0u)
std::cerr << "Error: Empty XMG network\n";
else {
auto xmg = store<xmg_network>().current();
begin = clock();
using view_t = depth_view<fanout_view<xmg_network>>;
fanout_view<xmg_network> fanout_view{xmg};
view_t resub_view{fanout_view};
xmg_resubstitution(resub_view);
xmg = cleanup_dangling(xmg);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
phyLS::print_stats(xmg);
store<xmg_network>().extend();
store<xmg_network>().current() = xmg;
}
} else if (is_set("mig")) {
if (store<mig_network>().size() == 0u)
std::cerr << "Error: Empty MIG network\n";
else {
auto mig = store<mig_network>().current();
begin = clock();
using view_t = depth_view<fanout_view<mig_network>>;
fanout_view<mig_network> fanout_view{mig};
view_t resub_view{fanout_view};
mig_resubstitution(resub_view);
mig = cleanup_dangling(mig);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
phyLS::print_stats(mig);
store<mig_network>().extend();
store<mig_network>().current() = mig;
}
} else if (is_set("xag")) {
if (store<xag_network>().size() == 0u)
std::cerr << "Error: Empty XAG network\n";
else {
auto xag = store<xag_network>().current();
begin = clock();
resubstitution_params ps;
using view_t = depth_view<fanout_view<xag_network>>;
fanout_view<xag_network> fanout_view{xag};
view_t resub_view{fanout_view};
resubstitution_minmc_withDC(resub_view, ps);
xag = cleanup_dangling(xag);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
phyLS::print_stats(xag);
store<xag_network>().extend();
store<xag_network>().current() = xag;
}
} else {
if (store<aig_network>().size() == 0u)
std::cerr << "Error: Empty AIG network\n";
else {
auto aig = store<aig_network>().current();
if (is_set("simulation")) {
begin = clock();
sim_resubstitution(aig);
aig = cleanup_dangling(aig);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
} else {
begin = clock();
using view_t = depth_view<fanout_view<aig_network>>;
fanout_view<aig_network> fanout_view{aig};
view_t resub_view{fanout_view};
aig_resubstitution(resub_view);
aig = cleanup_dangling(aig);
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
}
phyLS::print_stats(aig);
store<aig_network>().extend();
store<aig_network>().current() = aig;
}
if (store<aig_network>().size() == 0u)
std::cerr << "Error: Empty AIG network\n";
else {
auto aig = store<aig_network>().current();
phyLS::aig_resub(aig);
phyLS::print_stats(aig);
store<aig_network>().extend();
store<aig_network>().current() = aig;
}
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
};

48
src/commands/rewrite.hpp Normal file
View File

@ -0,0 +1,48 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2022 */
/**
* @file cut_rewriting.hpp
*
* @brief on-the-fly DAG-aware logic rewriting
*
* @author Homyoung
* @since 2022/12/15
*/
#ifndef CUT_REWRITING_HPP
#define CUT_REWRITING_HPP
#include "../core/rewrite.hpp"
#include "../core/misc.hpp"
using namespace std;
using namespace mockturtle;
namespace alice {
class rewrite_command : public command {
public:
explicit rewrite_command(const environment::ptr& env)
: command(env, "on-the-fly DAG-aware logic rewriting [default = AIG]") {
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
if (store<aig_network>().size() == 0u)
std::cerr << "Error: Empty AIG network\n";
else {
auto aig = store<aig_network>().current();
phyLS::aig_rewrite(aig);
phyLS::print_stats(aig);
store<aig_network>().extend();
store<aig_network>().current() = aig;
}
}
};
ALICE_ADD_COMMAND(rewrite, "Synthesis")
} // namespace alice
#endif

View File

@ -1,155 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2022 */
/**
* @file sim.hpp
*
* @brief logic network simulation
*
* @author Homyoung
* @since 2022/12/14
*/
#ifndef SIM_HPP
#define SIM_HPP
#include <kitty/static_truth_table.hpp>
#include <mockturtle/algorithms/simulation.hpp>
using namespace std;
using namespace mockturtle;
namespace alice {
class sim_command : public command {
public:
explicit sim_command(const environment::ptr &env)
: command(env, "logic network simulation") {
add_flag("-a, --aig_network", " simulate current aig network");
add_flag("-x, --xmg_network", " simulate current xmg network");
add_flag("-l, --klut_network", " simulate current klut network");
add_flag("-p, --partial_simulate",
" simulate current logic network using partial simulator ");
add_option("--filename, -f", filename, "pre-generated patterns file");
}
protected:
void execute() {
clock_t begin, end;
double totalTime = 0.0;
if (is_set("xmg_network")) {
begin = clock();
if (is_set("partial_simulate")) {
xmg_network xmg = store<xmg_network>().current();
std::vector<kitty::partial_truth_table> pats(xmg.num_pis());
for (auto i = 0; i < xmg.num_pis(); i++)
pats[i].add_bits(0x12345678, 32);
partial_simulator sim(pats);
unordered_node_map<kitty::partial_truth_table, xmg_network>
node_to_value(xmg);
simulate_nodes(xmg, node_to_value, sim);
xmg.foreach_po([&](auto const &f) {
std::cout << "tt: 0x"
<< (xmg.is_complemented(f) ? ~node_to_value[f]
: node_to_value[f])
._bits[0]
<< std::endl;
});
} else {
xmg_network xmg = store<xmg_network>().current();
default_simulator<kitty::dynamic_truth_table> sim(xmg.num_pis());
unordered_node_map<kitty::dynamic_truth_table, xmg_network>
node_to_value(xmg);
simulate_nodes(xmg, node_to_value, sim);
xmg.foreach_gate([&](auto const &n) {
std::cout << "node " << n << " tt: " << node_to_value[n]._bits[0]
<< std::endl;
});
xmg.foreach_po([&](auto const &f) {
std::cout << "PO tt: "
<< (xmg.is_complemented(f) ? ~node_to_value[f]
: node_to_value[f])
._bits[0]
<< std::endl;
});
// const auto tt = simulate<kitty::dynamic_truth_table>( xmg, sim )[0];
// std::cout << "tt: 0x" << tt._bits[0] << std::endl;
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
} else if (is_set("aig_network")) {
begin = clock();
aig_network aig = store<aig_network>().current();
if (is_set("partial_simulate")){
partial_simulator sim(aig.num_pis(), 10000);
unordered_node_map<kitty::partial_truth_table, aig_network>
node_to_value(aig);
simulate_nodes(aig, node_to_value, sim);
// aig.foreach_gate([&](auto const &n) {
// std::cout << "node " << n << " tt: ";
// for (auto x : node_to_value[n]._bits) std::cout << x;
// std::cout << std::endl;
// });
// aig.foreach_po([&](auto const &f) {
// std::cout << "PO tt: "
// << (aig.is_complemented(f) ? ~node_to_value[f]
// : node_to_value[f])
// ._bits[0]
// << std::endl;
// });
} else {
default_simulator<kitty::dynamic_truth_table> sim(aig.num_pis());
unordered_node_map<kitty::dynamic_truth_table, aig_network> node_to_value(aig);
simulate_nodes<kitty::dynamic_truth_table>(aig, node_to_value, sim);
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
} else if (is_set("klut_network")) {
begin = clock();
klut_network klut = store<klut_network>().current();
if (is_set("partial_simulate")) {
// partial_simulator sim(klut.num_pis(), 10000);
// unordered_node_map<kitty::partial_truth_table, klut_network>
// node_to_value(klut);
// simulate_nodes(klut, node_to_value, sim);
std::vector<kitty::partial_truth_table> pats(klut.num_pis());
partial_simulator sim(pats);
std::vector<bool> pattern(klut.num_pis());
for (int i = 0; i < 10000; i++) {
for (int j = 0; j < klut.num_pis(); j++) {
pattern[j] = rand() % 2;
}
sim.add_pattern(pattern);
}
unordered_node_map<kitty::partial_truth_table, klut_network>
node_to_value(klut);
simulate_nodes(klut, node_to_value, sim);
} else {
default_simulator<kitty::dynamic_truth_table> sim(klut.num_pis());
unordered_node_map<kitty::dynamic_truth_table, klut_network>
node_to_value(klut);
simulate_nodes<kitty::dynamic_truth_table>(klut, node_to_value, sim);
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
} else {
std::cout << "At least one store should be specified, see 'sim -h' for "
"help. \n";
}
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(3) << totalTime << " s" << endl;
}
private:
string filename;
};
ALICE_ADD_COMMAND(sim, "Verification")
} // namespace alice
#endif

View File

@ -1,75 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2022 */
/**
* @file simulator.hpp
*
* @brief Semi-tensor product based logic network simulation
*
* @author Homyoung
* @since 2023/03/21
*/
#ifndef SIMULATOR_HPP
#define SIMULATOR_HPP
#include <time.h>
#include <fstream>
#include "../core/simulator/lut_parser.hpp"
#include "../core/simulator/simulator.hpp"
namespace alice {
class simulator_command : public command {
public:
explicit simulator_command(const environment::ptr &env)
: command(env, "STP-based logic network simulation") {
add_option("filename,-f", filename, "name of input file");
add_flag("--verbose, -v", "verbose output");
add_flag("--full_simulation, -t", "full simulation to get the truth table");
}
protected:
void execute() {
std::ifstream ifs(filename);
if (!ifs.good()) std::cerr << "Can't open file " << filename << std::endl;
phyLS::CircuitGraph graph;
phyLS::LutParser parser;
if (!parser.parse(ifs, graph))
std::cerr << "Can't parse file " << filename << std::endl;
clock_t begin, end;
double totalTime = 0.0;
phyLS::simulator sim(graph);
begin = clock();
if(is_set("full_simulation")){
sim.full_simulate();
}else{
sim.simulate();
}
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
if (is_set("verbose")) sim.print_simulation_result();
std::cout.setf(ios::fixed);
std::cout << "[CPU time] " << setprecision(3) << totalTime << " s"
<< std::endl;
}
private:
std::string filename;
};
ALICE_ADD_COMMAND(simulator, "Verification")
} // namespace alice
#endif

View File

@ -1,78 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file stpfr.hpp
*
* @brief STP-based functional reduction
*
* @author Homyoung
* @since 2023/03/14
*/
#ifndef STPFR_HPP
#define STPFR_HPP
#include <kitty/static_truth_table.hpp>
#include <mockturtle/algorithms/cleanup.hpp>
#include <mockturtle/algorithms/functional_reduction.hpp>
#include <mockturtle/algorithms/simulation.hpp>
#include <mockturtle/networks/aig.hpp>
#include "../core/stp_functional_reduction.hpp"
using namespace std;
using namespace mockturtle;
namespace alice {
class stpfr_command : public command {
public:
explicit stpfr_command(const environment::ptr& env)
: command(env, "STP-based functional reduction [default = AIG]") {
add_option("--tfi_node, -n", max_tfi_node,
"Maximum number of nodes in the TFI to be compared");
add_option("--filename, -f", filename, "pre-generated patterns file");
add_option("--pattern, -p", pattern, "pre-generated equivalent class file");
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
phyLS::stp_functional_reduction_params ps;
if (is_set("--filename")) ps.pattern_filename = filename;
if (is_set("--tfi_node")) ps.max_TFI_nodes = max_tfi_node;
if (is_set("--pattern")) ps.equi_classes = pattern;
if (is_set("--verbose")) {
ps.verbose = true;
}
begin = clock();
auto aig = store<aig_network>().current();
phyLS::stp_functional_reduction(aig, ps);
aig = cleanup_dangling(aig);
phyLS::print_stats(aig);
store<aig_network>().extend();
store<aig_network>().current() = aig;
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
int max_tfi_node;
string filename;
string pattern;
};
ALICE_ADD_COMMAND(stpfr, "Synthesis")
} // namespace alice
#endif

View File

@ -1,173 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2022 */
/**
* @file stpsat.hpp
*
* @brief Semi-Tensor Product based SAT
*
* @author Homyoung
* @since 2022/12/14
*/
#ifndef STPSAT_HPP
#define STPSAT_HPP
#include <alice/alice.hpp>
#include <mockturtle/mockturtle.hpp>
#include "../core/stp_sat.hpp"
using namespace std;
namespace alice {
class sat_command : public command {
public:
explicit sat_command(const environment::ptr &env)
: command(env, " circuit-based SAT solver") {
add_option("filename, -f", filename, "the input file name (CNF or BENCH)");
add_option("single_po, -s", strategy,
"select PO to solve (only in BENCH file)");
add_flag("--verbose, -v", "verbose output");
}
protected:
void execute() {
in.clear();
mtx.clear();
expre.clear();
tt.clear();
vec.clear();
string tmp;
string s_cnf = ".cnf";
string s_bench = ".bench";
if (filename.find(s_bench) != string::npos)
flag = 1;
else if (filename.find(s_cnf) != string::npos)
flag = 2;
if (flag == 1) {
ifstream fin_bench(filename);
if (fin_bench.is_open()) {
while (getline(fin_bench, tmp)) in.push_back(tmp);
fin_bench.close();
po = strategy;
vector<string> &it = in;
vector<vector<int>> &mtxvec = mtx;
int &po_tmp = po;
stopwatch<>::duration time{0};
if (po < 0) {
call_with_stopwatch(time,
[&]() { phyLS::cdccl_for_all(it, mtxvec); });
if (it.size() == 0)
cout << "UNSAT" << endl;
else
cout << "SAT" << endl;
if (is_set("verbose")) {
int count = 0;
cout << "SAT Result : " << endl;
for (string i : it) {
cout << i << " ";
count += 1;
if (count == 10) {
cout << endl;
count = 0;
}
}
cout << endl << "Numbers of SAT Result : " << it.size() << endl;
}
} else {
call_with_stopwatch(
time, [&]() { phyLS::cdccl_for_single_po(it, mtxvec, po_tmp); });
if (it.size() == 0)
cout << "UNSAT" << endl;
else
cout << "SAT" << endl;
if (is_set("verbose")) {
int count = 0;
cout << " SAT Result of "
<< "PO" << po << " : " << endl;
for (string i : it) {
cout << i << " ";
count += 1;
if (count == 10) {
cout << endl;
count = 0;
}
}
cout << endl << "Numbers of SAT Result : " << it.size() << endl;
}
}
cout << fmt::format("[CPU time]: {:5.4f} seconds\n", to_seconds(time));
} else {
cerr << "Cannot open input file" << endl;
}
} else if (flag == 2) {
ifstream fin_cnf(filename);
stringstream buffer;
buffer << fin_cnf.rdbuf();
string str(buffer.str());
string expression;
vector<int> expre;
for (int i = 6; i < (str.size() - 1); i++) {
expression += str[i];
if ((str[i] == ' ') || (str[i] == '\n')) {
expression.pop_back();
int intstr = atoi(expression.c_str());
expre.push_back(intstr);
expression.clear();
}
}
fin_cnf.close();
vector<int> &exp = expre;
vector<string> &t = tt;
vector<MatrixXi> &mtxvec = vec;
stopwatch<>::duration time{0};
call_with_stopwatch(time, [&]() { phyLS::stp_cnf(exp, t, mtxvec); });
if (t.size() == 0)
cout << "UNSAT" << endl;
else
cout << "SAT" << endl;
if (is_set("verbose")) {
int count = 0;
cout << "SAT Result : " << endl;
for (string i : t) {
cout << i << " ";
count += 1;
if (count == 10) {
cout << endl;
count = 0;
}
}
cout << endl << "Numbers of SAT Result : " << t.size() << endl;
}
cout << fmt::format("[CPU time]: {:5.4f} seconds\n", to_seconds(time));
}
}
private:
string filename;
string cnf;
int strategy = -1;
int po;
int flag = 0;
vector<string> in;
vector<vector<int>> mtx;
vector<int> expre;
vector<string> tt;
vector<MatrixXi> vec;
};
ALICE_ADD_COMMAND(sat, "Verification")
} // namespace alice
#endif

View File

@ -17,9 +17,6 @@
#include <mockturtle/io/genlib_reader.hpp>
#include <mockturtle/io/write_verilog.hpp>
#include <mockturtle/networks/aig.hpp>
#include <mockturtle/networks/mig.hpp>
#include <mockturtle/networks/xmg.hpp>
#include <mockturtle/properties/xmgcost.hpp>
#include <mockturtle/utils/tech_library.hpp>
#include "../core/properties.hpp"
@ -30,9 +27,6 @@ class techmap_command : public command {
public:
explicit techmap_command(const environment::ptr& env)
: command(env, "Standard cell mapping [default = AIG]") {
add_flag("--xmg, -x", "Standard cell mapping for XMG");
add_flag("--mig, -m", "Standard cell mapping for MIG");
add_flag("--lut, -l", "Standard cell mapping for k-LUT");
add_option("--output, -o", filename, "the verilog filename");
add_flag("--verbose, -v", "print the information");
}
@ -54,82 +48,18 @@ class techmap_command : public command {
mockturtle::map_params ps;
mockturtle::map_stats st;
if (is_set("xmg")) {
if (store<xmg_network>().size() == 0u)
std::cerr << "[e] no XMG in the store\n";
else {
auto xmg = store<xmg_network>().current();
xmg_gate_stats stats;
xmg_profile_gates(xmg, stats);
std::cout << "[i] ";
stats.report();
phyLS::xmg_critical_path_stats critical_stats;
phyLS::xmg_critical_path_profile_gates(xmg, critical_stats);
std::cout << "[i] ";
critical_stats.report();
auto res = mockturtle::map(xmg, lib, ps, &st);
if (is_set("output")) {
write_verilog_with_binding(res, filename);
}
std::cout << fmt::format(
"[i] Mapped XMG into #gates = {} area = {:.2f} delay = {:.2f}\n",
res.num_gates(), st.area, st.delay);
}
} else if (is_set("mig")) {
if (store<mig_network>().size() == 0u) {
std::cerr << "[e] no MIG in the store\n";
} else {
auto mig = store<mig_network>().current();
auto res = mockturtle::map(mig, lib, ps, &st);
if (is_set("output")) {
write_verilog_with_binding(res, filename);
}
std::cout << fmt::format(
"Mapped MIG into #gates = {} area = {:.2f} delay = {:.2f}\n",
res.num_gates(), st.area, st.delay);
}
} else if (is_set("lut")) {
if (store<klut_network>().size() == 0u) {
std::cerr << "[e] no k-LUT in the store\n";
} else {
auto lut = store<klut_network>().current();
auto res = mockturtle::map(lut, lib, ps, &st);
if (is_set("output")) {
write_verilog_with_binding(res, filename);
}
std::cout << fmt::format(
"Mapped k-LUT into #gates = {} area = {:.2f} delay = {:.2f}\n",
res.num_gates(), st.area, st.delay);
}
if (store<aig_network>().size() == 0u) {
std::cerr << "[e] no AIG in the store\n";
} else {
if (store<aig_network>().size() == 0u) {
std::cerr << "[e] no AIG in the store\n";
} else {
auto aig = store<aig_network>().current();
auto res = mockturtle::map(aig, lib, ps, &st);
auto aig = store<aig_network>().current();
auto res = mockturtle::map(aig, lib, ps, &st);
if (is_set("output")) write_verilog_with_binding(res, filename);
if (is_set("output")) write_verilog_with_binding(res, filename);
// std::cout << fmt::format(
// "Mapped AIG into #gates = {}, area = {:.2f}, delay = {:.2f}, "
// "power = {:.2f}\n",
// res.num_gates(), st.area, st.delay, st.power);
}
}
if (is_set("verbose")) {
st.report();
cout << "Cut enumeration stats: " << endl;
st.cut_enumeration_st.report();
std::cout << fmt::format(
"Mapped AIG into #gates = {}, area = {:.2f}, delay = {:.2f}, "
"power = {:.2f}\n",
res.num_gates(), st.area, st.delay, st.power);
}
}
};

View File

@ -1,71 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2024 */
/**
* @file to_npz.hpp
*
* @brief transforms the current network into adjacency matrix(.npz)
*
* @author Homyoung
* @since 2024/03/01
*/
#ifndef TO_NPZ_HPP
#define TO_NPZ_HPP
#include <algorithm>
#include <mockturtle/networks/aig.hpp>
#include <vector>
#include "../core/tonpz.hpp"
using namespace std;
using namespace mockturtle;
namespace alice {
class write_npz_command : public command {
public:
explicit write_npz_command(const environment::ptr& env)
: command(env, "write npz file, default: AIG") {
add_flag("--xmg_network,-x", "write xmg_network into dot files");
add_flag("--mig_network,-m", "write mig_network into dot files");
add_flag("--klut_network,-l", "write klut_network into dot files");
add_option("--csv, -c", filename_csv,
"The path to store csv file, default: ./placement/test.csv");
add_option("--def, -d", filename_def,
"The path to store def file, default: "
"./placement/mfloorplan.def & ./placement/floorplan.def");
}
protected:
void execute() {
if (is_set("xmg_network")) {
xmg_network xmg = store<xmg_network>().current();
} else if (is_set("mig_network")) {
mig_network mig = store<mig_network>().current();
} else if (is_set("klut_network")) {
klut_network klut = store<klut_network>().current();
} else {
aig_network aig = store<aig_network>().current();
if (is_set("csv")) {
phyLS::write_npz(aig, filename_csv);
} else if (is_set("def")) {
phyLS::write_def(aig, filename_def, filename_mdef);
} else {
assert(false && "At least one filename should be specified. ");
}
}
}
private:
std::string filename_csv = "./placement/test.csv";
std::string filename_def = "./placement/ploorplan.def";
std::string filename_mdef = "./placement/mfloorplan.def";
};
ALICE_ADD_COMMAND(write_npz, "I/O")
} // namespace alice
#endif

View File

@ -1,110 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file window_rewriting.hpp
*
* @brief Window rewriting
*
* @author Homyoung
* @since 2023/09/27
*/
#ifndef WINDOW_REWRITING_HPP
#define WINDOW_REWRITING_HPP
#include <mockturtle/algorithms/cleanup.hpp>
#include <mockturtle/algorithms/experimental/boolean_optimization.hpp>
#include <mockturtle/algorithms/experimental/sim_resub.hpp>
#include <mockturtle/algorithms/experimental/window_resub.hpp>
#include <mockturtle/algorithms/window_rewriting.hpp>
#include <mockturtle/networks/aig.hpp>
#include <mockturtle/networks/mig.hpp>
#include <mockturtle/networks/xag.hpp>
#include <mockturtle/networks/xmg.hpp>
#include <mockturtle/traits.hpp>
#include <mockturtle/views/depth_view.hpp>
using namespace std;
using namespace mockturtle;
using namespace mockturtle::experimental;
namespace alice {
class wr_command : public command {
public:
explicit wr_command(const environment::ptr& env)
: command(env, "window rewriting") {
add_option("cut_size, -k", cut_size,
"set the cut size from 2 to 6, default = 4");
add_option("num_levels, -l", num_levels,
"set the window level, default = 5");
add_flag("--gain, -g", "optimize until there is no gain");
add_flag("--resub, -r", "window resub");
add_flag("--mffw, -w", "MFFW rewriting");
add_flag("--verbose, -v", "print the information");
}
protected:
void execute() {
clock_t begin, end;
double totalTime;
begin = clock();
auto aig = store<aig_network>().current();
window_rewriting_params ps;
ps.cut_size = cut_size;
ps.num_levels = num_levels;
if (is_set("resub")) {
window_resub_params ps_r;
if (is_set("gain")) {
window_aig_enumerative_resub(aig, ps_r);
} else {
window_aig_heuristic_resub(aig, ps_r);
}
aig = cleanup_dangling(aig);
} else {
if (is_set("gain")) {
uint64_t const size_before{aig.num_gates()};
uint64_t size_current{};
do {
size_current = aig.num_gates();
window_rewriting_stats win_st;
window_rewriting(aig, ps, &win_st);
if (is_set("verbose")) win_st.report();
aig = cleanup_dangling(aig);
} while (aig.num_gates() < size_current);
} else if (is_set("mffw")) {
window_rewriting_stats win_st;
mffw_rewriting(aig, ps, &win_st);
aig = cleanup_dangling(aig);
} else {
window_rewriting_stats win_st;
window_rewriting(aig, ps, &win_st);
aig = cleanup_dangling(aig);
}
}
phyLS::print_stats(aig);
store<aig_network>().extend();
store<aig_network>().current() = aig;
end = clock();
totalTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout.setf(ios::fixed);
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
}
private:
unsigned cut_size = 4u;
unsigned num_levels = 5u;
};
ALICE_ADD_COMMAND(wr, "Synthesis")
} // namespace alice
#endif

View File

@ -1,64 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2022 */
/**
* @file write_dot.hpp
*
* @brief write dot files
*
* @author Homyoung
* @since 2022/12/14
*/
#ifndef WRITE_DOT_HPP
#define WRITE_DOT_HPP
#include <mockturtle/io/write_dot.hpp>
#include <mockturtle/mockturtle.hpp>
namespace alice {
class write_dot_command : public command {
public:
explicit write_dot_command(const environment::ptr &env)
: command(env, "write dot file") {
add_flag("--xmg_network,-x", "write xmg_network into dot files");
add_flag("--aig_network,-a", "write aig_network into dot files");
add_flag("--mig_network,-m", "write mig_network into dot files");
add_flag("--klut_network,-l", "write klut_network into dot files");
add_option("--filename, -f", filename,
"The path to store dot file, default: /tmp/test.dot");
}
protected:
void execute() {
if (is_set("xmg_network")) {
xmg_network xmg = store<xmg_network>().current();
write_dot(xmg, filename, gate_dot_drawer<xmg_network>{});
} else if (is_set("aig_network")) {
aig_network aig = store<aig_network>().current();
write_dot(aig, filename, gate_dot_drawer<aig_network>{});
} else if (is_set("mig_network")) {
mig_network mig = store<mig_network>().current();
write_dot(mig, filename, gate_dot_drawer<mig_network>{});
} else if (is_set("klut_network")) {
klut_network klut = store<klut_network>().current();
write_dot(klut, filename, gate_dot_drawer<klut_network>{});
} else {
assert(false && " at least one store should be specified ");
}
}
private:
std::string filename = "/tmp/test.dot";
};
ALICE_ADD_COMMAND(write_dot, "I/O")
} // namespace alice
#endif

View File

@ -1,139 +0,0 @@
/* 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

View File

@ -1,151 +0,0 @@
/* 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

View File

@ -1,64 +0,0 @@
/* 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

View File

@ -1,95 +0,0 @@
/* 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

View File

@ -1,55 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file xmginv.hpp
*
* @brief Inversion optimization of xmg
*
* @author Homyoung
* @since 2023/11/16
*/
#ifndef XMGINV_HPP
#define XMGINV_HPP
#include <mockturtle/mockturtle.hpp>
#include <mockturtle/utils/stopwatch.hpp>
#include "../../core/xmginv.hpp"
namespace alice {
class xmginv_command : public command {
public:
explicit xmginv_command(const environment::ptr& env)
: command(env, "inversion optimization of xmg") {
add_flag("--verbose, -v", "print the information");
}
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 xmg_opt;
stopwatch<>::duration time{0};
call_with_stopwatch(
time, [&]() { xmg_opt = phyLS::xmg_inv_optimization(xmg); });
store<xmg_network>().extend();
store<xmg_network>().current() = xmg_opt;
phyLS::print_stats(xmg_opt);
std::cout << fmt::format("[time]: {:5.2f} seconds\n", to_seconds(time));
}
};
ALICE_ADD_COMMAND(xmginv, "Synthesis")
} // namespace alice
#endif

View File

@ -1,75 +0,0 @@
/* 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

View File

@ -1,145 +0,0 @@
/* 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

View File

@ -1,751 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2022 */
/**
* @file abc2mockturtle.hpp
*
* @brief convert format between abc and mockturtle
*
* @author Homyoung
* @since 2023/02/27
*/
#ifndef ABC2MOCKTURTLE_HPP
#define ABC2MOCKTURTLE_HPP
#include <base/abc/abc.h>
#include <base/io/ioAbc.h>
#include <map>
#include <mockturtle/mockturtle.hpp>
#include <string>
#include <vector>
namespace phyLS {
mockturtle::aig_network aig_new;
pabc::Abc_Ntk_t* abc_ntk_;
std::map<int, std::string> pi_names;
std::map<int, std::string> po_names;
mockturtle::aig_network& abc2mockturtle_a(pabc::Abc_Ntk_t* abc_ntk_new) {
// Convert abc aig network to the aig network in also
pabc::Abc_Ntk_t* abc_ntk_aig;
abc_ntk_aig = abc_ntk_new;
mockturtle::aig_network aig;
using sig = mockturtle::aig_network::signal;
std::map<int, sig> signals;
signals.clear();
pi_names.clear();
po_names.clear();
// create also network
// process the also network primary input
int i;
pabc::Abc_Obj_t* pObj1;
for (i = 0; (i < pabc::Abc_NtkPiNum(abc_ntk_aig)) &&
(((pObj1) = pabc::Abc_NtkPi(abc_ntk_aig, i)), 1);
i++) {
sig pi = aig.create_pi();
signals.insert(std::pair<int, sig>(pObj1->Id, pi));
unsigned int a = pi.index;
pi_names.insert(std::pair<int, std::string>(a, pabc::Abc_ObjName(pObj1)));
}
// process the also network node
int j, k;
pabc::Abc_Obj_t *pNode, *pFanin1;
for (i = 0; (i < pabc::Vec_PtrSize((abc_ntk_aig)->vObjs)) &&
(((pNode) = pabc::Abc_NtkObj(abc_ntk_aig, i)), 1);
i++) {
if ((pNode) == NULL || !pabc::Abc_ObjIsNode(pNode)) {
} else {
std::vector<sig> children;
children.clear();
if (pabc::Abc_AigNodeIsConst(pabc::Abc_ObjFanin0(pNode)))
children.push_back((pNode->fCompl0)
? aig.create_not(aig.get_constant(true))
: aig.get_constant(true));
else
children.push_back(
(pNode->fCompl0)
? aig.create_not(signals[pabc::Abc_ObjFaninId0(pNode)])
: signals[pabc::Abc_ObjFaninId0(pNode)]);
if (pabc::Abc_AigNodeIsConst(pabc::Abc_ObjFanin1(pNode)))
children.push_back((pNode->fCompl1)
? aig.create_not(aig.get_constant(true))
: aig.get_constant(true));
else
children.push_back(
(pNode->fCompl1)
? aig.create_not(signals[pabc::Abc_ObjFaninId1(pNode)])
: signals[pabc::Abc_ObjFaninId1(pNode)]);
assert(children.size() == 2u);
signals.insert(std::pair<int, sig>(
pNode->Id, aig.create_and(children[0], children[1])));
}
}
// process the also network primary output
int m, n, n1;
pabc::Abc_Obj_t *pObj2, *pFanin2;
for (i = 0; (i < pabc::Abc_NtkPoNum(abc_ntk_aig)) &&
(((pObj2) = pabc::Abc_NtkPo(abc_ntk_aig, i)), 1);
i++) {
if (pabc::Abc_AigNodeIsConst(pabc::Abc_ObjFanin0(pObj2))) {
auto const o = (pObj2->fCompl0) ? aig.create_not(aig.get_constant(true))
: aig.get_constant(true);
aig.create_po(o);
} else {
auto const o = (pObj2->fCompl0)
? aig.create_not(signals[pabc::Abc_ObjFaninId0(pObj2)])
: signals[pabc::Abc_ObjFaninId0(pObj2)];
aig.create_po(o);
}
po_names.insert(std::pair<int, std::string>(i, pabc::Abc_ObjName(pObj2)));
}
aig_new = aig;
return aig_new;
}
pabc::Abc_Ntk_t* mockturtle2abc_x(const mockturtle::xmg_network& xmg) {
// Convert xmg network to the netlist network in abc
const int MAX = 3;
bool const0_created = false;
std::string constant_name = "1\'b0";
// Initialize the abc network
abc_ntk_ = pabc::Abc_NtkAlloc(pabc::ABC_NTK_NETLIST, pabc::ABC_FUNC_SOP, 1);
abc_ntk_->pName = strdup("netlist");
mockturtle::topo_view topo_xmg{xmg};
// create abc network
// process the abc network primary input
topo_xmg.foreach_pi([&](auto const& n, auto index) {
const auto index1 = topo_xmg.node_to_index(n);
unsigned int a = index1;
std::string input_name = pi_names[a];
pabc::Io_ReadCreatePi(abc_ntk_, (char*)(input_name.c_str()));
});
// process the abc network node
topo_xmg.foreach_node([&](auto n) {
if (topo_xmg.is_constant(n) || topo_xmg.is_pi(n)) return true;
auto func = topo_xmg.node_function(n);
std::string node_name = std::to_string(topo_xmg.node_to_index(n));
std::vector<std::string> children;
children.clear();
char* pNamesIn[MAX];
topo_xmg.foreach_fanin(n, [&](auto const& f) {
auto index = topo_xmg.node_to_index(topo_xmg.get_node(f));
std::string fanin_name = std::to_string(index);
if (topo_xmg.is_pi(topo_xmg.get_node(f))) {
unsigned int b = index;
children.push_back(pi_names[b]);
} else if (topo_xmg.is_constant(topo_xmg.get_node(f))) {
// process the abc network constant node
if (!const0_created) {
pabc::Abc_NtkFindOrCreateNet(abc_ntk_,
(char*)(constant_name.c_str()));
pabc::Io_ReadCreateConst(abc_ntk_, (char*)(constant_name.c_str()), 0);
const0_created = true;
}
children.push_back(constant_name);
} else
children.push_back(fanin_name);
});
for (size_t i = 0; i < children.size(); i++)
pNamesIn[i] = (char*)(children[i].c_str());
pabc::Abc_Obj_t* pNode;
pNode = pabc::Io_ReadCreateNode(abc_ntk_, (char*)(node_name.c_str()),
pNamesIn, topo_xmg.fanin_size(n));
std::string abc_func = "";
int count = 0;
for (auto cube : kitty::isop(func)) {
topo_xmg.foreach_fanin(n, [&](auto const& f, auto index) {
if (cube.get_mask(index) && topo_xmg.is_complemented(f))
cube.flip_bit(index);
});
for (auto i = 0u; i < topo_xmg.fanin_size(n); ++i)
abc_func += (cube.get_mask(i) ? (cube.get_bit(i) ? '1' : '0') : '-');
abc_func += " 1\n";
count++;
}
pabc::Abc_ObjSetData(
pNode, pabc::Abc_SopRegister((pabc::Mem_Flex_t*)abc_ntk_->pManFunc,
abc_func.c_str()));
return true;
});
// process the abc network primary output
std::vector<std::string> children1;
topo_xmg.foreach_po([&](auto const& f, auto index) {
auto a = topo_xmg.node_to_index(topo_xmg.get_node(f));
std::string fanin_name = std::to_string(a);
pabc::Io_ReadCreatePo(abc_ntk_, (char*)(po_names[index].c_str()));
if (topo_xmg.is_complemented(f)) {
children1.clear();
if (topo_xmg.is_pi(topo_xmg.get_node(f))) {
unsigned int b = a;
children1.push_back(pi_names[b]);
} else if (topo_xmg.is_constant(topo_xmg.get_node(f))) {
// process the abc network constant node
if (!const0_created) {
pabc::Abc_NtkFindOrCreateNet(abc_ntk_,
(char*)(constant_name.c_str()));
pabc::Io_ReadCreateConst(abc_ntk_, (char*)(constant_name.c_str()), 0);
const0_created = true;
}
children1.push_back(constant_name);
} else
children1.push_back(fanin_name);
pabc::Io_ReadCreateInv(abc_ntk_, (char*)(children1[0].c_str()),
(char*)(po_names[index].c_str()));
} else {
children1.clear();
if (topo_xmg.is_pi(topo_xmg.get_node(f))) {
unsigned int b = a;
children1.push_back(pi_names[b]);
} else if (topo_xmg.is_constant(topo_xmg.get_node(f))) {
// process the abc network constant node
if (!const0_created) {
pabc::Abc_NtkFindOrCreateNet(abc_ntk_,
(char*)(constant_name.c_str()));
pabc::Io_ReadCreateConst(abc_ntk_, (char*)(constant_name.c_str()), 0);
const0_created = true;
}
children1.push_back(constant_name);
} else
children1.push_back(fanin_name);
pabc::Io_ReadCreateBuf(abc_ntk_, (char*)(children1[0].c_str()),
(char*)(po_names[index].c_str()));
}
});
return abc_ntk_;
}
pabc::Abc_Ntk_t* mockturtle2abc_a(const mockturtle::aig_network& aig) {
// Convert aig network to the netlist network in abc
const int MAX = 3;
bool const0_created = false;
std::string constant_name = "1\'b0";
// Initialize the abc network
abc_ntk_ = pabc::Abc_NtkAlloc(pabc::ABC_NTK_NETLIST, pabc::ABC_FUNC_SOP, 1);
abc_ntk_->pName = strdup("netlist");
mockturtle::topo_view topo_aig{aig};
// create abc network
// process the abc network primary input
topo_aig.foreach_pi([&](auto const& n, auto index) {
const auto index1 = topo_aig.node_to_index(n);
unsigned int a = index1;
std::string input_name = pi_names[a];
pabc::Io_ReadCreatePi(abc_ntk_, (char*)(input_name.c_str()));
});
// process the abc network node
topo_aig.foreach_node([&](auto n) {
if (topo_aig.is_constant(n) || topo_aig.is_pi(n)) return true;
auto func = topo_aig.node_function(n);
std::string node_name = std::to_string(topo_aig.node_to_index(n));
std::vector<std::string> children;
children.clear();
char* pNamesIn[MAX];
topo_aig.foreach_fanin(n, [&](auto const& f) {
auto index = topo_aig.node_to_index(topo_aig.get_node(f));
std::string fanin_name = std::to_string(index);
if (topo_aig.is_pi(topo_aig.get_node(f))) {
unsigned int b = index;
children.push_back(pi_names[b]);
} else if (topo_aig.is_constant(topo_aig.get_node(f))) {
// process the abc network constant node
if (!const0_created) {
pabc::Abc_NtkFindOrCreateNet(abc_ntk_,
(char*)(constant_name.c_str()));
pabc::Io_ReadCreateConst(abc_ntk_, (char*)(constant_name.c_str()), 0);
const0_created = true;
}
children.push_back(constant_name);
} else
children.push_back(fanin_name);
});
for (size_t i = 0; i < children.size(); i++)
pNamesIn[i] = (char*)(children[i].c_str());
pabc::Abc_Obj_t* pNode;
pNode = pabc::Io_ReadCreateNode(abc_ntk_, (char*)(node_name.c_str()),
pNamesIn, topo_aig.fanin_size(n));
std::string abc_func = "";
int count = 0;
for (auto cube : kitty::isop(func)) {
topo_aig.foreach_fanin(n, [&](auto const& f, auto index) {
if (cube.get_mask(index) && topo_aig.is_complemented(f))
cube.flip_bit(index);
});
for (auto i = 0u; i < topo_aig.fanin_size(n); ++i)
abc_func += (cube.get_mask(i) ? (cube.get_bit(i) ? '1' : '0') : '-');
abc_func += " 1\n";
count++;
}
pabc::Abc_ObjSetData(
pNode, pabc::Abc_SopRegister((pabc::Mem_Flex_t*)abc_ntk_->pManFunc,
abc_func.c_str()));
return true;
});
// process the abc network primary output
std::vector<std::string> children1;
topo_aig.foreach_po([&](auto const& f, auto index) {
auto a = topo_aig.node_to_index(topo_aig.get_node(f));
std::string fanin_name = std::to_string(a);
pabc::Io_ReadCreatePo(abc_ntk_, (char*)(po_names[index].c_str()));
if (topo_aig.is_complemented(f)) {
children1.clear();
if (topo_aig.is_pi(topo_aig.get_node(f))) {
unsigned int b = a;
children1.push_back(pi_names[b]);
} else if (topo_aig.is_constant(topo_aig.get_node(f))) {
// process the abc network constant node
if (!const0_created) {
pabc::Abc_NtkFindOrCreateNet(abc_ntk_,
(char*)(constant_name.c_str()));
pabc::Io_ReadCreateConst(abc_ntk_, (char*)(constant_name.c_str()), 0);
const0_created = true;
}
children1.push_back(constant_name);
} else
children1.push_back(fanin_name);
pabc::Io_ReadCreateInv(abc_ntk_, (char*)(children1[0].c_str()),
(char*)(po_names[index].c_str()));
} else {
children1.clear();
if (topo_aig.is_pi(topo_aig.get_node(f))) {
unsigned int b = a;
children1.push_back(pi_names[b]);
} else if (topo_aig.is_constant(topo_aig.get_node(f))) {
// process the abc network constant node
if (!const0_created) {
pabc::Abc_NtkFindOrCreateNet(abc_ntk_,
(char*)(constant_name.c_str()));
pabc::Io_ReadCreateConst(abc_ntk_, (char*)(constant_name.c_str()), 0);
const0_created = true;
}
children1.push_back(constant_name);
} else
children1.push_back(fanin_name);
pabc::Io_ReadCreateBuf(abc_ntk_, (char*)(children1[0].c_str()),
(char*)(po_names[index].c_str()));
}
});
return abc_ntk_;
}
pabc::Abc_Ntk_t* mockturtle2abc_m(const mockturtle::mig_network& mig) {
// Convert mig network to the netlist network in abc
const int MAX = 3;
bool const0_created = false;
std::string constant_name = "1\'b0";
// Initialize the abc network
abc_ntk_ = pabc::Abc_NtkAlloc(pabc::ABC_NTK_NETLIST, pabc::ABC_FUNC_SOP, 1);
abc_ntk_->pName = strdup("netlist");
mockturtle::topo_view topo_mig{mig};
// create abc network
// process the abc network primary input
topo_mig.foreach_pi([&](auto const& n, auto index) {
const auto index1 = topo_mig.node_to_index(n);
unsigned int a = index1;
std::string input_name = pi_names[a];
pabc::Io_ReadCreatePi(abc_ntk_, (char*)(input_name.c_str()));
});
// process the abc network node
topo_mig.foreach_node([&](auto n) {
if (topo_mig.is_constant(n) || topo_mig.is_pi(n)) return true;
auto func = topo_mig.node_function(n);
std::string node_name = std::to_string(topo_mig.node_to_index(n));
std::vector<std::string> children;
children.clear();
char* pNamesIn[MAX];
topo_mig.foreach_fanin(n, [&](auto const& f) {
auto index = topo_mig.node_to_index(topo_mig.get_node(f));
std::string fanin_name = std::to_string(index);
if (topo_mig.is_pi(topo_mig.get_node(f))) {
unsigned int b = index;
children.push_back(pi_names[b]);
} else if (topo_mig.is_constant(topo_mig.get_node(f))) {
// process the abc network constant node
if (!const0_created) {
pabc::Abc_NtkFindOrCreateNet(abc_ntk_,
(char*)(constant_name.c_str()));
pabc::Io_ReadCreateConst(abc_ntk_, (char*)(constant_name.c_str()), 0);
const0_created = true;
}
children.push_back(constant_name);
} else
children.push_back(fanin_name);
});
for (size_t i = 0; i < children.size(); i++)
pNamesIn[i] = (char*)(children[i].c_str());
pabc::Abc_Obj_t* pNode;
pNode = pabc::Io_ReadCreateNode(abc_ntk_, (char*)(node_name.c_str()),
pNamesIn, topo_mig.fanin_size(n));
std::string abc_func = "";
int count = 0;
for (auto cube : kitty::isop(func)) {
topo_mig.foreach_fanin(n, [&](auto const& f, auto index) {
if (cube.get_mask(index) && topo_mig.is_complemented(f))
cube.flip_bit(index);
});
for (auto i = 0u; i < topo_mig.fanin_size(n); ++i)
abc_func += (cube.get_mask(i) ? (cube.get_bit(i) ? '1' : '0') : '-');
abc_func += " 1\n";
count++;
}
pabc::Abc_ObjSetData(
pNode, pabc::Abc_SopRegister((pabc::Mem_Flex_t*)abc_ntk_->pManFunc,
abc_func.c_str()));
return true;
});
// process the abc network primary output
std::vector<std::string> children1;
topo_mig.foreach_po([&](auto const& f, auto index) {
auto a = topo_mig.node_to_index(topo_mig.get_node(f));
std::string fanin_name = std::to_string(a);
pabc::Io_ReadCreatePo(abc_ntk_, (char*)(po_names[index].c_str()));
if (topo_mig.is_complemented(f)) {
children1.clear();
if (topo_mig.is_pi(topo_mig.get_node(f))) {
unsigned int b = a;
children1.push_back(pi_names[b]);
} else if (topo_mig.is_constant(topo_mig.get_node(f))) {
// process the abc network constant node
if (!const0_created) {
pabc::Abc_NtkFindOrCreateNet(abc_ntk_,
(char*)(constant_name.c_str()));
pabc::Io_ReadCreateConst(abc_ntk_, (char*)(constant_name.c_str()), 0);
const0_created = true;
}
children1.push_back(constant_name);
} else
children1.push_back(fanin_name);
pabc::Io_ReadCreateInv(abc_ntk_, (char*)(children1[0].c_str()),
(char*)(po_names[index].c_str()));
} else {
children1.clear();
if (topo_mig.is_pi(topo_mig.get_node(f))) {
unsigned int b = a;
children1.push_back(pi_names[b]);
} else if (topo_mig.is_constant(topo_mig.get_node(f))) {
// process the abc network constant node
if (!const0_created) {
pabc::Abc_NtkFindOrCreateNet(abc_ntk_,
(char*)(constant_name.c_str()));
pabc::Io_ReadCreateConst(abc_ntk_, (char*)(constant_name.c_str()), 0);
const0_created = true;
}
children1.push_back(constant_name);
} else
children1.push_back(fanin_name);
pabc::Io_ReadCreateBuf(abc_ntk_, (char*)(children1[0].c_str()),
(char*)(po_names[index].c_str()));
}
});
return abc_ntk_;
}
pabc::Abc_Ntk_t* mockturtle2abc_g(const mockturtle::xag_network& xag) {
// Convert xag network to the netlist network in abc
const int MAX = 3;
bool const0_created = false;
std::string constant_name = "1\'b0";
// Initialize the abc network
abc_ntk_ = pabc::Abc_NtkAlloc(pabc::ABC_NTK_NETLIST, pabc::ABC_FUNC_SOP, 1);
abc_ntk_->pName = strdup("netlist");
mockturtle::topo_view topo_xag{xag};
// create abc network
// process the abc network primary input
topo_xag.foreach_pi([&](auto const& n, auto index) {
const auto index1 = topo_xag.node_to_index(n);
unsigned int a = index1;
std::string input_name = pi_names[a];
pabc::Io_ReadCreatePi(abc_ntk_, (char*)(input_name.c_str()));
});
// process the abc network node
topo_xag.foreach_node([&](auto n) {
if (topo_xag.is_constant(n) || topo_xag.is_pi(n)) return true;
auto func = topo_xag.node_function(n);
std::string node_name = std::to_string(topo_xag.node_to_index(n));
std::vector<std::string> children;
children.clear();
char* pNamesIn[MAX];
topo_xag.foreach_fanin(n, [&](auto const& f) {
auto index = topo_xag.node_to_index(topo_xag.get_node(f));
std::string fanin_name = std::to_string(index);
if (topo_xag.is_pi(topo_xag.get_node(f))) {
unsigned int b = index;
children.push_back(pi_names[b]);
} else if (topo_xag.is_constant(topo_xag.get_node(f))) {
// process the abc network constant node
if (!const0_created) {
pabc::Abc_NtkFindOrCreateNet(abc_ntk_,
(char*)(constant_name.c_str()));
pabc::Io_ReadCreateConst(abc_ntk_, (char*)(constant_name.c_str()), 0);
const0_created = true;
}
children.push_back(constant_name);
} else
children.push_back(fanin_name);
});
for (size_t i = 0; i < children.size(); i++)
pNamesIn[i] = (char*)(children[i].c_str());
pabc::Abc_Obj_t* pNode;
pNode = pabc::Io_ReadCreateNode(abc_ntk_, (char*)(node_name.c_str()),
pNamesIn, topo_xag.fanin_size(n));
std::string abc_func = "";
int count = 0;
for (auto cube : kitty::isop(func)) {
topo_xag.foreach_fanin(n, [&](auto const& f, auto index) {
if (cube.get_mask(index) && topo_xag.is_complemented(f))
cube.flip_bit(index);
});
for (auto i = 0u; i < topo_xag.fanin_size(n); ++i)
abc_func += (cube.get_mask(i) ? (cube.get_bit(i) ? '1' : '0') : '-');
abc_func += " 1\n";
count++;
}
pabc::Abc_ObjSetData(
pNode, pabc::Abc_SopRegister((pabc::Mem_Flex_t*)abc_ntk_->pManFunc,
abc_func.c_str()));
return true;
});
// process the abc network primary output
std::vector<std::string> children1;
topo_xag.foreach_po([&](auto const& f, auto index) {
auto a = topo_xag.node_to_index(topo_xag.get_node(f));
std::string fanin_name = std::to_string(a);
pabc::Io_ReadCreatePo(abc_ntk_, (char*)(po_names[index].c_str()));
if (topo_xag.is_complemented(f)) {
children1.clear();
if (topo_xag.is_pi(topo_xag.get_node(f))) {
unsigned int b = a;
children1.push_back(pi_names[b]);
} else if (topo_xag.is_constant(topo_xag.get_node(f))) {
// process the abc network constant node
if (!const0_created) {
pabc::Abc_NtkFindOrCreateNet(abc_ntk_,
(char*)(constant_name.c_str()));
pabc::Io_ReadCreateConst(abc_ntk_, (char*)(constant_name.c_str()), 0);
const0_created = true;
}
children1.push_back(constant_name);
} else
children1.push_back(fanin_name);
pabc::Io_ReadCreateInv(abc_ntk_, (char*)(children1[0].c_str()),
(char*)(po_names[index].c_str()));
} else {
children1.clear();
if (topo_xag.is_pi(topo_xag.get_node(f))) {
unsigned int b = a;
children1.push_back(pi_names[b]);
} else if (topo_xag.is_constant(topo_xag.get_node(f))) {
// process the abc network constant node
if (!const0_created) {
pabc::Abc_NtkFindOrCreateNet(abc_ntk_,
(char*)(constant_name.c_str()));
pabc::Io_ReadCreateConst(abc_ntk_, (char*)(constant_name.c_str()), 0);
const0_created = true;
}
children1.push_back(constant_name);
} else
children1.push_back(fanin_name);
pabc::Io_ReadCreateBuf(abc_ntk_, (char*)(children1[0].c_str()),
(char*)(po_names[index].c_str()));
}
});
return abc_ntk_;
}
pabc::Abc_Ntk_t* mockturtle2abc_l(const mockturtle::klut_network& klut) {
// Convert klut network to the netlist network in abc
const int MAX = 3;
bool const0_created = false;
std::string constant_name = "1\'b0";
// Initialize the abc network
abc_ntk_ = pabc::Abc_NtkAlloc(pabc::ABC_NTK_NETLIST, pabc::ABC_FUNC_SOP, 1);
abc_ntk_->pName = strdup("netlist");
mockturtle::topo_view topo_klut{klut};
// create abc network
// process the abc network primary input
topo_klut.foreach_pi([&](auto const& n, auto index) {
const auto index1 = topo_klut.node_to_index(n);
unsigned int a = index1;
std::string input_name = pi_names[a];
pabc::Io_ReadCreatePi(abc_ntk_, (char*)(input_name.c_str()));
});
// process the abc network node
topo_klut.foreach_node([&](auto n) {
if (topo_klut.is_constant(n) || topo_klut.is_pi(n)) return true;
auto func = topo_klut.node_function(n);
std::string node_name = std::to_string(topo_klut.node_to_index(n));
std::vector<std::string> children;
children.clear();
char* pNamesIn[MAX];
topo_klut.foreach_fanin(n, [&](auto const& f) {
auto index = topo_klut.node_to_index(topo_klut.get_node(f));
std::string fanin_name = std::to_string(index);
if (topo_klut.is_pi(topo_klut.get_node(f))) {
unsigned int b = index;
children.push_back(pi_names[b]);
} else if (topo_klut.is_constant(topo_klut.get_node(f))) {
// process the abc network constant node
if (!const0_created) {
pabc::Abc_NtkFindOrCreateNet(abc_ntk_,
(char*)(constant_name.c_str()));
pabc::Io_ReadCreateConst(abc_ntk_, (char*)(constant_name.c_str()), 0);
const0_created = true;
}
children.push_back(constant_name);
} else
children.push_back(fanin_name);
});
for (size_t i = 0; i < children.size(); i++)
pNamesIn[i] = (char*)(children[i].c_str());
pabc::Abc_Obj_t* pNode;
pNode = pabc::Io_ReadCreateNode(abc_ntk_, (char*)(node_name.c_str()),
pNamesIn, topo_klut.fanin_size(n));
std::string abc_func = "";
int count = 0;
for (auto cube : kitty::isop(func)) {
topo_klut.foreach_fanin(n, [&](auto const& f, auto index) {
if (cube.get_mask(index) && topo_klut.is_complemented(f))
cube.flip_bit(index);
});
for (auto i = 0u; i < topo_klut.fanin_size(n); ++i)
abc_func += (cube.get_mask(i) ? (cube.get_bit(i) ? '1' : '0') : '-');
abc_func += " 1\n";
count++;
}
pabc::Abc_ObjSetData(
pNode, pabc::Abc_SopRegister((pabc::Mem_Flex_t*)abc_ntk_->pManFunc,
abc_func.c_str()));
return true;
});
// process the abc network primary output
std::vector<std::string> children1;
topo_klut.foreach_po([&](auto const& f, auto index) {
auto a = topo_klut.node_to_index(topo_klut.get_node(f));
std::string fanin_name = std::to_string(a);
pabc::Io_ReadCreatePo(abc_ntk_, (char*)(po_names[index].c_str()));
if (topo_klut.is_complemented(f)) {
children1.clear();
if (topo_klut.is_pi(topo_klut.get_node(f))) {
unsigned int b = a;
children1.push_back(pi_names[b]);
} else if (topo_klut.is_constant(topo_klut.get_node(f))) {
// process the abc network constant node
if (!const0_created) {
pabc::Abc_NtkFindOrCreateNet(abc_ntk_,
(char*)(constant_name.c_str()));
pabc::Io_ReadCreateConst(abc_ntk_, (char*)(constant_name.c_str()), 0);
const0_created = true;
}
children1.push_back(constant_name);
} else
children1.push_back(fanin_name);
pabc::Io_ReadCreateInv(abc_ntk_, (char*)(children1[0].c_str()),
(char*)(po_names[index].c_str()));
} else {
children1.clear();
if (topo_klut.is_pi(topo_klut.get_node(f))) {
unsigned int b = a;
children1.push_back(pi_names[b]);
} else if (topo_klut.is_constant(topo_klut.get_node(f))) {
// process the abc network constant node
if (!const0_created) {
pabc::Abc_NtkFindOrCreateNet(abc_ntk_,
(char*)(constant_name.c_str()));
pabc::Io_ReadCreateConst(abc_ntk_, (char*)(constant_name.c_str()), 0);
const0_created = true;
}
children1.push_back(constant_name);
} else
children1.push_back(fanin_name);
pabc::Io_ReadCreateBuf(abc_ntk_, (char*)(children1[0].c_str()),
(char*)(po_names[index].c_str()));
}
});
return abc_ntk_;
}
} // namespace phyLS
#endif

21
src/core/balance.hpp Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#include <algorithm>
#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/views/depth_view.hpp>
#include <vector>
using namespace percy;
using namespace mockturtle;
namespace phyLS
{
template <class Ntk>
void aig_balancing(Ntk& ntk) {
// please learn the algorithm of "mockturtle/algorithms/aig_balancing.hpp"
}
}

20
src/core/balance.rst Normal file
View File

@ -0,0 +1,20 @@
Balance
=============
**Header:** ``mockturtle/algorithms/balancing.hpp``
Parameters
~~~~~~~~~~
.. doxygenstruct:: mockturtle::aig_balancing_params
:members:
Algorithm
~~~~~~~~~
.. doxygenfunction:: mockturtle::aig_balance
Balancing of a logic network
This function implements a dynamic-programming and cut-enumeration based balancing algorithm.
It returns a new network of the same type and performs generic balancing by providing a rebalancing function.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,382 +0,0 @@
#ifndef LUT_REWRITING_HPP
#define LUT_REWRITING_HPP
#include <algorithm>
#include <mockturtle/algorithms/cleanup.hpp>
#include <mockturtle/mockturtle.hpp>
#include <mockturtle/networks/klut.hpp>
#include <percy/percy.hpp>
#include <string>
#include <vector>
#include "exact_dag.hpp"
using namespace percy;
using namespace mockturtle;
namespace phyLS {
struct lut_rewriting_params {
/*! \brief Enable exact synthesis for XAG. */
bool xag{false};
};
class lut_rewriting_manager {
public:
lut_rewriting_manager(klut_network klut, lut_rewriting_params const& ps)
: klut(klut), ps(ps) {}
klut_network run_c() {
klut.foreach_node([&](auto const& n) {
if (klut.is_constant(n) || klut.is_pi(n)) return true; /* continue */
std::string func = kitty::to_hex(klut.node_function(n));
std::vector<klut_network::node> lut_inputs;
klut.foreach_fanin(
n, [&](auto const& c) { lut_inputs.push_back(klut.get_node(c)); });
if (lut_inputs.size() <= 2) return true; /* continue */
// exact synthesis for each node
int input_num = lut_inputs.size();
percy::chain chain;
es(input_num, func, chain);
std::vector<int> node;
std::vector<int> right;
std::vector<int> left;
std::vector<std::string> tt;
chain.bench_infor(node, left, right, tt);
if (tt.size() != node.size()) {
tt.pop_back();
hex_invert(tt[tt.size() - 1]);
}
// rewrite origin node by the optimal Boolean chains of exact synthesis
std::vector<mockturtle::klut_network::node> new_lut;
for (int i = 0; i < node.size(); i++) {
kitty::dynamic_truth_table node_tt(2u);
kitty::create_from_hex_string(node_tt, tt[i]);
if (left[i] <= input_num && right[i] <= input_num) {
const auto node_new = klut.create_node(
{lut_inputs[left[i] - 1], lut_inputs[right[i] - 1]}, node_tt);
new_lut.push_back(node_new);
} else if (left[i] <= input_num && right[i] > input_num) {
const auto node_new = klut.create_node(
{lut_inputs[left[i] - 1], new_lut[right[i] - 1 - input_num]},
node_tt);
new_lut.push_back(node_new);
} else if (left[i] > input_num && right[i] > input_num) {
const auto node_new =
klut.create_node({new_lut[left[i] - 1 - input_num],
new_lut[right[i] - 1 - input_num]},
node_tt);
new_lut.push_back(node_new);
}
}
klut.substitute_node(n, new_lut[new_lut.size() - 1]);
return true;
});
// clean all redundant luts
auto klut_opt = mockturtle::cleanup_dangling(klut);
return klut_opt;
}
klut_network run_s() {
klut.foreach_node([&](auto const& n) {
if (klut.is_constant(n) || klut.is_pi(n)) return true; /* continue */
std::string func = kitty::to_hex(klut.node_function(n));
std::vector<klut_network::node> lut_inputs;
klut.foreach_fanin(
n, [&](auto const& c) { lut_inputs.push_back(klut.get_node(c)); });
if (lut_inputs.size() <= 2) return true; /* continue */
// exact synthesis for each node
int input_num = lut_inputs.size();
phyLS::exact_lut_params ps;
dag_impl mgr(func, input_num, ps);
mgr.run_rewrite();
// compute the techmap costs of all realizations
float cost = 0;
int min_cost_realization = 0;
for (int i = 0; i < mgr.exact_synthesis_results.size(); i++) {
float cost_temp = 0;
for (auto y : mgr.exact_synthesis_results[i])
cost_temp += bench_cost_area(y.tt);
if (cost_temp < cost || cost == 0) {
cost = cost_temp;
min_cost_realization = i;
}
}
std::vector<int> nodes;
std::vector<int> rights;
std::vector<int> lefts;
std::vector<std::string> tts;
for (auto x : mgr.exact_synthesis_results[min_cost_realization]) {
nodes.push_back(x.node);
lefts.push_back(x.left);
rights.push_back(x.right);
tts.push_back(x.tt);
}
// rewrite origin node by the optimal Boolean chains of exact synthesis
std::vector<mockturtle::klut_network::node> new_lut;
for (int i = nodes.size() - 1; i >= 0; i--) {
kitty::dynamic_truth_table node_tt(2u);
kitty::create_from_binary_string(node_tt, tts[i]);
if (lefts[i] <= input_num && rights[i] <= input_num) {
const auto node_new = klut.create_node(
{lut_inputs[lefts[i] - 1], lut_inputs[rights[i] - 1]}, node_tt);
new_lut.push_back(node_new);
} else if (lefts[i] <= input_num && rights[i] > input_num) {
const auto node_new = klut.create_node(
{lut_inputs[lefts[i] - 1], new_lut[rights[i] - 1 - input_num]},
node_tt);
new_lut.push_back(node_new);
} else if (lefts[i] > input_num && rights[i] > input_num) {
const auto node_new =
klut.create_node({new_lut[lefts[i] - 1 - input_num],
new_lut[rights[i] - 1 - input_num]},
node_tt);
new_lut.push_back(node_new);
}
}
klut.substitute_node(n, new_lut[new_lut.size() - 1]);
return true;
});
// clean all redundant luts
auto klut_opt = mockturtle::cleanup_luts(klut);
return klut_opt;
}
klut_network run_s_enu() {
klut.foreach_node([&](auto const& n) {
if (klut.is_constant(n) || klut.is_pi(n)) return true; /* continue */
std::string func = kitty::to_hex(klut.node_function(n));
std::vector<klut_network::node> lut_inputs;
klut.foreach_fanin(
n, [&](auto const& c) { lut_inputs.push_back(klut.get_node(c)); });
if (lut_inputs.size() <= 2) return true; /* continue */
// exact synthesis for each node
int input_num = lut_inputs.size();
phyLS::exact_lut_params ps;
dag_impl mgr(func, input_num, ps);
mgr.run_rewrite_enu();
// compute the techmap costs of all realizations
float cost = 0;
int min_cost_realization = 0;
for (int i = 0; i < mgr.exact_synthesis_results.size(); i++) {
float cost_temp = 0;
for (auto y : mgr.exact_synthesis_results[i])
cost_temp += bench_cost_area(y.tt);
if (cost_temp < cost || cost == 0) {
cost = cost_temp;
min_cost_realization = i;
}
}
std::vector<int> nodes;
std::vector<int> rights;
std::vector<int> lefts;
std::vector<std::string> tts;
for (auto x : mgr.exact_synthesis_results[min_cost_realization]) {
nodes.push_back(x.node);
lefts.push_back(x.left);
rights.push_back(x.right);
tts.push_back(x.tt);
}
// rewrite origin node by the optimal Boolean chains of exact synthesis
std::vector<mockturtle::klut_network::node> new_lut;
for (int i = nodes.size() - 1; i >= 0; i--) {
kitty::dynamic_truth_table node_tt(2u);
kitty::create_from_binary_string(node_tt, tts[i]);
if (lefts[i] <= input_num && rights[i] <= input_num) {
const auto node_new = klut.create_node(
{lut_inputs[lefts[i] - 1], lut_inputs[rights[i] - 1]}, node_tt);
new_lut.push_back(node_new);
} else if (lefts[i] <= input_num && rights[i] > input_num) {
const auto node_new = klut.create_node(
{lut_inputs[lefts[i] - 1], new_lut[rights[i] - 1 - input_num]},
node_tt);
new_lut.push_back(node_new);
} else if (lefts[i] > input_num && rights[i] > input_num) {
const auto node_new =
klut.create_node({new_lut[lefts[i] - 1 - input_num],
new_lut[rights[i] - 1 - input_num]},
node_tt);
new_lut.push_back(node_new);
}
}
klut.substitute_node(n, new_lut[new_lut.size() - 1]);
return true;
});
// clean all redundant luts
auto klut_opt = mockturtle::cleanup_luts(klut);
return klut_opt;
}
private:
void hex_invert(std::string& tt_temp) {
if (tt_temp == "1")
tt_temp = "e";
else if (tt_temp == "2")
tt_temp = "d";
else if (tt_temp == "3")
tt_temp = "c";
else if (tt_temp == "4")
tt_temp = "b";
else if (tt_temp == "5")
tt_temp = "a";
else if (tt_temp == "6")
tt_temp = "9";
else if (tt_temp == "7")
tt_temp = "8";
else if (tt_temp == "8")
tt_temp = "7";
else if (tt_temp == "9")
tt_temp = "6";
else if (tt_temp == "a")
tt_temp = "5";
else if (tt_temp == "b")
tt_temp = "4";
else if (tt_temp == "c")
tt_temp = "3";
else if (tt_temp == "d")
tt_temp = "2";
else if (tt_temp == "e")
tt_temp = "1";
else
tt_temp = "0";
}
// TODO
float techmap_cost(std::vector<std::vector<std::string>> tt) {
float cost = 0;
for (auto x : tt) {
float cost_temp = 0;
for (auto y : x) {
cost_temp += bench_cost_area(y);
}
if (cost_temp < cost || cost == 0) cost = cost_temp;
}
return cost;
}
// TODO
float bench_cost_area(std::string tt) {
float area_cost = 0;
if (tt == "0001")
area_cost = 2;
else if (tt == "0010")
area_cost = 3;
else if (tt == "0011")
area_cost = 1;
else if (tt == "0100")
area_cost = 3;
else if (tt == "0101")
area_cost = 1;
else if (tt == "0110")
area_cost = 5;
else if (tt == "0111")
area_cost = 2;
else if (tt == "1000")
area_cost = 3;
else if (tt == "1001")
area_cost = 5;
else if (tt == "1010")
area_cost = 1;
else if (tt == "1011")
area_cost = 3;
else if (tt == "1100")
area_cost = 1;
else if (tt == "1101")
area_cost = 3;
else if (tt == "1110")
area_cost = 4;
else
area_cost = 0;
return area_cost;
}
// TODO
float bench_cost_depth(std::string tt) {
float depth_cost = 0;
if (tt == "0001")
depth_cost = 1.4;
else if (tt == "0010")
depth_cost = 2.3;
else if (tt == "0011")
depth_cost = 0.9;
else if (tt == "0100")
depth_cost = 2.3;
else if (tt == "0101")
depth_cost = 0.9;
else if (tt == "0110")
depth_cost = 1.9;
else if (tt == "0111")
depth_cost = 1;
else if (tt == "1000")
depth_cost = 1.9;
else if (tt == "1001")
depth_cost = 2.1;
else if (tt == "1010")
depth_cost = 1;
else if (tt == "1011")
depth_cost = 1.9;
else if (tt == "1100")
depth_cost = 1;
else if (tt == "1101")
depth_cost = 1.9;
else if (tt == "1110")
depth_cost = 1.9;
else
depth_cost = 0;
return depth_cost;
}
void es(int nr_in, std::string tt, percy::chain& result) {
spec spec;
chain c;
spec.verbosity = 0;
kitty::dynamic_truth_table f(nr_in);
kitty::create_from_hex_string(f, tt);
spec[0] = f;
spec.preprocess();
auto res = pd_ser_synthesize_parallel(spec, c, 4, "../src/pd/");
if (res == success) result.copy(c);
}
private:
klut_network klut;
lut_rewriting_params const& ps;
};
klut_network lut_rewriting_c(klut_network& klut,
lut_rewriting_params const& ps = {}) {
lut_rewriting_manager mgr(klut, ps);
return mgr.run_c();
}
klut_network lut_rewriting_s(klut_network& klut,
lut_rewriting_params const& ps = {}) {
lut_rewriting_manager mgr(klut, ps);
return mgr.run_s();
}
klut_network lut_rewriting_s_enu(klut_network& klut,
lut_rewriting_params const& ps = {}) {
lut_rewriting_manager mgr(klut, ps);
return mgr.run_s_enu();
}
} // namespace phyLS
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,124 +0,0 @@
#ifndef _MATRIX_H_
#define _MATRIX_H_
#include <algorithm>
#include <cassert>
#include <cstring>
#include <iostream>
#include <sstream>
#include <vector>
using namespace std;
class MatrixXi {
friend ostream &operator<<(ostream &os, const MatrixXi &m) {
for (size_t i = 0; i < m.row; i++) {
for (size_t j = 0; j < m.col; j++) {
os << m.data[i][j] << " ";
}
os << endl;
}
return os;
}
friend istream &operator>>(istream &is, MatrixXi &m) {
for (size_t i = 0; i < m.row; i++) {
for (size_t j = 0; j < m.col; j++) {
is >> m.data[i][j];
}
}
return is;
}
public:
typedef int value_type;
typedef vector<int>::size_type size_type;
MatrixXi() {
row = 0;
col = 0;
data.clear();
}
MatrixXi(size_t i, size_t j) {
row = i;
col = j;
vector<vector<int>> vdata(row, vector<int>(col, 0));
data = move(vdata);
}
MatrixXi(const MatrixXi &m) {
row = m.row;
col = m.col;
data = m.data;
}
MatrixXi &operator=(const MatrixXi &m) {
row = m.row;
col = m.col;
data = m.data;
return *this;
}
static MatrixXi product(MatrixXi &m, MatrixXi &n) {
MatrixXi t(m.row, n.col);
for (size_t i = 0; i < m.row; i++) {
for (size_t j = 0; j < n.col; j++) {
for (size_t k = 0; k < m.col; k++) {
t.data[i][j] += (m.data[i][k] * n.data[k][j]);
}
}
}
return t;
}
static MatrixXi eye(size_t n) {
MatrixXi A(n, n);
for (size_t i = 0; i < n; i++) {
for (size_t j = 0; j < n; j++) {
if (i == j) {
A.data[i][j] = 1;
} else {
A.data[i][j] = 0;
}
}
}
return A;
}
static MatrixXi kron(const MatrixXi &m, const MatrixXi &n) {
size_t a = m.row;
size_t b = m.col;
size_t c = n.row;
size_t d = n.col;
MatrixXi t(a * c, b * d);
for (size_t i = 0; i < a * c; i++) {
for (size_t j = 0; j < b * d; j++) {
t.data[i][j] = m.data[i / c][j / d] * n.data[i % c][j % d];
}
}
return t;
}
~MatrixXi() { data.clear(); }
int &operator()(size_t i, size_t j) { return data[i][j]; }
const int &operator()(size_t i, size_t j) const { return data[i][j]; }
size_t rows() const { return row; }
size_t cols() const { return col; }
void resize(size_t nr, size_t nc) {
data.resize(nr);
for (size_t i = 0; i < nr; i++) {
data[i].resize(nc);
}
col = nc;
row = nr;
}
private:
size_t row;
size_t col;
vector<vector<int>> data;
};
#endif

View File

@ -1,277 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file ps2.hpp
*
* @brief Show statistics in the stored network
*
* @author Homyoung
* @since 2023/11/16
*/
#pragma once
#include <alice/alice.hpp>
#include <mockturtle/mockturtle.hpp>
#include <string>
#include <vector>
namespace phyLS {
using aig_names = mockturtle::names_view<mockturtle::aig_network>;
using mig_names = mockturtle::names_view<mockturtle::mig_network>;
using xag_names = mockturtle::names_view<mockturtle::xag_network>;
using xmg_names = mockturtle::names_view<mockturtle::xmg_network>;
struct function_counts {
int maj_num = 0;
int xor_num = 0;
int xnor_num = 0;
int xor3_num = 0;
int and_num = 0;
int or_num = 0;
int input_num = 0;
int unknown_num = 0;
};
enum reconfig_function { AND, OR, XOR, XNOR, XOR3, MAJ, INPUT, UNKNOWN };
template <typename network>
reconfig_function node_function(const network& ntk,
const typename network::node& node) {
if (ntk.is_pi(node) || ntk.is_constant(node)) {
return reconfig_function::INPUT;
} else if (ntk.is_and(node)) {
return reconfig_function::AND;
} else if (ntk.is_or(node)) {
return reconfig_function::OR;
} else if (ntk.is_xor(node)) {
return reconfig_function::XOR;
} else if (ntk.is_maj(node)) {
typename network::signal first_signal =
ntk._storage->nodes[node].children[0];
typename network::node first_fanin = ntk.get_node(first_signal);
if (ntk.is_constant(first_fanin)) {
if (first_signal.complement) {
return reconfig_function::OR;
} else {
return reconfig_function::AND;
}
} else {
return reconfig_function::MAJ;
}
} else if (ntk.is_xor3(node)) {
typename network::signal first_signal =
ntk._storage->nodes[node].children[0];
typename network::node first_fanin = ntk.get_node(first_signal);
if (ntk.is_constant(first_fanin)) {
if (first_signal.complement) {
return reconfig_function::XNOR;
} else {
return reconfig_function::XOR;
}
} else {
return reconfig_function::XOR3;
}
} else {
return reconfig_function::UNKNOWN;
}
}
template <typename network>
void update_counts(function_counts& counts, const network& ntk,
const typename network::node& node) {
reconfig_function func = node_function(ntk, node);
switch (func) {
case AND:
counts.and_num++;
break;
case OR:
counts.or_num++;
break;
case XOR:
counts.xor_num++;
break;
case XNOR:
counts.xnor_num++;
break;
case XOR3:
counts.xor3_num++;
break;
case MAJ:
counts.maj_num++;
break;
case INPUT:
counts.input_num++;
break;
case UNKNOWN:
default:
counts.unknown_num++;
}
}
template <typename network>
function_counts node_functions(const network& ntk) {
function_counts counts;
ntk.foreach_node([&](auto node) { update_counts(counts, ntk, node); });
return counts;
}
template <typename Ntk>
class critical_node_view : public Ntk {
public:
using storage = typename Ntk::storage;
using node = typename Ntk::node;
using signal = typename Ntk::signal;
public:
critical_node_view() {}
explicit critical_node_view(Ntk const& ntk) : Ntk(ntk), ntk(ntk) {
int depth = depth_ntk.depth();
depth_ntk.clear_visited();
nums_criti = 0;
depth_ntk.foreach_po([&](auto const& po, auto i) {
node pon = depth_ntk.get_node(po);
if (depth_ntk.level(pon) != depth) return;
nums_criti++;
recursive(pon, critical_path, i);
});
}
std::vector<node> recursive(node& n, std::vector<node>& critical, int i) {
if (depth_ntk.visited(n) != 0) return critical;
depth_ntk.set_visited(n, i + 1);
critical.emplace_back(n);
depth_ntk.foreach_fanin(n, [&](auto fi) {
node fin = depth_ntk.get_node(fi);
int level = depth_ntk.level(n);
if (depth_ntk.level(fin) == level - 1) {
recursive(fin, critical, i);
}
});
return critical;
}
std::vector<node> get_critical_path() { return critical_path; }
uint32_t get_critical_nums() { return nums_criti; }
private:
uint32_t nums_criti;
std::vector<node> critical_path;
Ntk const& ntk;
mockturtle::depth_view<Ntk> depth_ntk{ntk};
};
static void compute_cone(mockturtle::aig_network aig, uint64_t index,
std::unordered_map<int, int>& nodes, int outindex,
std::unordered_map<int, int>& ins) {
if (aig._storage->nodes[index].data[1].h1 == 0) {
// increment number of nodes in this cone
std::unordered_map<int, int>::iterator it = nodes.find(outindex);
if (it != nodes.end() && index > aig.num_pis()) {
// increment the number of nodes
it->second++;
}
// set node as visited
aig._storage->nodes[index].data[1].h1 = 1;
// traverse one side to the PIs
if (!aig.is_pi(aig._storage->nodes[index].children[0].index) &&
index > aig.num_pis()) {
if (aig._storage->nodes[index].children[0].data & 1)
aig._storage->nodes[index].children[0].data =
aig._storage->nodes[index].children[0].data - 1;
// calculate input node index
auto inIndex = aig._storage->nodes[index].children[0].data >> 1;
// im ignoring latches
if (inIndex > aig.num_pis()) {
// call recursion
compute_cone(aig, inIndex, nodes, outindex, ins);
}
}
// traverse the other side to the PIs
if (!aig.is_pi(aig._storage->nodes[index].children[1].index) &&
index > aig.num_pis()) {
if (aig._storage->nodes[index].children[1].data & 1)
aig._storage->nodes[index].children[1].data =
aig._storage->nodes[index].children[1].data - 1;
// calculate input node index
auto inIndex = aig._storage->nodes[index].children[1].data >> 1;
// im ignoring latches
if (inIndex > aig.num_pis()) {
// call recursion
compute_cone(aig, inIndex, nodes, outindex, ins);
}
}
// if my child is PI and was not visited yet, I increase the input counter
if (aig.is_ci(aig._storage->nodes[index].children[0].index) &&
aig._storage->nodes[aig._storage->nodes[index].children[0].index]
.data[1]
.h1 == 0) {
aig._storage->nodes[aig._storage->nodes[index].children[0].index]
.data[1]
.h1 = 1;
std::unordered_map<int, int>::iterator it = ins.find(outindex);
if (it != ins.end()) {
// increment the number of inputs
it->second++;
}
}
// if my other child is PI and was not visited yet, I phyLS increase the
// input counter
if (aig.is_ci(aig._storage->nodes[index].children[1].index) &&
aig._storage->nodes[aig._storage->nodes[index].children[1].index]
.data[1]
.h1 == 0) {
aig._storage->nodes[aig._storage->nodes[index].children[1].index]
.data[1]
.h1 = 1;
std::unordered_map<int, int>::iterator it = ins.find(outindex);
if (it != ins.end()) {
// increment the number of inputs
it->second++;
}
}
}
}
template <typename Ntk>
static int computeLevel(Ntk const& ntk, int index) {
// if node not visited
if (ntk._storage->nodes[index].data[1].h1 == 0) {
// set node as visited
ntk._storage->nodes[index].data[1].h1 = 1;
// if is input
if (ntk.is_ci(index)) {
return 0;
}
auto inIdx2 = ntk._storage->nodes[index].children[1].data;
if (inIdx2 & 1) inIdx2 = inIdx2 - 1;
// calculate input node index
auto inNode1 = inIdx2 >> 1;
int levelNode1 = computeLevel<Ntk>(ntk, inNode1);
auto inIdx = ntk._storage->nodes[index].children[0].data;
if (inIdx & 1) inIdx = inIdx - 1;
// calculate input node index
auto inNode0 = inIdx >> 1;
int levelNode0 = computeLevel<Ntk>(ntk, inNode0);
int level = 1 + std::max(levelNode0, levelNode1);
return level;
}
return 0;
}
} // namespace phyLS

24
src/core/resub.hpp Normal file
View File

@ -0,0 +1,24 @@
#pragma once
#include <kitty/static_truth_table.hpp>
#include <mockturtle/algorithms/aig_resub.hpp>
#include <mockturtle/algorithms/cleanup.hpp>
#include <mockturtle/algorithms/resubstitution.hpp>
#include <mockturtle/algorithms/sim_resub.hpp>
#include <mockturtle/algorithms/simulation.hpp>
#include <mockturtle/io/write_verilog.hpp>
#include <mockturtle/networks/aig.hpp>
#include <mockturtle/traits.hpp>
#include <mockturtle/views/depth_view.hpp>
#include <mockturtle/views/fanout_view.hpp>
using namespace percy;
using namespace mockturtle;
namespace phyLS
{
template <class Ntk>
void aig_resub(Ntk& ntk) {
// please learn the algorithm of "mockturtle/algorithms/aig_resub.hpp"
}
}

80
src/core/resub.rst Normal file
View File

@ -0,0 +1,80 @@
Resub
=============
**Header:** ``mockturtle/algorithms/resubstitution.hpp``
Several resubstitution algorithms are implemented and can be called directly, including:
- ``default_resubstitution`` does functional reduction within a window.
Structure
~~~~~~~~~
In addition to the example algorithms listed above, custom resubstitution algorithms can also be composed.
**Top level**
First, the top-level framework ``detail::resubstitution_impl`` is built-up with a resubstitution engine and a divisor collector.
.. doxygenclass:: mockturtle::detail::resubstitution_impl
.. doxygenfunction:: mockturtle::detail::resubstitution_impl::resubstitution_impl
**ResubEngine**
There are two resubstitution engines implemented: `window_based_resub_engine` and `simulation_based_resub_engine`.
.. doxygenclass:: mockturtle::detail::window_based_resub_engine
.. doxygenclass:: mockturtle::detail::simulation_based_resub_engine
**DivCollector**
Currently, there is only one implementation:
.. doxygenclass:: mockturtle::detail::default_divisor_collector
**Example**
The following example shows how to compose a customized resubstitution algorithm.
.. code-block:: c++
/* derive some AIG */
aig_network aig = ...;
/* prepare the needed views */
using resub_view_t = fanout_view<depth_view<aig_network>>;
depth_view<aig_network> depth_view{aig};
resub_view_t resub_view{depth_view};
/* compose the resubstitution framework */
using validator_t = circuit_validator<Ntk, bill::solvers::bsat2, false, true, false>;
using functor_t = typename detail::sim_aig_resub_functor<resub_view_t, validator_t>;
using engine_t = typename detail::simulation_based_resub_engine<resub_view_t, validator_t, functor_t>;
using resub_impl_t = typename detail::resubstitution_impl<resub_view_t, engine_t>;
/* statistics objects */
resubstitution_stats st;
typename resub_impl_t::engine_st_t engine_st;
typename resub_impl_t::collector_st_t collector_st;
/* instantiate the framework and run it */
resubstitution_params ps;
resub_impl_t p( resub_view, ps, st, engine_st, collector_st );
p.run();
/* report statistics */
st.report();
collector_st.report();
engine_st.report();
Detailed statistics
~~~~~~~~~~~~~~~~~~~
.. doxygenstruct:: mockturtle::detail::window_resub_stats
:members:
.. doxygenstruct:: mockturtle::detail::sim_resub_stats
:members:

21
src/core/rewrite.hpp Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#include <mockturtle/algorithms/cut_rewriting.hpp>
#include <mockturtle/algorithms/node_resynthesis/akers.hpp>
#include <mockturtle/algorithms/node_resynthesis/exact.hpp>
#include <mockturtle/networks/aig.hpp>
#include <mockturtle/properties/mccost.hpp>
#include <mockturtle/traits.hpp>
#include <mockturtle/utils/cost_functions.hpp>
#include <mockturtle/views/fanout_view.hpp>
using namespace percy;
using namespace mockturtle;
namespace phyLS
{
template <class Ntk>
void aig_rewrite(Ntk& ntk) {
// please learn the algorithm of "mockturtle/algorithms/cut_rewriting.hpp"
}
}

45
src/core/rewrite.rst Normal file
View File

@ -0,0 +1,45 @@
Rewrite
=============
**Header:** ``mockturtle/algorithms/cut_rewriting.hpp``
The following example shows how to rewrite an MIG using precomputed optimum networks. In this case the maximum number of variables for a node function is 4.
It is possible to change the cost function of nodes in cut rewriting. Here is
an example, in which the cost function only accounts for AND gates in a network,
which corresponds to the multiplicative complexity of a function.
.. code-block:: c++
template<class Ntk>
struct mc_cost
{
uint32_t operator()( Ntk const& ntk, node<Ntk> const& n ) const
{
return ntk.is_and( n ) ? 1 : 0;
}
};
SomeResynthesisClass resyn;
ntk = cut_rewriting<SomeResynthesisClass, mc_cost>( ntk, resyn );
Parameters and statistics
~~~~~~~~~~~~~~~~~~~~~~~~~
.. doxygenstruct:: mockturtle::cut_rewriting_params
:members:
.. doxygenstruct:: mockturtle::cut_rewriting_stats
:members:
Algorithm
~~~~~~~~~
.. doxygenfunction:: mockturtle::cut_rewriting
.. doxygenfunction:: mockturtle::cut_rewriting_with_compatibility_graph
Rewriting functions
~~~~~~~~~~~~~~~~~~~
One can use resynthesis functions that can be passed to `node_resynthesis`, see
:ref:`node_resynthesis_functions`.

View File

@ -1,824 +0,0 @@
/* 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

View File

@ -1,210 +0,0 @@
#include "circuit_graph.hpp"
#include <iostream>
#include <map>
#include <set>
#include <sstream>
namespace phyLS {
Gate::Gate(Type type, line_idx output, std::vector<line_idx>&& inputs)
: m_type(type), m_inputs(inputs), m_output(output) {}
int Gate::make_gate_name(Type type) {
int lut = 0;
for (int i = 1; i < type.cols(); i++) {
lut = (lut << 1) + 1 - type(i);
}
return lut;
}
// 图的构造函数,预留一块空间
CircuitGraph::CircuitGraph() {
m_gates.reserve(5000u);
m_lines.reserve(5000u);
}
line_idx CircuitGraph::add_input(const std::string& name) {
line_idx p_line = ensure_line(name);
if (!m_lines[p_line].is_input) {
m_lines[p_line].is_input = true;
m_inputs.push_back(p_line);
}
return p_line;
}
line_idx CircuitGraph::add_output(const std::string& name) {
line_idx p_line = ensure_line(name);
if (!m_lines[p_line].is_output) {
m_lines[p_line].is_output = true;
m_outputs.push_back(p_line);
}
return p_line;
}
gate_idx CircuitGraph::add_gate(Type type,
const std::vector<std::string>& input_names,
const std::string& output_name) {
std::vector<line_idx> inputs;
// for (size_t i = 0; i < input_names.size(); ++i)
for (int i = input_names.size() - 1; i >= 0; i--) {
line_idx p_input = ensure_line(input_names[i]);
inputs.push_back(p_input);
}
line_idx p_output = ensure_line(output_name);
m_gates.emplace_back(type, p_output, std::move(inputs));
gate_idx gate = m_gates.size() - 1;
m_lines[p_output].source = gate;
m_gates.back().id() = gate;
for (size_t i = 0; i < m_gates[gate].get_inputs().size(); ++i) {
m_lines[m_gates[gate].get_inputs().at(i)].connect_as_input(gate);
}
return gate;
}
line_idx CircuitGraph::line(const std::string& name) {
auto it = m_name_to_line_idx.find(name);
if (it != m_name_to_line_idx.end()) {
return it->second;
}
return NULL_INDEX;
}
line_idx CircuitGraph::get_line(const std::string& name) const {
auto it = m_name_to_line_idx.find(name);
if (it != m_name_to_line_idx.end()) {
return it->second;
}
return NULL_INDEX;
}
const std::vector<line_idx>& CircuitGraph::get_inputs() const {
return m_inputs;
}
const std::vector<line_idx>& CircuitGraph::get_outputs() const {
return m_outputs;
}
const std::vector<Gate>& CircuitGraph::get_gates() const { return m_gates; }
std::vector<Gate>& CircuitGraph::get_gates() { return m_gates; }
const std::vector<Line>& CircuitGraph::get_lines() const { return m_lines; }
line_idx CircuitGraph::ensure_line(const std::string& name) {
auto it = m_name_to_line_idx.find(name);
if (it != m_name_to_line_idx.end()) {
return it->second;
}
m_lines.emplace_back();
Line& line = m_lines.back();
line.name = name;
line.id_line = m_lines.size() - 1;
m_name_to_line_idx[name] = m_lines.size() - 1;
return line.id_line;
}
void CircuitGraph::match_logic_depth() {
for (int i = 0, num = m_outputs.size(); i < num; i++) {
int level = compute_node_depth(m_lines[m_outputs[i]].source);
if (level > max_logic_depth) max_logic_depth = level;
}
m_node_level.resize(max_logic_depth + 1);
for (int i = 0; i < m_gates.size(); i++) {
m_node_level[m_gates[i].get_level()].push_back(i);
}
}
// 计算该节点的depth = max children's depth
int CircuitGraph::compute_node_depth(const gate_idx g_id) {
Gate& gate = m_gates[g_id];
// 如果已经被计算过 直接返回
if (gate.get_level() != NO_LEVEL) return gate.get_level();
// 访问所有子节点计算
int max_depth = NO_LEVEL;
int level = -1;
for (const auto& child : gate.get_inputs()) {
if (m_lines[child].is_input) continue;
level = compute_node_depth(m_lines[child].source);
if (level > max_depth) {
max_depth = level;
}
}
if (max_depth ==
NO_LEVEL) // 走出for循环max_depth没有改变说明该节点所有的输入线都是input
max_depth = -1;
m_gates[g_id].level() = max_depth + 1;
return m_gates[g_id].level();
}
void CircuitGraph::print_graph() {
// 打印INPUT
for (unsigned i = 0, length = m_inputs.size(); i < length; i++) {
std::cout << "INPUT(" << m_lines[m_inputs[i]].name << ")" << std::endl;
}
// 打印OUTPUT
for (unsigned i = 0, length = m_outputs.size(); i < length; i++) {
std::cout << "OUTPUT(" << m_lines[m_outputs[i]].name << ")" << std::endl;
}
// 打印gate
for (unsigned i = 0, length = m_gates.size(); i < length; i++) {
auto& gate = m_gates[i];
std::cout << m_lines[gate.get_output()].name << " = LUT 0x" << std::hex
<< int(gate.make_gate_name(gate.get_type())) << "(";
std::vector<std::string> inputs_name;
// for(const auto& input : gate.get_inputs())
for (int i = gate.get_inputs().size() - 1; i > -1; i--) {
inputs_name.push_back(m_lines[gate.get_inputs()[i]].name);
inputs_name.push_back(", ");
}
inputs_name.pop_back();
for (const auto& temp : inputs_name) std::cout << temp;
std::cout << ")" << std::endl;
}
// //打印逻辑深度的信息
// int level = -1;
// std::cout << "*************************************" << std::endl;
// for(const auto& t1 : m_node_level)
// {
// level++;
// std::cout << "lev = " << level << " : ";
// for(const auto& t2 : t1)
// {
// std::cout << t2 << " ";
// }
// std::cout << std::endl;
// }
// //遍历所有的线 打印线的前后节点信息
// for(const auto& line : m_lines)
// {
// std::cout << "*************************************" << std::endl;
// std::cout << "name: " << line.name << " ";
// if(line.is_input)
// std::cout << "input" << " /";
// if(line.is_output)
// std::cout << "output" << " /";
// if(!line.is_input)
// std::cout << "source: " << line.source << std::endl;
// if(!line.is_output)
// {
// std::cout << "destination_gates: ";
// for(const auto& gate : line.destination_gates)
// std::cout << gate << " ";
// std::cout << std::endl;
// }
// }
}
} // namespace phyLS

View File

@ -1,136 +0,0 @@
#ifndef CIRCUIT_GRAPH_H
#define CIRCUIT_GRAPH_H
#include <cassert>
#include <cstdint>
#include <deque>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <limits>
#include <set>
#include <sstream>
#include <string>
#include <unordered_map>
#include <vector>
#include "stp_vector.hpp"
#define NULL_INDEX -1
#define NO_LEVEL -10000
namespace phyLS {
using gate_idx = int;
using line_idx = int;
using node_level = int;
using Type = stp_vec;
class Gate;
class CircuitGraph;
struct Line {
void connect_as_input(gate_idx gate) { destination_gates.insert(gate); }
gate_idx source = NULL_INDEX; // nullptr means input port
std::set<gate_idx> destination_gates;
bool is_input = false;
bool is_output = false;
int id_line = NULL_INDEX;
std::string name;
};
class Gate {
public:
Gate(Type type, line_idx output,
std::vector<line_idx> &&inputs); // 构造一般gate
Type get_type() const { return m_type; }
Type &type() { return m_type; }
const std::vector<line_idx> &get_inputs() const { return m_inputs; }
std::vector<line_idx> &inputs() { return m_inputs; }
const line_idx &get_output() const { return m_output; }
line_idx &output() { return m_output; }
const int &get_id() const { return m_id; }
int &id() { return m_id; }
const int &get_level() const { return m_level; }
int &level() { return m_level; }
bool is_input() const { return m_type.cols() == 0; }
int make_gate_name(Type type);
private:
Type m_type;
int m_id = NULL_INDEX;
node_level m_level = NO_LEVEL;
std::vector<line_idx> m_inputs;
line_idx m_output = NULL_INDEX;
};
class CircuitGraph {
public:
CircuitGraph();
line_idx add_input(const std::string &name);
line_idx add_output(const std::string &name);
gate_idx add_gate(Type type, const std::vector<std::string> &input_names,
const std::string &output_name);
line_idx get_line(const std::string &name) const;
line_idx line(const std::string &name);
const Gate &get_gate(const gate_idx &idx) const { return m_gates[idx]; }
Gate &gate(const gate_idx &idx) { return m_gates[idx]; }
const Line &get_line(const line_idx &idx) const { return m_lines[idx]; }
Line &line(const line_idx &idx) { return m_lines[idx]; }
const std::vector<line_idx> &get_inputs() const;
std::vector<line_idx> &inputs() { return m_inputs; }
const std::vector<line_idx> &get_outputs() const;
std::vector<line_idx> &outputs() { return m_outputs; }
const std::vector<Gate> &get_gates() const;
std::vector<Gate> &get_gates();
const std::vector<Line> &get_lines() const;
std::vector<Line> &lines() { return m_lines; }
const std::vector<std::vector<gate_idx>> &get_m_node_level() const {
return m_node_level;
}
std::vector<std::vector<gate_idx>> &get_m_node_level() {
return m_node_level;
}
const int &get_mld() const { return max_logic_depth; }
void match_logic_depth();
void print_graph();
private:
line_idx ensure_line(const std::string &name);
int compute_node_depth(const gate_idx g_id);
private:
std::vector<Line> m_lines;
std::vector<Gate> m_gates;
std::vector<line_idx> m_inputs;
std::vector<line_idx> m_outputs;
std::vector<std::vector<gate_idx>> m_node_level;
int max_logic_depth = -1;
public:
std::unordered_map<std::string, line_idx> m_name_to_line_idx;
};
} // namespace phyLS
#endif

View File

@ -1,189 +0,0 @@
#include "lut_parser.hpp"
#include <algorithm>
#include <string>
namespace phyLS {
bool LutParser::parse(std::istream& is, CircuitGraph& graph) {
const std::string flag_input = "INPUT";
const std::string flag_output = "OUTPUT";
const std::string flag_lut = "LUT";
const std::string flag_gnd = "gnd";
for (std::string line; std::getline(is, line, '\n');) {
if (line.empty()) continue;
if (line.find(flag_input) != std::string::npos) {
match_input(graph, line);
continue;
}
if (line.find(flag_output) != std::string::npos) {
match_output(graph, line);
continue;
}
if (line.find(flag_lut) != std::string::npos) {
match_gate(graph, line);
continue;
}
}
return true;
}
bool LutParser::match_input(CircuitGraph& graph, const std::string& line) {
std::string input_name = m_split(line, "( )")[1];
graph.add_input(input_name);
return true;
}
bool LutParser::match_output(CircuitGraph& graph, const std::string& line) {
std::string output_name = m_split(line, "( )")[1];
graph.add_output(output_name);
return true;
}
bool LutParser::match_gate(CircuitGraph& graph, const std::string& line) {
std::vector<std::string> gate = m_split(line, ",=( )");
std::string output = gate[0];
std::string tt = gate[2];
gate.erase(gate.begin(), gate.begin() + 3);
std::vector<std::string> inputs(gate);
tt.erase(0, 2); // 删除0x
Type type = get_stp_vec(tt, inputs.size());
graph.add_gate(type, inputs, output);
return true;
}
stp_vec LutParser::get_stp_vec(const std::string& tt, const int& inputs_num) {
// 只有一个输入的节点(buff 或 not)
if (inputs_num == 1 && tt.size() == 1) {
stp_vec type(3);
type(0) = 2;
switch (tt[0]) {
case '0':
type(1) = 1;
type(2) = 1;
break;
case '1':
type(1) = 1;
type(2) = 0;
break;
case '2':
type(1) = 0;
type(2) = 1;
break;
case '3':
type(1) = 0;
type(2) = 0;
break;
default:
break;
}
return type;
}
stp_vec type((1 << inputs_num) + 1);
type(0) = 2;
int type_idx;
for (int i = 0, len = tt.size(); i < len; i++) {
type_idx = 4 * i + 1;
switch (tt[i]) {
case '0': // 0000 - > 1111
type(type_idx) = 1;
type(type_idx + 1) = 1;
type(type_idx + 2) = 1;
type(type_idx + 3) = 1;
break;
case '1': // 0001 - > 1110
type(type_idx) = 1;
type(type_idx + 1) = 1;
type(type_idx + 2) = 1;
type(type_idx + 3) = 0;
break;
case '2': // 0010 - > 1101
type(type_idx) = 1;
type(type_idx + 1) = 1;
type(type_idx + 2) = 0;
type(type_idx + 3) = 1;
break;
case '3': // 0011 - > 1100
type(type_idx) = 1;
type(type_idx + 1) = 1;
type(type_idx + 2) = 0;
type(type_idx + 3) = 0;
break;
case '4': // 0100 - > 1011
type(type_idx) = 1;
type(type_idx + 1) = 0;
type(type_idx + 2) = 1;
type(type_idx + 3) = 1;
break;
case '5': // 0101 - > 1010
type(type_idx) = 1;
type(type_idx + 1) = 0;
type(type_idx + 2) = 1;
type(type_idx + 3) = 0;
break;
case '6': // 0110 - > 1001
type(type_idx) = 1;
type(type_idx + 1) = 0;
type(type_idx + 2) = 0;
type(type_idx + 3) = 1;
break;
case '7': // 0111 - > 1000
type(type_idx) = 1;
type(type_idx + 1) = 0;
type(type_idx + 2) = 0;
type(type_idx + 3) = 0;
break;
case '8': // 1000 - > 0111
type(type_idx) = 0;
type(type_idx + 1) = 1;
type(type_idx + 2) = 1;
type(type_idx + 3) = 1;
break;
case '9': // 1001 - > 0110
type(type_idx) = 0;
type(type_idx + 1) = 1;
type(type_idx + 2) = 1;
type(type_idx + 3) = 0;
break;
case 'a': // 1010 - > 0101
type(type_idx) = 0;
type(type_idx + 1) = 1;
type(type_idx + 2) = 0;
type(type_idx + 3) = 1;
break;
case 'b': // 1011 - > 0100
type(type_idx) = 0;
type(type_idx + 1) = 1;
type(type_idx + 2) = 0;
type(type_idx + 3) = 0;
break;
case 'c': // 1100 - > 0011
type(type_idx) = 0;
type(type_idx + 1) = 0;
type(type_idx + 2) = 1;
type(type_idx + 3) = 1;
break;
case 'd': // 1101 - > 0010
type(type_idx) = 0;
type(type_idx + 1) = 0;
type(type_idx + 2) = 1;
type(type_idx + 3) = 0;
break;
case 'e': // 1110 - > 0001
type(type_idx) = 0;
type(type_idx + 1) = 0;
type(type_idx + 2) = 0;
type(type_idx + 3) = 1;
break;
case 'f': // 1111 - > 0000
type(type_idx) = 0;
type(type_idx + 1) = 0;
type(type_idx + 2) = 0;
type(type_idx + 3) = 0;
break;
default:
break;
}
}
return type;
}
} // namespace phyLS

View File

@ -1,20 +0,0 @@
#ifndef LUT_PARSER_HPP
#define LUT_PARSER_HPP
#include "circuit_graph.hpp"
#include "myfunction.hpp"
namespace phyLS {
class LutParser {
public:
bool parse(std::istream& is, CircuitGraph& graph);
private:
bool match_input(CircuitGraph& graph, const std::string& line);
bool match_output(CircuitGraph& graph, const std::string& line);
bool match_gate(CircuitGraph& graph, const std::string& line);
Type get_stp_vec(const std::string& tt, const int& inputs_num);
};
} // namespace phyLS
#endif

View File

@ -1,40 +0,0 @@
#ifndef MYFUNCTION_HPP
#define MYFUNCTION_HPP
#include <iostream>
#include <string>
#include <vector>
namespace phyLS {
static std::vector<std::string> m_split(const std::string& input,
const std::string& pred) {
std::vector<std::string> result;
std::string temp = "";
unsigned count1 = input.size();
unsigned count2 = pred.size();
unsigned j;
for (size_t i = 0; i < count1; i++) {
for (j = 0; j < count2; j++) {
if (input[i] == pred[j]) {
break;
}
}
// if input[i] != pred中的任何一个 该字符加到temp上
if (j == count2)
temp += input[i];
else {
if (!temp.empty()) {
result.push_back(temp);
temp.clear();
}
}
}
return result;
}
static void seg_fault(const std::string& name, int size, int idx) {
std::cout << name << " " << size << " : " << idx << std::endl;
}
} // namespace phyLS
#endif

View File

@ -1,256 +0,0 @@
#include "simulator.hpp"
#include<algorithm>
namespace phyLS {
simulator::simulator(CircuitGraph& graph) : graph(graph) {
pattern_num = 10000; // 随机产生100个仿真向量
// max_branch = int( log2(pattern_num) ); //做cut的界
max_branch = 8;
sim_info.resize(graph.get_lines().size()); // 按照lines的id记录仿真向量的信息
lines_flag.resize(graph.get_lines().size(), false); // 按照线的id给线做标记
for (const line_idx& line_id : graph.get_inputs()) {
sim_info[line_id].resize(pattern_num);
lines_flag[line_id] = true;
for (int i = 0; i < pattern_num; i++) {
sim_info[line_id][i] = rand() % 2;
}
}
}
std::vector<std::vector<int>> simulator::generateBinary(int n)//generate n bit binary
{
std::vector<std::vector<int>> nbitBinary;//store n bit binary
for(int i = 0;i < (1 << n); i++)
{
std::string s = "";
for (int j = 0; j < n; j++)
{
if (i & (1 << j))
{
s += "1";
}
else
{
s += "0";
}
}
reverse(s.begin(), s.end());
std::vector<int> vec;//single n bit binary
for(auto c : s)
{
vec.push_back(std::stoi(std::string(1,c)));//stoi (string to int)
}
nbitBinary.push_back(vec);
}
return nbitBinary;
}
bool simulator::simulate() {
// 1: 给电路划分层级
graph.match_logic_depth();
// 2: 确定电路中需要仿真的nodes
need_sim_nodes nodes = get_need_nodes();
// 3: 仿真
for (const auto& node : nodes) {
single_node_sim(node);
}
return true;
}
bool simulator::full_simulate() {
std::vector<std::vector<int>> nbitBinary = generateBinary(graph.get_inputs().size());
pattern_num = nbitBinary.size();
for (const line_idx& line_id : graph.get_inputs())
{
sim_info[line_id].resize(pattern_num);
lines_flag[line_id] = true;
for (int i = 0; i < pattern_num; i++)
{
sim_info[line_id][i] = nbitBinary[i][line_id];//生成全仿真的真值表
}
}
graph.match_logic_depth();
need_sim_nodes nodes = get_need_nodes();
for (const auto& node : nodes) {
single_node_sim(node);
}
//get the truth table
int po0_index = graph.get_inputs().size();
int pon_index = po0_index + graph.get_outputs().size() - 1;
std::vector<std::vector<int>> outputs_tt;
//std::vector<std::vector<int>> nbitBinary = generateBinary(graph.get_inputs().size());
for(int i = po0_index;i <= pon_index; i++)
{
std::vector<int> int_vector(sim_info[i].begin(), sim_info[i].end());
outputs_tt.push_back(int_vector);
std::reverse(outputs_tt[i - po0_index].begin(), outputs_tt[i - po0_index].end());
}
std::vector<std::string> hex_strings;
for(const auto& binary_vector : outputs_tt)
{
std::stringstream hex_stream;
for (int i = 0; i < binary_vector.size(); i += 4)
{
int sum = binary_vector[i] * 8 + binary_vector[i+1] * 4 + binary_vector[i+2] * 2 + binary_vector[i+3];
hex_stream << std::hex << sum;
}
hex_strings.push_back(hex_stream.str());
}
for(int i = 0;i < graph.get_outputs().size(); i++)
{
std::cout << "turth table of po" << i << " is: 0x" << hex_strings[i] << std::endl;
}
return true;
}
need_sim_nodes simulator::get_need_nodes() {
need_sim_nodes nodes;
for (const auto& nodes_id : graph.get_m_node_level()) {
for (const auto& node_id : nodes_id) {
const auto& node = graph.get_gates()[node_id];
const auto& output = graph.get_lines()[node.get_output()];
// 如果是output节点或多扇出节点则需要仿真
if (output.is_output || output.destination_gates.size() > fanout_limit) {
nodes.clear();
lines_flag[node.get_output()] = true; // 给需要仿真的节点打标记
nodes.push_back(node_id);
cut_tree(nodes);
}
nodes.push_back(node_id);
}
}
nodes.clear();
for (unsigned level = 0; level <= graph.get_mld(); level++) {
for (const auto& node_id : graph.get_m_node_level()[level]) {
line_idx output = graph.get_gates()[node_id].get_output();
//lines_flag[output] = true;
if (lines_flag[output] == true) {
nodes.push_back(node_id);
}
}
}
return nodes;
}
// 广度优先遍历 cut tree
void simulator::cut_tree(need_sim_nodes& nodes) {
need_sim_nodes temp_nodes;
const auto& graph_lines = graph.get_lines();
const auto& graph_gates = graph.get_gates();
while (!nodes.empty()) {
temp_nodes.clear();
temp_nodes.push_back(nodes.front());
nodes.pop_front();
int count = 0;
while (1) {
for (const auto& input : graph_gates[temp_nodes.front()].get_inputs()) {
count++;
if (lines_flag[input] == false) {
temp_nodes.push_back(graph_lines[input].source);
}
}
temp_nodes.pop_front();
count--;
// 对应该两种情况 (确实是棵大树,将其化为小树 || 本就是一颗小树)
if (count > max_branch || temp_nodes.empty()) {
break;
}
}
for (const auto& node_id : temp_nodes) {
lines_flag[graph_gates[node_id].get_output()] = true;
nodes.push_back(node_id);
}
}
}
void simulator::single_node_sim(const gate_idx node_id) {
const auto& node = graph.get_gates()[node_id];
const gate_idx& output = node.get_output();
// 1:生成矩阵链
std::map<line_idx, int> map;
m_chain matrix_chain;
get_node_matrix(node_id, matrix_chain, map);
// 2:分析矩阵链,减少变量个数
stp_logic_manage stp;
stp_vec root_stp_vec = stp.normalize_matrix(matrix_chain);
// 3:仿真
std::vector<line_idx> variable(map.size());
int inputs_number = variable.size();
for (const auto& temp : map) variable[temp.second - 1] = temp.first;
sim_info[output].resize(pattern_num);
int idx;
int bits = 1 << inputs_number;
for (int i = 0; i < pattern_num; i++) {
idx = 0;
for (int j = 0; j < inputs_number; j++) {
idx = (idx << 1) + sim_info[variable[j]][i];
}
idx = bits - idx;
sim_info[output][i] = 1 - root_stp_vec(idx);
}
lines_flag[output] = true;
}
// 对于某个cut 生成matrix chain
void simulator::get_node_matrix(const gate_idx node_id, m_chain& mc,
std::map<line_idx, int>& map) {
const auto& node = graph.get_gates()[node_id];
mc.push_back(node.get_type());
int temp;
for (const auto& line_id : node.get_inputs()) {
if (lines_flag[line_id]) // 存变量
{
if (map.find(line_id) == map.end()) {
temp = map.size() + 1;
map.emplace(line_id, map.size() + 1);
} else
temp = map.at(line_id);
mc.emplace_back(1, temp);
} else // 存lut (PIs)的lines_flag必为true 所以这种情况不可能出现source为空
get_node_matrix(graph.get_lines()[line_id].source, mc, map);
}
}
void simulator::print_simulation_result() {
std::cout << "PI/PO : " << graph.get_inputs().size() << "/"
<< graph.get_outputs().size() << std::endl;
for (const auto& input_id : graph.get_inputs()) {
std::cout << graph.get_lines()[input_id].name << " ";
}
std::cout << ": ";
for (const auto& output_id : graph.get_outputs()) {
std::cout << graph.get_lines()[output_id].name << " ";
}
std::cout << std::endl;
for (int i = 0; i < pattern_num; i++) {
for (const auto& input_id : graph.get_inputs()) {
std::cout << sim_info[input_id][i] << " ";
}
std::cout << ": ";
for (const auto& output_id : graph.get_outputs()) {
std::cout << sim_info[output_id][i] << " ";
}
std::cout << std::endl;
}
}
bool simulator::check_sim_info() {
for (int i = 0; i < sim_info.size(); i++) {
if (sim_info[i].size() != pattern_num) {
std::cout << "!" << std::endl;
return false;
}
for (int j = 0; j < sim_info[i].size(); j++) {
if (sim_info[i][j] != 0 && sim_info[i][j] != 1) {
std::cout << "!" << std::endl;
return false;
}
}
}
std::cout << "^ ^" << std::endl;
return true;
}
} // namespace phyLS

View File

@ -1,50 +0,0 @@
#ifndef C_SIMLUATOR_HPP
#define C_SIMLUATOR_HPP
#include <deque>
#include <iostream>
#include <map>
#include <random>
#include <string>
#include <vector>
#include "circuit_graph.hpp"
#include "myfunction.hpp"
namespace phyLS {
using need_sim_nodes = std::deque<gate_idx>;
using line_sim_info = std::vector<u_int16_t>;
class simulator {
public:
simulator(CircuitGraph& graph);
bool simulate(); // simulate
bool full_simulate(); //full_simulate
std::vector<std::vector<int>> generateBinary(int n);
void print_simulation_result();
private:
bool is_simulated(const line_idx id) {
return sim_info[id].size() == pattern_num;
}
need_sim_nodes get_need_nodes();
void single_node_sim(const gate_idx node);
void get_node_matrix(const gate_idx node, m_chain& mc,
std::map<line_idx, int>& map);
void cut_tree(need_sim_nodes& nodes);
bool check_sim_info();
private:
std::vector<line_sim_info> sim_info;
std::vector<int> time_interval;
std::vector<bool> lines_flag;
CircuitGraph& graph;
int pattern_num;
int max_branch;
int fanout_limit = 1;
};
} // namespace phyLS
#endif

View File

@ -1,260 +0,0 @@
#ifndef STP_VECTOR_HPP
#define STP_VECTOR_HPP
#include <iostream>
#include <list>
#include <vector>
#include "myfunction.hpp"
namespace phyLS {
class stp_vec;
using word = unsigned;
using m_chain = std::vector<stp_vec>;
class stp_vec {
// 重载打印操作符
friend std::ostream &operator<<(std::ostream &os, const stp_vec &v) {
const unsigned length = v.cols();
for (unsigned i = 0; i < length; ++i) os << v.vec[i] << " ";
os << std::endl;
return os;
}
// 重载初始化操作符
friend std::istream &operator>>(std::istream &is, stp_vec &v) {
const unsigned length = v.cols();
for (unsigned i = 0; i < length; ++i) is >> v.vec[i];
return is;
}
public:
// 各种初始化操作
stp_vec() { this->vec.clear(); }
stp_vec(unsigned cols, unsigned value = 0) { this->vec.resize(cols, value); }
stp_vec(const stp_vec &v) { this->vec = v.vec; }
stp_vec &operator=(const stp_vec &v) {
this->vec = v.vec;
return *this;
}
// 重载==
bool operator==(const stp_vec &v) {
unsigned m_length = this->cols();
unsigned length = v.cols();
if (m_length != length) return false;
for (unsigned i = 0; i < length; ++i) {
if (this->vec[i] != v.vec[i]) {
return false;
}
}
return true;
}
// 重载()
word &operator()(unsigned idx) { return vec[idx]; }
const word &operator()(unsigned idx) const { return vec[idx]; }
// 获取矩阵的列数
unsigned cols() const { return this->vec.size(); }
// 判断是不是一个变量
bool is_variable() { return this->cols() == 1; }
// 块赋值
bool block(const stp_vec &v, int m_begin, int begin, int num) {
if (this->cols() < num || v.cols() < num) {
std::cout << "block abnormal" << std::endl;
return false;
}
for (unsigned i = 0; i < num; ++i) {
this->vec[m_begin + i] = v.vec[begin + i];
}
return true;
}
private:
private:
std::vector<word> vec; // 可以对比一下vector 与 deque
};
class stp_logic_manage {
public:
// 生成一个交换矩阵
stp_vec logic_swap_matrix(int m, int n) {
stp_vec result(m * n + 1);
int p, q;
result(0) = m * n;
for (int i = 0; i < m * n; i++) {
p = i / m;
q = i % m;
int j = q * n + p;
result(j + 1) = i;
}
return result;
}
// 克罗内克积
stp_vec logic_kron_product(const stp_vec &v_f, const stp_vec &v_b) {
int m = v_f(0);
int n = v_f.cols() - 1;
int p = v_b(0);
int q = v_b.cols() - 1;
stp_vec result(n * q + 1);
result(0) = m * p;
for (int i = 0; i < n; i++) {
int temp = v_f(i + 1) * p;
int idx = i * q + 1;
for (int j = 0; j < q; j++) {
result(idx + j) = temp + v_b(j + 1);
}
}
return result;
}
// 两矩阵乘法
stp_vec logic_stpm_product(const stp_vec &v_f, const stp_vec &v_b) {
int mf_row = v_f(0); // m
int mf_col = v_f.cols() - 1; // n
int mb_row = v_b(0); // p
int mb_col = v_b.cols() - 1; // q
int row, col;
stp_vec result;
if (mf_col % mb_row == 0) {
int times = mf_col / mb_row;
row = mf_row;
col = times * mb_col;
stp_vec result_matrix(col + 1);
result_matrix(0) = row;
for (int i = 1; i <= mb_col; ++i) {
result_matrix.block(v_f, 1 + times * (i - 1), times * v_b(i) + 1,
times);
}
return result_matrix;
} else if (mb_row % mf_col == 0) {
int times = mb_row / mf_col;
stp_vec i_times(times + 1);
i_times(0) = times;
// 单位矩阵的编码向量
for (int i = 1; i <= times; i++) {
i_times(i) = i - 1;
}
return logic_stpm_product(logic_kron_product(v_f, i_times), v_b);
} else {
std::cout << v_f << v_b << std::endl;
std::cout << "matrix type error!" << std::endl;
}
return result;
}
// 矩阵链乘法
stp_vec matrix_chain_mul(const m_chain &matrix_chain) {
if (matrix_chain.size() == 1) return matrix_chain[0];
stp_vec result;
result = logic_stpm_product(matrix_chain[0], matrix_chain[1]);
for (int i = 2; i < matrix_chain.size(); i++) {
result = logic_stpm_product(result, matrix_chain[i]);
}
return result;
}
// 化为规范型 提前给出变量的信息
stp_vec normalize_matrix(m_chain &vec_chain) {
stp_vec Mr(3);
Mr(0) = 4;
Mr(1) = 0;
Mr(2) = 3; // Reduced power matrix
stp_vec I2(3);
I2(0) = 2;
I2(1) = 0;
I2(2) = 1;
stp_vec normal_matrix;
int p_variable;
int p;
int max = 0;
for (int i = 0; i < vec_chain.size();
i++) // the max is the number of variable
{
if (vec_chain[i].is_variable() && vec_chain[i](0) > max) {
max = vec_chain[i](0);
}
}
// 处理直接就是规范型的矩阵链
if (vec_chain.size() == max + 1) return vec_chain[0];
// 常规处理
std::vector<int> idx(max + 1); // id0 is the max of idx
p_variable = vec_chain.size() - 1;
int flag;
while (p_variable >= 0) {
int flag = 0;
if (vec_chain[p_variable].is_variable()) // 1:find a variable
{
if (idx[vec_chain[p_variable](0)] == 0) {
idx[vec_chain[p_variable](0)] = idx[0] + 1;
idx[0]++;
if (p_variable == vec_chain.size() - 1) //!
{
vec_chain.pop_back();
p_variable--;
continue;
}
} else {
if (idx[vec_chain[p_variable](0)] == idx[0]) {
flag = 1;
if (p_variable == vec_chain.size() - 1) {
vec_chain.pop_back();
vec_chain.push_back(Mr);
continue;
}
} else {
flag = 1;
vec_chain.push_back(logic_swap_matrix(
2, 1 << (idx[0] - idx[vec_chain[p_variable](0)])));
for (int i = 1; i <= max; i++) {
if (idx[i] != 0 && idx[i] > idx[vec_chain[p_variable](0)])
idx[i]--;
}
idx[vec_chain[p_variable](0)] = idx[0];
}
}
m_chain matrix_chain1; //?
matrix_chain1.clear();
for (p = p_variable + 1; p < vec_chain.size(); p++) {
matrix_chain1.push_back(vec_chain[p]); // have no matrix
}
while (p > p_variable + 1) {
vec_chain.pop_back();
p--;
}
if (matrix_chain1.size() > 0) {
vec_chain.push_back(matrix_chain_mul(matrix_chain1));
}
if (p_variable != vec_chain.size() - 1) {
vec_chain[p_variable] =
logic_kron_product(I2, vec_chain[p_variable + 1]);
vec_chain.pop_back();
}
if (flag) vec_chain.push_back(Mr);
continue;
} else {
p_variable--;
}
}
// 后续矩阵链中已经没有变量
for (int i = max; i > 0; i--) //!
{
vec_chain.push_back(logic_swap_matrix(2, 1 << (idx[0] - idx[i])));
for (int j = 1; j <= max; j++) {
if (idx[j] != 0 && idx[j] > idx[i]) idx[j]--;
}
idx[i] = max;
}
normal_matrix = matrix_chain_mul(vec_chain);
return normal_matrix;
}
private:
};
} // namespace phyLS
#endif

View File

@ -1,544 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2022 */
/**
* @file stp_functional_reduction.hpp
*
* @brief performs functional reduction
*
* @author Homyoung
* @since 2023/03/31
*/
#pragma once
#include <bill/sat/interface/abc_bsat2.hpp>
#include <kitty/partial_truth_table.hpp>
#include <list>
#include <map>
#include <mockturtle/algorithms/circuit_validator.hpp>
#include <mockturtle/algorithms/simulation.hpp>
#include <mockturtle/io/write_patterns.hpp>
#include <mockturtle/utils/progress_bar.hpp>
#include <mockturtle/utils/stopwatch.hpp>
#include <mockturtle/views/fanout_view.hpp>
#include <sstream>
#include <vector>
using namespace mockturtle;
namespace phyLS {
struct stp_functional_reduction_params {
/*! \brief Show progress. */
bool progress{false};
/*! \brief Be verbose. */
bool verbose{false};
/*! \brief Maximum number of iterations to run. 0 = repeat until no further
* improvement can be found. */
uint32_t max_iterations{10};
/*! \brief Whether to use pre-generated patterns stored in a file.
* If not, by default, 256 random patterns will be used.
*/
std::optional<std::string> pattern_filename{};
/*! \brief Whether to save the appended patterns (with CEXs) into file. */
std::optional<std::string> save_patterns{};
std::string equi_classes{};
/*! \brief Maximum number of nodes in the transitive fanin cone (and their
* fanouts) to be compared to. */
uint32_t max_TFI_nodes{1000};
/*! \brief Maximum fanout count of a node in the transitive fanin cone to
* explore its fanouts. */
uint32_t skip_fanout_limit{100};
/*! \brief Conflict limit for the SAT solver. */
uint32_t conflict_limit{100};
/*! \brief Maximum number of clauses of the SAT solver. (incremental CNF
* construction) */
uint32_t max_clauses{1000};
/*! \brief Initial number of (random) simulation patterns. */
uint32_t num_patterns{256};
/*! \brief Maximum number of simulation patterns. Discards all patterns and
* re-seeds with random patterns when exceeded. */
uint32_t max_patterns{1024};
};
struct stp_functional_reduction_stats {
/*! \brief Total runtime. */
stopwatch<>::duration time_total{0};
/*! \brief Time for simulation. */
stopwatch<>::duration time_sim{0};
/*! \brief Time for SAT solving. */
stopwatch<>::duration time_sat{0};
/*! \brief Number of accepted constant nodes. */
uint32_t num_const_accepts{0};
/*! \brief Number of accepted functionally equivalent nodes. */
uint32_t num_equ_accepts{0};
/*! \brief Number of counter-examples (SAT calls). */
uint32_t num_cex{0};
/*! \brief Number of successful node reductions (UNSAT calls). */
uint32_t num_reduction{0};
/*! \brief Number of SAT solver timeout. */
uint32_t num_timeout{0};
void report() const {
// clang-format off
std::cout << "[i] Functional Reduction\n";
std::cout << "[i] ======== Stats ========\n";
std::cout << fmt::format( "[i] #constant = {:8d}\n", num_const_accepts );
std::cout << fmt::format( "[i] #FE pairs = {:8d}\n", num_equ_accepts );
std::cout << fmt::format( "[i] #SAT = {:8d}\n", num_cex );
std::cout << fmt::format( "[i] #UNSAT = {:8d}\n", num_reduction );
std::cout << fmt::format( "[i] #TIMEOUT = {:8d}\n", num_timeout );
std::cout << "[i] ======== Runtime ========\n";
std::cout << fmt::format( "[i] total : {:>5.2f} secs\n", to_seconds( time_total ) );
std::cout << fmt::format( "[i] simulation : {:>5.2f} secs\n", to_seconds( time_sim ) );
std::cout << fmt::format( "[i] SAT solving: {:>5.2f} secs\n", to_seconds( time_sat ) );
std::cout << "[i] =========================\n\n";
// clang-format on
}
};
namespace detail {
template <typename Ntk,
typename validator_t = circuit_validator<Ntk, bill::solvers::bsat2>>
class stp_functional_reduction_impl {
public:
using node = typename Ntk::node;
using signal = typename Ntk::signal;
using TT = unordered_node_map<kitty::partial_truth_table, Ntk>;
explicit stp_functional_reduction_impl(
Ntk& ntk, stp_functional_reduction_params const& ps,
validator_params const& vps, stp_functional_reduction_stats& st)
: ntk(ntk),
ps(ps),
st(st),
tts(ntk),
sim(ps.pattern_filename ? partial_simulator(*ps.pattern_filename)
: partial_simulator(ntk.num_pis(), 256)),
validator(ntk, vps) {
static_assert(!validator_t::use_odc_,
"`circuit_validator::use_odc` flag should be turned off.");
}
~stp_functional_reduction_impl() {
if (ps.save_patterns) {
write_patterns(sim, *ps.save_patterns);
}
}
void run() {
stopwatch t(st.time_total);
/* first simulation: the whole circuit; from 0 bits. */
call_with_stopwatch(st.time_sim,
[&]() { simulate_nodes<Ntk>(ntk, tts, sim, true); });
/* remove constant nodes. */
stp_constant_select();
stp_substitute_constants();
/* substitute functional equivalent nodes. */
auto size_before = ntk.size();
stp_substitute_equivalent_nodes();
uint32_t iterations{0};
while (ps.max_iterations && iterations++ <= ps.max_iterations &&
ntk.size() != size_before) {
size_before = ntk.size();
stp_substitute_equivalent_nodes();
}
// std::cout << "final equ classes\n";
// for (auto x :equ_classes)
// {
// std::cout << x.first << " - ";
// for (auto y : x.second) {
// std::cout << y << " ";
// }
// std::cout << std::endl;
// }
}
private:
void stp_constant_select() {
unordered_node_map<kitty::partial_truth_table, Ntk> node_to_value(ntk);
simulate_nodes(ntk, node_to_value, sim);
bool target = true;
ntk.foreach_gate([&](auto const& n) {
for (auto x : node_to_value[n]._bits) {
if (x == 0)
continue;
else {
target = false;
break;
}
}
if (target) const0.push_back(n);
});
}
void stp_substitute_constants() {
auto zero = sim.compute_constant(false);
auto one = sim.compute_constant(true);
for (auto n : const0) {
check_tts(n);
bool const_value;
if (tts[n] == zero)
const_value = false;
else if (tts[n] == one)
const_value = true;
else /* not constant */
continue; /* next */
const auto res = call_with_stopwatch(
st.time_sat, [&]() { return validator.validate(n, const_value); });
if (!res) /* timeout */
{
++st.num_timeout;
continue;
} else if (!(*res)) /* SAT, cex found */
{
found_cex();
zero = sim.compute_constant(false);
one = sim.compute_constant(true);
} else /* UNSAT, constant verified */
{
++st.num_reduction;
++st.num_const_accepts;
/* update network */
ntk.substitute_node(n, ntk.get_constant(const_value));
}
}
}
void stp_equivalent_classes(const std::string& filename) {
std::ifstream in(filename, std::ifstream::in);
std::string line;
while (getline(in, line)) {
std::vector<int> nums;
stringstream ss(line);
int num;
while (ss >> num) nums.push_back(num);
int key = nums[0];
nums.erase(nums.begin());
equ_classes[key] = nums;
}
in.close();
}
void stp_substitute_equivalent_nodes() {
stp_equivalent_classes(ps.equi_classes);
for (auto x : equ_classes) {
check_tts(x.first);
auto tt = tts[x.first];
auto ntt = ~tts[x.first];
std::vector<node> tfi;
bool keep_trying = true;
foreach_transitive_fanin(x.first, [&](auto const& n) {
tfi.emplace_back(n);
if (tfi.size() > ps.max_TFI_nodes) {
return false;
}
keep_trying = try_node(tt, ntt, x.first, n);
return keep_trying;
});
if (keep_trying) /* didn't find a substitution in TFI cone, explore
fanouts. */
{
for (auto j = 0u;
j < tfi.size() && tfi.size() <= ps.max_TFI_nodes && keep_trying;
++j) {
auto& n = tfi.at(j);
if (ntk.fanout_size(n) > ps.skip_fanout_limit) {
continue;
}
/* if the fanout has all fanins in the set, add it */
ntk.foreach_fanout(n, [&](node const& p) {
if (ntk.visited(p) == ntk.trav_id()) {
return true; /* next fanout */
}
bool all_fanins_visited = true;
ntk.foreach_fanin(p, [&](const auto& g) {
if (ntk.visited(ntk.get_node(g)) != ntk.trav_id()) {
all_fanins_visited = false;
return false; /* terminate fanin-loop */
}
return true; /* next fanin */
});
if (!all_fanins_visited) {
return true; /* next fanout */
}
bool has_root_as_child = false;
ntk.foreach_fanin(p, [&](const auto& g) {
if (ntk.get_node(g) == x.first) {
has_root_as_child = true;
return false; /* terminate fanin-loop */
}
return true; /* next fanin */
});
if (has_root_as_child) {
return true; /* next fanout */
}
tfi.emplace_back(p);
ntk.set_visited(p, ntk.trav_id());
check_tts(p);
keep_trying = try_node(tt, ntt, x.first, p);
return keep_trying;
});
}
}
if (x.second.size()) {
for (auto y : x.second) {
check_tts(y);
auto tt_equ = tts[y];
auto ntt_equ = ~tts[y];
std::vector<node> tfi_equ;
bool keep_trying_equ = true;
foreach_transitive_fanin(y, [&](auto const& n) {
tfi_equ.emplace_back(n);
if (tfi_equ.size() > ps.max_TFI_nodes) {
return false;
}
keep_trying_equ = try_node(tt_equ, ntt_equ, y, n);
return keep_trying;
});
if (keep_trying_equ) /* didn't find a substitution in TFI cone, explore
fanouts. */
{
for (auto j = 0u; j < tfi_equ.size() &&
tfi_equ.size() <= ps.max_TFI_nodes && keep_trying_equ;
++j) {
auto& n = tfi_equ.at(j);
if (ntk.fanout_size(n) > ps.skip_fanout_limit) {
continue;
}
/* if the fanout has all fanins in the set, add it */
ntk.foreach_fanout(n, [&](node const& p) {
if (ntk.visited(p) == ntk.trav_id()) {
return true; /* next fanout */
}
bool all_fanins_visited_equ = true;
ntk.foreach_fanin(p, [&](const auto& g) {
if (ntk.visited(ntk.get_node(g)) != ntk.trav_id()) {
all_fanins_visited_equ = false;
return false; /* terminate fanin-loop */
}
return true; /* next fanin */
});
if (!all_fanins_visited_equ) {
return true; /* next fanout */
}
bool has_root_as_child = false;
ntk.foreach_fanin(p, [&](const auto& g) {
if (ntk.get_node(g) == y) {
has_root_as_child = true;
return false; /* terminate fanin-loop */
}
return true; /* next fanin */
});
if (has_root_as_child) {
return true; /* next fanout */
}
tfi_equ.emplace_back(p);
ntk.set_visited(p, ntk.trav_id());
check_tts(p);
keep_trying_equ = try_node(tt_equ, ntt_equ, y, p);
return keep_trying_equ;
});
}
}
}
}
}
}
bool try_node(kitty::partial_truth_table& tt, kitty::partial_truth_table& ntt,
node const& root, node const& n) {
signal g;
if (tt == tts[n])
g = ntk.make_signal(n);
else if (ntt == tts[n])
g = !ntk.make_signal(n);
else /* not equivalent */
return true; /* try next transitive fanin node */
const auto res = call_with_stopwatch(
st.time_sat, [&]() { return validator.validate(root, g); });
if (!res) /* timeout */
{
++st.num_timeout;
return true; /* try next transitive fanin node */
} else if (!(*res)) /* SAT, cex found */
{
found_cex();
check_tts(root);
tt = tts[root];
ntt = ~tts[root];
return true; /* try next transitive fanin node */
} else /* UNSAT, equivalent node verified */
{
++st.num_reduction;
++st.num_equ_accepts;
/* update network */
ntk.substitute_node(root, g);
return false; /* break `foreach_transitive_fanin` */
}
}
void found_cex() {
++st.num_cex;
sim.add_pattern(validator.cex);
/* re-simulate the whole circuit and refine the equivalent classes */
refine_classes();
}
void refine_classes() {
simulate_nodes<Ntk>(ntk, tts, sim, false);
std::map<int, std::vector<int>> equ_classes_new;
for (auto x : equ_classes) {
std::vector<int> equ_class_new;
for (auto y : x.second) {
if (tts[x.first] == tts[y]) equ_class_new.push_back(y);
}
if (equ_class_new.size()) equ_classes_new[x.first] = equ_class_new;
}
equ_classes = equ_classes_new;
}
void check_tts(node const& n) {
if (tts[n].num_bits() != sim.num_bits()) {
call_with_stopwatch(st.time_sim,
[&]() { simulate_node<Ntk>(ntk, n, tts, sim); });
}
}
template <typename Fn>
void foreach_transitive_fanin(node const& n, Fn&& fn) {
ntk.incr_trav_id();
ntk.set_visited(n, ntk.trav_id());
ntk.foreach_fanin(n, [&](auto const& f) {
return foreach_transitive_fanin_rec(ntk.get_node(f), fn);
});
}
template <typename Fn>
bool foreach_transitive_fanin_rec(node const& n, Fn&& fn) {
ntk.set_visited(n, ntk.trav_id());
if (!fn(n)) {
return false;
}
bool continue_loop = true;
ntk.foreach_fanin(n, [&](auto const& f) {
if (ntk.visited(ntk.get_node(f)) == ntk.trav_id()) {
return true;
} /* skip visited node, continue looping. */
continue_loop = foreach_transitive_fanin_rec(ntk.get_node(f), fn);
return continue_loop; /* break `foreach_fanin` loop immediately when
receiving `false`. */
});
return continue_loop; /* return `false` only if `false` has ever been
received from recursive calls. */
}
private:
Ntk& ntk;
stp_functional_reduction_params const& ps;
stp_functional_reduction_stats& st;
TT tts;
partial_simulator sim;
validator_t validator;
std::vector<int> const0;
std::vector<int> const1;
std::map<int, std::vector<int>> equ_classes;
}; /* stp_functional_reduction_impl */
} /* namespace detail */
/*! \brief Functional reduction.
*
* Removes constant nodes and substitute functionally equivalent nodes.
*/
template <class Ntk>
void stp_functional_reduction(Ntk& ntk,
stp_functional_reduction_params const& ps = {},
stp_functional_reduction_stats* pst = nullptr) {
static_assert(is_network_type_v<Ntk>, "Ntk is not a network type");
static_assert(has_foreach_fanin_v<Ntk>,
"Ntk does not implement the foreach_fanin method");
static_assert(has_foreach_gate_v<Ntk>,
"Ntk does not implement the foreach_gate method");
static_assert(has_foreach_node_v<Ntk>,
"Ntk does not implement the foreach_node method");
static_assert(has_get_constant_v<Ntk>,
"Ntk does not implement the get_constant method");
static_assert(has_get_node_v<Ntk>,
"Ntk does not implement the get_node method");
static_assert(has_is_complemented_v<Ntk>,
"Ntk does not implement the is_complemented method");
static_assert(has_is_pi_v<Ntk>, "Ntk does not implement the is_pi method");
static_assert(has_make_signal_v<Ntk>,
"Ntk does not implement the make_signal method");
static_assert(has_set_visited_v<Ntk>,
"Ntk does not implement the set_visited method");
static_assert(has_size_v<Ntk>, "Ntk does not implement the size method");
static_assert(has_substitute_node_v<Ntk>,
"Ntk does not implement the substitute_node method");
static_assert(has_visited_v<Ntk>,
"Ntk does not implement the visited method");
validator_params vps;
vps.max_clauses = ps.max_clauses;
vps.conflict_limit = ps.conflict_limit;
using fanout_view_t = fanout_view<Ntk>;
fanout_view_t fanout_view{ntk};
stp_functional_reduction_stats st;
detail::stp_functional_reduction_impl p(fanout_view, ps, vps, st);
p.run();
if (ps.verbose) st.report();
if (pst) *pst = st;
}
} // namespace phyLS

File diff suppressed because it is too large Load Diff

View File

@ -1,170 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2024 */
/**
* @file to_npz.hpp
*
* @brief transforms the current network into adjacency matrix(.npz)
*
* @author Homyoung
* @since 2024/03/01
*/
#pragma once
#include <fmt/format.h>
#include <cstdint>
#include <fstream>
#include <iostream>
#include <memory>
#include <mockturtle/networks/aig.hpp>
#include <mockturtle/views/depth_view.hpp>
#include <mockturtle/views/fanout_view.hpp>
#include <sstream>
#include <string>
using namespace std; // 名字空间
namespace phyLS {
template <class Ntk>
void write_npz(Ntk const& ntk, std::ostream& os) {
std::stringstream connect;
cout << "num_pis: " << ntk.num_pis() << endl;
cout << "num_pos: " << ntk.num_pos() << endl;
cout << "num_gates: " << ntk.num_gates() << endl;
int num_pis = ntk.num_pis(), num_pos = ntk.num_pos(),
num_gates = ntk.num_gates();
int size = num_pis + num_pos + num_gates;
vector<vector<double>> adj(size, vector<double>(size, 0));
ntk.foreach_node([&](auto const& n) {
if (ntk.is_constant(n) || ntk.is_ci(n)) return true;
ntk.foreach_fanin(n, [&](auto const& f) {
if (ntk.node_to_index(ntk.get_node(f)) <= num_pis) {
adj[ntk.node_to_index(n) - num_pis - 1]
[ntk.node_to_index(ntk.get_node(f)) + num_gates - 1] = 1;
adj[ntk.node_to_index(ntk.get_node(f)) + num_gates - 1]
[ntk.node_to_index(n) - num_pis - 1] = 1;
} else {
adj[ntk.node_to_index(n) - num_pis - 1]
[ntk.node_to_index(ntk.get_node(f)) - num_pis - 1] = 0.5;
adj[ntk.node_to_index(ntk.get_node(f)) - num_pis - 1]
[ntk.node_to_index(n) - num_pis - 1] = 0.5;
}
return true;
});
return true;
});
ntk.foreach_po([&](auto const& f, auto i) {
if (ntk.node_to_index(ntk.get_node(f)) <= num_pis) {
adj[i + num_pis + num_gates]
[ntk.node_to_index(ntk.get_node(f)) + num_gates - 1] = 1;
adj[ntk.node_to_index(ntk.get_node(f)) + num_gates - 1]
[i + num_pis + num_gates] = 1;
} else {
adj[i + num_pis + num_gates]
[ntk.node_to_index(ntk.get_node(f)) - num_pis - 1] = 0.5;
adj[ntk.node_to_index(ntk.get_node(f)) - num_pis - 1]
[i + num_pis + num_gates] = 0.5;
}
});
for (auto x : adj) {
for (int i = 0; i < x.size(); i++) {
if (i == x.size() - 1) {
connect << fmt::format("{}", x[i]);
} else {
connect << fmt::format("{}", x[i]) << ",";
}
}
connect << "\n";
}
os << connect.str();
}
template <class Ntk>
void write_def(Ntk const& ntk, std::ostream& os_def, std::ostream& os_mdef) {
std::stringstream components, pins, pins_def;
cout << "num_pis: " << ntk.num_pis() << endl;
cout << "num_pos: " << ntk.num_pos() << endl;
cout << "num_gates: " << ntk.num_gates() << endl;
int num_pis = ntk.num_pis(), num_pos = ntk.num_pos(),
num_gates = ntk.num_gates();
int size = num_pis + num_pos + num_gates;
int output_position = 0, input_position = 0, max_position = 10 * size;
components << fmt::format("COMPONENTS {} ;\n", num_gates);
ntk.foreach_node([&](auto const& n) {
if (ntk.is_constant(n) || ntk.is_ci(n)) return true;
components << fmt::format(" - and_{}_ and\n", ntk.node_to_index(n))
<< " + UNPLACED ;\n";
return true;
});
components << "END COMPONENTS\n"
<< "\n";
pins << fmt::format("PINS {} ;\n", num_pis + num_pos + 1);
pins_def << fmt::format("PINS {} ;\n", num_pis + num_pos + 1);
ntk.foreach_po([&](auto const& f, auto i) {
pins << fmt::format(" - output_{} + NET output_{}\n", i, i)
<< " + DIRECTION OUTPUT\n"
<< fmt::format(" + PLACED ( {} {} ) N\n", output_position * 10,
max_position)
<< " + LAYER metal3 ( 0 0 ) ( 510 100 ) ;\n";
pins_def << fmt::format(" - output_{} + NET output_{}\n", i, i)
<< " + DIRECTION OUTPUT\n"
<< fmt::format(" + PLACED ( {} {} ) N\n",
output_position * 10, max_position)
<< " + LAYER metal3 ( 0 0 ) ( 510 100 ) ;\n";
output_position++;
});
ntk.foreach_pi([&](auto const& f, auto i) {
pins << fmt::format(" - input_{} + NET input_{}\n", i, i)
<< " + DIRECTION INPUT\n"
<< fmt::format(" + PLACED ( {} {} ) N\n", input_position * 10, 0)
<< " + LAYER metal3 ( 0 0 ) ( 510 100 ) ;\n";
pins_def << fmt::format(" - input_{} + NET input_{}\n", i, i)
<< " + DIRECTION INPUT\n"
<< fmt::format(" + PLACED ( {} {} ) N\n", input_position * 10,
0)
<< " + LAYER metal3 ( 0 0 ) ( 510 100 ) ;\n";
input_position++;
});
pins << "END PINS\n";
pins_def << " - input_clk + NET input_clk\n"
<< " + DIRECTION INPUT\n"
<< fmt::format(" + PLACED ( {} {} ) N\n", input_position * 10,
0)
<< " + LAYER metal3 ( 0 0 ) ( 510 100 ) ;\n";
pins_def << "END PINS\n";
os_mdef << components.str() << pins.str();
os_def << components.str() << pins_def.str();
}
template <class Ntk>
void write_npz(Ntk const& ntk, std::string const& filename) {
std::ofstream os(filename.c_str(), std::ofstream::out);
write_npz(ntk, os);
os.close();
}
template <class Ntk>
void write_def(Ntk const& ntk, std::string const& filename_def,
std::string const& filename_mdef) {
std::ofstream os_def(filename_def.c_str(), std::ofstream::out);
std::ofstream os_mdef(filename_mdef.c_str(), std::ofstream::out);
write_def(ntk, os_def, os_mdef);
os_def.close();
os_mdef.close();
}
} // namespace phyLS

View File

@ -1,54 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file utils.hpp
*
* @brief TODO
*
* @author Homyoung
* @since 2023/11/16
*/
#ifndef UTILS_HPP
#define UTILS_HPP
#include <mockturtle/networks/xag.hpp>
#include <mockturtle/networks/xmg.hpp>
using namespace mockturtle;
namespace phyLS {
std::array<xmg_network::signal, 3> get_children(xmg_network const& xmg,
xmg_network::node const& n) {
std::array<xmg_network::signal, 3> children;
xmg.foreach_fanin(n, [&children](auto const& f, auto i) { children[i] = f; });
std::sort(
children.begin(), children.end(),
[&](auto const& c1, auto const& c2) { return c1.index < c2.index; });
return children;
}
std::array<xag_network::signal, 2> get_xag_children(
xag_network const& xag, xag_network::node const& n) {
std::array<xag_network::signal, 2> children;
xag.foreach_fanin(n, [&children](auto const& f, auto i) { children[i] = f; });
std::sort(
children.begin(), children.end(),
[&](auto const& c1, auto const& c2) { return c1.index < c2.index; });
return children;
}
void print_children(std::array<xmg_network::signal, 3> const& children) {
auto i = 0u;
for (auto child : children) {
std::cout << "children " << i << " is " << child.index << " complemented ? "
<< child.complement << std::endl;
i++;
}
}
} // namespace phyLS
#endif

View File

@ -1,678 +0,0 @@
#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!(!!) (!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 */

View File

@ -1,170 +0,0 @@
#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 */

View File

@ -1,66 +0,0 @@
#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

View File

@ -1,925 +0,0 @@
#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 */

View File

@ -1,344 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file xmginv.hpp
*
* @brief Inversion optimization of xmg
*
* @author Homyoung
* @since 2023/11/16
*/
#ifndef XMG_INV_HPP
#define XMG_INV_HPP
#include <mockturtle/algorithms/cleanup.hpp>
#include <mockturtle/networks/xmg.hpp>
#include <mockturtle/properties/migcost.hpp>
#include "utils.hpp"
using namespace mockturtle;
namespace phyLS {
/* use substitue method for inveters propagation */
xmg_network complement_node(xmg_network& xmg, xmg_network::node const& n) {
xmg_network::signal opt;
auto children = get_children(xmg, n);
if (xmg.is_maj(n)) {
children[0] = !children[0];
children[1] = !children[1];
children[2] = !children[2];
opt = xmg.create_maj_without_complement_opt(children[0], children[1],
children[2]) ^
true;
} else {
if (xmg.is_complemented(children[2])) {
children[2] = !children[2];
} else {
children[1] = !children[1];
}
opt =
xmg.create_xor_without_complement_opt(children[1], children[2]) ^ true;
}
xmg.substitute_node_without_complement_opt(n, opt);
return xmg;
}
/* print information */
void print_node(xmg_network const& xmg, xmg_network::node const& n) {
std::cout << " node " << n << " inverters infro: ";
xmg.foreach_fanin(n, [&](auto s) {
std::cout << " { " << s.index << " , " << s.complement << " } ";
});
std::cout << std::endl;
}
void print_network(xmg_network const& xmg) {
xmg.foreach_gate([&](auto n) { print_node(xmg, n); });
}
/******************************************************************************
* Types *
******************************************************************************/
class inv_manager {
public:
inv_manager(xmg_network xmg);
void compute_parents();
std::vector<xmg_network::node> get_parents(xmg_network::node const& n);
int num_invs_fanins(xmg_network::node const& n);
int num_invs_fanouts(xmg_network::node const& n);
int num_in_edges(xmg_network::node const& n);
int num_out_edges(xmg_network::node const& n);
int num_edges(xmg_network::node const& n);
int num_invs(xmg_network::node const& n);
int one_level_savings(xmg_network::node const& n);
int one_level_savings_nni(xmg_network::node const& n);
int two_level_savings(xmg_network::node const& n);
void xor_jump();
void one_level_optimization(const int& thres1, const int& thres2);
void two_level_optimization(const int& thres1, const int& thres2);
xmg_network run();
private:
xmg_network xmg;
std::map<xmg_network::node, std::vector<xmg_network::node>> pmap;
unsigned num_inv_origin{0u}, num_inv_opt{0u};
};
inv_manager::inv_manager(xmg_network xmg) : xmg(xmg) { compute_parents(); }
/* compute the node parents information and save it */
void inv_manager::compute_parents() {
xmg.foreach_gate([&](auto n) {
xmg.foreach_fanin(n, [&](auto c) {
auto it = pmap.find(xmg.get_node(c));
if (it == pmap.end()) {
std::vector<xmg_network::node> fout;
fout.push_back(n);
pmap[xmg.get_node(c)] = fout;
} else {
auto& f = it->second;
if (std::find(f.begin(), f.end(), n) == f.end()) {
f.push_back(n);
}
}
});
});
}
std::vector<xmg_network::node> inv_manager::get_parents(
xmg_network::node const& n) {
return pmap[n];
}
int inv_manager::num_invs_fanins(xmg_network::node const& n) {
int cost = 0;
xmg.foreach_fanin(n, [&](auto s) {
if (xmg.is_complemented(s)) {
cost++;
}
});
return cost;
}
int inv_manager::num_invs_fanouts(xmg_network::node const& n) {
int cost = 0u;
/* ordinary fanouts */
auto parents = get_parents(n);
for (const auto pn : parents) {
xmg.foreach_fanin(pn, [&](auto s) {
if (xmg.get_node(s) == n && xmg.is_complemented(s)) {
cost++;
}
});
}
/* POs */
xmg.foreach_po([&](auto const& f) {
if (xmg.get_node(f) == n && xmg.is_complemented(f)) {
cost++;
}
});
return cost;
}
int inv_manager::num_in_edges(xmg_network::node const& n) {
auto num_in = (xmg.is_maj(n) ? 3 : 2);
return num_in;
}
int inv_manager::num_out_edges(xmg_network::node const& n) {
/* pos */
int num_po = 0;
xmg.foreach_po([&](auto const& f) {
if (xmg.get_node(f) == n) {
num_po++;
}
});
return get_parents(n).size() + num_po;
}
int inv_manager::num_edges(xmg_network::node const& n) {
assert(xmg.is_maj(n) || xmg.is_xor3(n));
return num_in_edges(n) + num_out_edges(n);
}
int inv_manager::num_invs(xmg_network::node const& n) {
return num_invs_fanins(n) + num_invs_fanouts(n);
}
int inv_manager::one_level_savings(xmg_network::node const& n) {
int before, after;
before = num_invs(n);
if (xmg.is_maj(n)) {
after = num_edges(n) - before;
} else {
int in, out;
out = num_out_edges(n) - num_invs_fanouts(n);
auto tmp = num_invs_fanins(n);
if (tmp == 1 || tmp == 3) {
in = 0;
} else if (tmp == 2 || tmp == 0) {
in = 1;
} else {
assert(false);
}
after = in + out;
}
return before - after;
}
int inv_manager::one_level_savings_nni(xmg_network::node const& n) {
int before, after, after_nni;
before = num_invs(n);
if (xmg.is_maj(n)) {
after = num_edges(n) - before;
if (num_invs_fanins(n) == 2) {
}
} else {
int in, out;
out = num_out_edges(n) - num_invs_fanouts(n);
auto tmp = num_invs_fanins(n);
if (tmp == 1 || tmp == 3) {
in = 0;
} else if (tmp == 2 || tmp == 0) {
in = 1;
} else {
assert(false);
}
after = in + out;
}
return before - after;
}
int inv_manager::two_level_savings(xmg_network::node const& n) {
assert(!xmg.is_pi(n));
auto parents = get_parents(n);
int total_savings = 0;
/* no parents */
if (parents.size() == 0) {
return one_level_savings(n);
} else {
auto child_savings = one_level_savings(n);
for (const auto& p : parents) {
total_savings += one_level_savings(p);
xmg.foreach_fanin(p, [&](auto s) {
if (xmg.get_node(s) == n && xmg.is_complemented(s)) {
if (xmg.is_complemented(s)) {
total_savings -= 2;
} else {
total_savings += 2;
}
}
});
}
total_savings += child_savings;
}
return total_savings;
}
void inv_manager::one_level_optimization(const int& thres1, const int& thres2) {
xmg.foreach_gate([&](auto n) {
if (one_level_savings(n) >= thres1) {
xmg.complement_node(n, pmap[n]);
} else if (two_level_savings(n) >= thres2) {
auto parents = pmap[n];
xmg.complement_node(n, pmap[n]);
for (const auto& p : parents) {
xmg.complement_node(p, pmap[p]);
}
}
});
}
void inv_manager::two_level_optimization(const int& thres1, const int& thres2) {
xmg.foreach_gate([&](auto n) {
auto parents = pmap[n];
auto savings = two_level_savings(n);
if (savings >= thres1) {
xmg.complement_node(n, pmap[n]);
for (const auto& p : parents) {
xmg.complement_node(p, pmap[p]);
}
} else if (one_level_savings(n) >= thres2) {
xmg.complement_node(n, pmap[n]);
}
});
}
void inv_manager::xor_jump() {
xmg.foreach_gate([&](const auto& n) {
if (xmg.is_xor3(n)) {
xmg.xor_inv_jump(n);
}
});
}
xmg_network inv_manager::run() {
num_inv_origin = num_inverters(xmg);
one_level_optimization(0, 1);
two_level_optimization(1, 0);
one_level_optimization(0, 1);
two_level_optimization(1, 1);
num_inv_opt = num_inverters(xmg);
xor_jump();
std::cout << "[xmginv] "
<< " num_inv_origin: " << num_inv_origin
<< " num_opt_inv: " << num_inv_opt << std::endl;
auto xmg_opt = mockturtle::cleanup_dangling(xmg);
return xmg_opt;
}
/* public function */
xmg_network xmg_inv_optimization(xmg_network& xmg) {
inv_manager mgr(xmg);
return mgr.run();
}
} // namespace phyLS
#endif

File diff suppressed because one or more lines are too long

View File

@ -1,644 +0,0 @@
#pragma once
/*!
\file aoig.hpp
\brief aoig logic network implementation
*/
#include <mockturtle/mockturtle.hpp>
#include <kitty/kitty.hpp>
namespace mockturtle
{
struct aoig_storage_data
{
truth_table_cache<kitty::dynamic_truth_table> cache;
uint32_t num_pis = 0u;
uint32_t num_pos = 0u;
std::vector<int8_t> latches;
uint32_t trav_id = 0u;
};
/*! \brief k-LUT node
*
* `data[0].h1`: Fan-out size
* `data[0].h2`: Application-specific value
* `data[1].h1`: Function literal in truth table cache
* `data[2].h2`: Visited flags
*/
struct aoig_storage_node : mixed_fanin_node<2>
{
bool operator==(aoig_storage_node const& other) const
{
return data[1].h1 == other.data[1].h1 && children == other.children;
}
};
/*! \brief k-LUT storage container */
using aoig_storage = storage<aoig_storage_node, aoig_storage_data>;
class aoig_network
{
public:
#pragma region Types and constructors
static constexpr auto min_fanin_size = 1;
static constexpr auto max_fanin_size = 3;
using base_type = aoig_network;
using storage = std::shared_ptr<aoig_storage>;
using node = uint64_t;
using signal = uint64_t;
aoig_network()
: _storage(std::make_shared<aoig_storage>()),
_events(std::make_shared<decltype(_events)::element_type>())
{
_init();
}
aoig_network(std::shared_ptr<aoig_storage> storage)
: _storage(storage),
_events(std::make_shared<decltype(_events)::element_type>())
{
_init();
}
private:
inline void _init()
{
/* reserve the second node for constant 1 */
_storage->nodes.emplace_back();
/* reserve some truth tables for nodes */
kitty::dynamic_truth_table tt_zero(0);
_storage->data.cache.insert(tt_zero);
static uint64_t _not = 0x1;
kitty::dynamic_truth_table tt_not(1);
kitty::create_from_words(tt_not, &_not, &_not + 1);
_storage->data.cache.insert(tt_not);
static uint64_t _and = 0x8;
kitty::dynamic_truth_table tt_and(2);
kitty::create_from_words(tt_and, &_and, &_and + 1);
_storage->data.cache.insert(tt_and);
static uint64_t _or = 0xe;
kitty::dynamic_truth_table tt_or(2);
kitty::create_from_words(tt_or, &_or, &_or + 1);
_storage->data.cache.insert(tt_or);
static uint64_t _xor = 0x6;
kitty::dynamic_truth_table tt_xor(2);
kitty::create_from_words(tt_xor, &_xor, &_xor + 1);
_storage->data.cache.insert(tt_xor);
static uint64_t _mux= 0xd8;
kitty::dynamic_truth_table tt_mux(3);
kitty::create_from_words(tt_mux, &_mux, &_mux + 1);
_storage->data.cache.insert(tt_mux);
/* truth tables for constants */
_storage->nodes[0].data[1].h1 = 0;
_storage->nodes[1].data[1].h1 = 1;
}
#pragma endregion
#pragma region Primary I / O and constants
public:
signal get_constant(bool value = false) const
{
return value ? 1 : 0;
}
signal create_pi(std::string const& name = std::string())
{
(void)name;
const auto index = _storage->nodes.size();
_storage->nodes.emplace_back();
_storage->inputs.emplace_back(index);
_storage->nodes[index].data[1].h1 = 2;
++_storage->data.num_pis;
return index;
}
uint32_t create_po(signal const& f, std::string const& name = std::string())
{
(void)name;
/* increase ref-count to children */
_storage->nodes[f].data[0].h1++;
auto const po_index = _storage->outputs.size();
_storage->outputs.emplace_back(f);
++_storage->data.num_pos;
return po_index;
}
uint32_t create_ri(signal const& f, int8_t reset = 0, std::string const& name = std::string())
{
(void)name;
/* increase ref-count to children */
_storage->nodes[f].data[0].h1++;
auto const ri_index = _storage->outputs.size();
_storage->outputs.emplace_back(f);
_storage->data.latches.emplace_back(reset);
return ri_index;
}
int8_t latch_reset(uint32_t index) const
{
assert(index < _storage->data.latches.size());
return _storage->data.latches[index];
}
bool is_combinational() const
{
return (static_cast<uint32_t>(_storage->inputs.size()) == _storage->data.num_pis &&
static_cast<uint32_t>(_storage->outputs.size()) == _storage->data.num_pos);
}
bool is_constant(node const& n) const
{
return n <= 1;
}
bool is_ci(node const& n) const
{
bool found = false;
detail::foreach_element(_storage->inputs.begin(), _storage->inputs.end(), [&found, &n](auto const& node) {
if (node == n)
{
found = true;
return false;
}
return true;
});
return found;
}
bool is_pi(node const& n) const
{
bool found = false;
detail::foreach_element(_storage->inputs.begin(), _storage->inputs.begin() + _storage->data.num_pis, [&found, &n](auto const& node) {
if (node == n)
{
found = true;
return false;
}
return true;
});
return found;
}
bool constant_value(node const& n) const
{
return n == 1;
}
#pragma endregion
#pragma region Create unary functions
signal create_buf(signal const& a)
{
return a;
}
signal create_not(signal const& a)
{
return _create_node({ a }, 3);
}
#pragma endregion
#pragma region Create binary/ternary functions
signal create_and(signal a, signal b)
{
return _create_node({ a, b }, 4);
}
signal create_or(signal a, signal b)
{
return _create_node({ a, b }, 6);
}
signal create_xor(signal a, signal b)
{
return _create_node({ a, b }, 8);
}
signal create_mux(signal a, signal b, signal c)
{
return _create_node({ a, b, c }, 10);
}
#pragma endregion
#pragma region Create arbitrary functions
signal _create_node(std::vector<signal> const& children, uint32_t literal)
{
storage::element_type::node_type node;
std::copy(children.begin(), children.end(), std::back_inserter(node.children));
node.data[1].h1 = literal;
const auto it = _storage->hash.find(node);
if (it != _storage->hash.end())
{
return it->second;
}
const auto index = _storage->nodes.size();
_storage->nodes.push_back(node);
_storage->hash[node] = index;
/* increase ref-count to children */
for (auto c : children)
{
_storage->nodes[c].data[0].h1++;
}
set_value(index, 0);
for (auto const& fn : _events->on_add)
{
(*fn)(index);
}
return index;
}
signal create_node(std::vector<signal> const& children, kitty::dynamic_truth_table const& function)
{
if (children.size() == 0u)
{
assert(function.num_vars() == 0u);
return get_constant(!kitty::is_const0(function));
}
return _create_node(children, _storage->data.cache.insert(function));
}
signal clone_node(aoig_network const& other, node const& source, std::vector<signal> const& children)
{
assert(!children.empty());
const auto tt = other._storage->data.cache[other._storage->nodes[source].data[1].h1];
return create_node(children, tt);
}
#pragma endregion
#pragma region Restructuring
void substitute_node(node const& old_node, signal const& new_signal)
{
/* find all parents from old_node */
for (auto i = 0u; i < _storage->nodes.size(); ++i)
{
auto& n = _storage->nodes[i];
for (auto& child : n.children)
{
if (child == old_node)
{
std::vector<signal> old_children(n.children.size());
std::transform(n.children.begin(), n.children.end(), old_children.begin(), [](auto c) { return c.index; });
child = new_signal;
// increment fan-out of new node
_storage->nodes[new_signal].data[0].h1++;
for (auto const& fn : _events->on_modified)
{
(*fn)(i, old_children);
}
}
}
}
/* check outputs */
for (auto& output : _storage->outputs)
{
if (output == old_node)
{
output = new_signal;
// increment fan-out of new node
_storage->nodes[new_signal].data[0].h1++;
}
}
// reset fan-out of old node
_storage->nodes[old_node].data[0].h1 = 0;
}
#pragma endregion
#pragma region Structural properties
auto size() const
{
return static_cast<uint32_t>(_storage->nodes.size());
}
auto num_cis() const
{
return static_cast<uint32_t>(_storage->inputs.size());
}
auto num_cos() const
{
return static_cast<uint32_t>(_storage->outputs.size());
}
auto num_pis() const
{
return _storage->data.num_pis;
}
auto num_pos() const
{
return _storage->data.num_pos;
}
auto num_gates() const
{
return static_cast<uint32_t>(_storage->nodes.size() - _storage->inputs.size() - 2);
}
uint32_t fanin_size(node const& n) const
{
return static_cast<uint32_t>(_storage->nodes[n].children.size());
}
uint32_t fanout_size(node const& n) const
{
return _storage->nodes[n].data[0].h1;
}
bool is_function(node const& n) const
{
return n > 1 && !is_ci(n);
}
#pragma endregion
#pragma region Functional properties
kitty::dynamic_truth_table node_function(const node& n) const
{
return _storage->data.cache[_storage->nodes[n].data[1].h1];
}
#pragma endregion
#pragma region Nodes and signals
node get_node(signal const& f) const
{
return f;
}
bool is_complemented( signal const& f ) const
{
(void)f;
return false;
}
signal make_signal(node const& n) const
{
return n;
}
uint32_t node_to_index(node const& n) const
{
return static_cast<uint32_t>(n);
}
node index_to_node(uint32_t index) const
{
return index;
}
node ci_at(uint32_t index) const
{
assert(index < _storage->inputs.size());
return *(_storage->inputs.begin() + index);
}
signal co_at(uint32_t index) const
{
assert(index < _storage->outputs.size());
return (_storage->outputs.begin() + index)->index;
}
node pi_at(uint32_t index) const
{
assert(index < _storage->data.num_pis);
return *(_storage->inputs.begin() + index);
}
signal po_at(uint32_t index) const
{
assert(index < _storage->data.num_pos);
return (_storage->outputs.begin() + index)->index;
}
uint32_t ci_index(node const& n) const
{
assert(_storage->nodes[n].children[0].data == _storage->nodes[n].children[1].data);
return (_storage->nodes[n].children[0].data);
}
uint32_t co_index(signal const& s) const
{
uint32_t i = -1;
foreach_co([&](const auto& x, auto index) {
if (x == s)
{
i = index;
return false;
}
return true;
});
return i;
}
uint32_t pi_index(node const& n) const
{
assert(_storage->nodes[n].children[0].data == _storage->nodes[n].children[1].data);
return (_storage->nodes[n].children[0].data);
}
uint32_t po_index(signal const& s) const
{
uint32_t i = -1;
foreach_po([&](const auto& x, auto index) {
if (x == s)
{
i = index;
return false;
}
return true;
});
return i;
}
#pragma endregion
#pragma region Node and signal iterators
template<typename Fn>
void foreach_node(Fn&& fn) const
{
detail::foreach_element(ez::make_direct_iterator<uint64_t>(0),
ez::make_direct_iterator<uint64_t>(_storage->nodes.size()),
fn);
}
template<typename Fn>
void foreach_ci(Fn&& fn) const
{
detail::foreach_element(_storage->inputs.begin(), _storage->inputs.end(), fn);
}
template<typename Fn>
void foreach_co(Fn&& fn) const
{
using IteratorType = decltype(_storage->outputs.begin());
detail::foreach_element_transform<IteratorType, uint32_t>(_storage->outputs.begin(), _storage->outputs.end(), [](auto o) { return o.index; }, fn);
}
template<typename Fn>
void foreach_pi(Fn&& fn) const
{
detail::foreach_element(_storage->inputs.begin(), _storage->inputs.begin() + _storage->data.num_pis, fn);
}
template<typename Fn>
void foreach_po(Fn&& fn) const
{
using IteratorType = decltype(_storage->outputs.begin());
detail::foreach_element_transform<IteratorType, uint32_t>(_storage->outputs.begin(), _storage->outputs.begin() + _storage->data.num_pos, [](auto o) { return o.index; }, fn);
}
template<typename Fn>
void foreach_gate(Fn&& fn) const
{
detail::foreach_element_if(ez::make_direct_iterator<uint64_t>(2), /* start from 2 to avoid constants */
ez::make_direct_iterator<uint64_t>(_storage->nodes.size()),
[this](auto n) { return !is_ci(n); },
fn);
}
template<typename Fn>
void foreach_fanin(node const& n, Fn&& fn) const
{
if (n == 0 || is_ci(n))
return;
using IteratorType = decltype(_storage->outputs.begin());
detail::foreach_element_transform<IteratorType, uint32_t>(_storage->nodes[n].children.begin(), _storage->nodes[n].children.end(), [](auto f) { return f.index; }, fn);
}
#pragma endregion
#pragma region Simulate values
template<typename Iterator>
iterates_over_t<Iterator, bool>
compute(node const& n, Iterator begin, Iterator end) const
{
uint32_t index{ 0 };
while (begin != end)
{
index <<= 1;
index ^= *begin++ ? 1 : 0;
}
return kitty::get_bit(_storage->data.cache[_storage->nodes[n].data[1].h1], index);
}
template<typename Iterator>
iterates_over_truth_table_t<Iterator>
compute(node const& n, Iterator begin, Iterator end) const
{
const auto nfanin = _storage->nodes[n].children.size();
std::vector<typename Iterator::value_type> tts(begin, end);
assert(nfanin != 0);
assert(tts.size() == nfanin);
/* resulting truth table has the same size as any of the children */
auto result = tts.front().construct();
const auto gate_tt = _storage->data.cache[_storage->nodes[n].data[1].h1];
for (auto i = 0u; i < result.num_bits(); ++i)
{
uint32_t pattern = 0u;
for (auto j = 0u; j < nfanin; ++j)
{
pattern |= kitty::get_bit(tts[j], i) << j;
}
if (kitty::get_bit(gate_tt, pattern))
{
kitty::set_bit(result, i);
}
}
return result;
}
#pragma endregion
#pragma region Custom node values
void clear_values() const
{
std::for_each(_storage->nodes.begin(), _storage->nodes.end(), [](auto& n) { n.data[0].h2 = 0; });
}
uint32_t value(node const& n) const
{
return _storage->nodes[n].data[0].h2;
}
void set_value(node const& n, uint32_t v) const
{
_storage->nodes[n].data[0].h2 = v;
}
uint32_t incr_value(node const& n) const
{
return static_cast<uint32_t>(_storage->nodes[n].data[0].h2++);
}
uint32_t decr_value(node const& n) const
{
return static_cast<uint32_t>(--_storage->nodes[n].data[0].h2);
}
#pragma endregion
#pragma region Visited flags
void clear_visited() const
{
std::for_each(_storage->nodes.begin(), _storage->nodes.end(), [](auto& n) { n.data[1].h2 = 0; });
}
auto visited(node const& n) const
{
return _storage->nodes[n].data[1].h2;
}
void set_visited(node const& n, uint32_t v) const
{
_storage->nodes[n].data[1].h2 = v;
}
uint32_t trav_id() const
{
return _storage->data.trav_id;
}
void incr_trav_id() const
{
++_storage->data.trav_id;
}
#pragma endregion
#pragma region General methods
auto& events() const
{
return *_events;
}
#pragma endregion
public:
std::shared_ptr<aoig_storage> _storage;
std::shared_ptr<network_events<base_type>> _events;
};
} // namespace mockturtle

File diff suppressed because one or more lines are too long

View File

@ -1,220 +0,0 @@
0x3cc3 ![d[bc]]
0x1ee1 ![{ab}[cd]]
0x1be4 [c[d(!a[bc])]]
0x19e6 [[ad](b!(ac))]
0x19e1 ![[a(c!d)](b!(a!(!cd)))]
0x18e7 ![d([ac][bc])]
0x1798 [d{(ab)(c![d[ab]])}]
0x1796 [a{[bc](d![ab])}]
0x177e [(ab){[cd][d[ab]]}]
0x16e9 ![d(!(ab)[c{ab}])]
0x169b ![[b[ad]]([c(a[b[ad]])][d(a[b[ad]])])]
0x1699 ![b[a(d!(c!(ab)))]]
0x1696 [a[b(c!(b(ad)))]]
0x017e [d{[a(b!(ad))][c(b!(ad))]}]
0x168e (!(c[d[ac]])[b([ac]!(b!d))])
0x0666 ([ab]!(cd))
0x1687 ![c([a(d!(a!c))][b(d!(a!c))])]
0x016f !{(c![ab])(d{ab})}
0x166e [(cd)[a(b!(a![cd]))]]
0x1683 ![{bc}(![a(bc)][d(bc)])]
0x1681 ![([ad][bd]){c[[ad]{b([ad][bd])}]}]
0x17e8 [d({ab}!(!c[ab]))]
0x166a [[a(!d[bc])]{[bc](c!(!ad))}]
0x168b ![[c(b![ac])](d![b{a(b![ac])}])]
0x1669 ![[b[ac]](d!(c(ab)))]
0x16ac {([bc][ad])([bd][a[bc]])}
0x07f8 [d{c(ab)}]
0x07b5 !{(cd)([ac]!(!b[cd]))}
0x07b4 [c{(!ab)(d!(b!c))}]
0x001f !{d(c{ab})}
0x03c7 !{(bd)({ac}[bc])}
0x0ff0 [cd]
0x03d7 !({ad}[b(c!(bd))])
0x07b1 !{(b![ad])[d(!c{ad})]}
0x077e (!(cd){[a[cd]][b[cd]]})
0x0778 [d[c(b(a!(cd)))]]
0x06f0 ([cd]!(d![ab]))
0x06f9 ![d(!c[ab])]
0x07b0 ([cd]!(b[ac]))
0x06f6 [d{c[b[ad]]}]
0x06b6 ([c[a{b(ac)}]]!(d![a{b(ac)}]))
0x06b4 (!(cd)[[bc](a{bd})])
0x019a [a{(ad)(!b[cd])}]
0x06b0 ([cd]{(ac)[a[bc]]})
0x07e3 ![(b!(!ad))(c!(a![bd]))]
0x0697 !(!(!c[b(a!c)]){d[a[b(a!c)]]})
0x06b5 !({d[ac]}!([cd][b[ac]]))
0x0696 (!(cd)[b[ac]])
0x178e [c{[a[cd]][b[cd]]}]
0x0691 !{[b[ad]](![cd]{c[ad]})}
0x169a (!(c(bd))[(!bc)[a(bd)]])
0x077a (!(cd)[{cd}(a!(!b{cd}))])
0x0679 ![d([b[ac]]!(c!(b!d)))]
0x0678 [[c(ab)](d{[ab][c(ab)]})]
0x0672 (!(cd)[{ac}(b{ad})])
0x066b !({b{cd}}!(!(cd)[a(b{cd})]))
0x0662 ([ab]![c(!d{bc})])
0x6996 [d[c[ab]]]
0x0661 !{({ac}![cd])[a[b[cd]]]}
0x07e0 ([cd]!([ac][bc]))
0x0690 ([cd][b[ac]])
0x0660 ([ab][cd])
0x011e [{cd}{b{a(cd)}}]
0x03dd ![{bc}(!d{b[ac]})]
0x1668 [[ac](![bd]{[ab][ac]})]
0x0007 !{d{c(ab)}}
0x06b1 ![(!c[b[ac]]){d(b[ac])}]
0x03dc [d{b(c!(a!d))}]
0x0667 !(!(!c[b{ac}]){d[a[b{ac}]]})
0x01eb !{(d{ab})(!a[bc])}
0x03d5 !({ad}!(![bc][cd]))
0x066f ![(!c[b[ac]]){d[b[ac]]}]
0x03d8 ([d[c(a[bc])]]!([bc]![c(a[bc])]))
0x06b3 !{(cd)[(!ad)(b!(ac))]}
0x03d6 [{bc}{d(a!(bc))}]
0x0180 ([bd]([ad][cd]))
0x03fc [d{bc}]
0x03d4 [{bc}{d(a[bc])}]
0x016a (!(d{bc})[(bc)[ad]])
0x07e9 ![{c(ab)}(!d{ab})]
0x06b9 ![d([ab]!(c!(b!d)))]
0x03c6 [(!c{ad})(b!(d!(!c{ad})))]
0x0669 !{(cd)[b[a{cd}]]}
0x03c1 !{[bc]({ad}![cd])}
0x036f ![{bc}(!d[b(ac)])]
0x036e {(!c[bd])(!d[a[bd]])}
0x07f2 [d{c(a![bd])}]
0x03db !({bc}!(!d[c(a!(bc))]))
0x036d ![{(b!c)(a!d)}[c(b!d)]]
0x0189 ![{b(!ac)}(a!(d{b(!ac)}))]
0x0369 !{[c[b(a!d)]](d[b(a!d)])}
0x035e [c{(a!d)[d(b!c)]}]
0x035b !({bc}!(!d[ac]))
0x033f !{(bc)(d[bc])}
0x01fe [d{c{ab}}]
0x01ee [d{b{a(cd)}}]
0x003d !{d[b(!c{ab})]}
0x06bd ![d([ab]![c(b!d)])]
0x035f !{(ac)(d{bc})}
0x1bd8 [a[c(![bc][ad])]]
0x0116 (!(c{ab})(!(ab)[c[d{ab}]]))
0x03d9 ![b{(a!d)(c[bd])}]
0x06f2 ([(a!c){bc}]{(a!c)[cd]})
0x0358 [c({ad}{c[bd]})]
0x033d !{(bc)[d(!b(!c{ad}))]}
0x006f !{d(c![ab])}
0x019e (!(c![b[ac]])[d{a[b[ac]]}])
0x01e8 ([d{ab}]!(!(ab)[c{ab}]))
0x07f0 [d{c(b(ad))}]
0x01af !{(!ac)(d{ab})}
0x0197 ![{d[ab]}(!c[d{ab}])]
0x01bf !{(c(!a[bd]))(d!(!a[bd]))}
0x03c5 ![{c(a!d)}(b[cd])]
0x01bd ![{bc}({a[bc]}!(d{bc}))]
0x011f !({cd}{b{a(cd)}})
0x06b7 ![d([b(ad)][c{ad}])]
0x013f !{(bc)(d{a[bc]})}
0x01bc ([d{a[bc]}]!(![bc][c{a[bc]}]))
0x036a [{bc}{d[a[bc]]}]
0x036c [[b(ac)](d!(c![b(ac)]))]
0x167e (!(d![c[ab]]){[ab][b[c[ab]]]})
0x06b2 (!(!a[bd])[d{c[a[bd]]}])
0x01ad ![a{(!ac)({bc}[ad])}]
0x035a [{ad}{c(bd)}]
0x01ab ![{bc}(a[d{bc}])]
0x018b !{(ad)[c(b![ac])]}
0x01ac ([a(!c[b{ad}])]!(d!(!c[b{ad}])))
0x01be (!(bd)[d{a[bc]}])
0x16ad ![(bd)[[cd](a!(b![cd]))]]
0x0186 (![c(ab)][d{ab}])
0x01aa ([ad]!(d{bc}))
0x1686 ([b[ac]]!(c![ad]))
0x01a9 ![a({bc}!(ad))]
0x07b6 [{c(a![bd])}{d(!a[bd])}]
0x01a8 (![a{bc}][d{bc}])
0x007e (!d{[ab][ac]})
0x019f !{(d!(!a[cd]))[(!a[cd])(!b[cd])]}
0x0676 (!(cd)[a{b(!ac)}])
0x0663 !{(cd)[b(!a[cd])]}
0x013d ![(!d[bc]){b{a[bc]}}]
0x019b !{(cd)[b(a{c[bd]})]}
0x0119 ![{a(cd)}(b!({cd}{a(cd)}))]
0x0168 (![c[ab]][d{ab}])
0x16a9 ![{bc}[a(d!(!a(bc)))]]
0x0368 [(a!d)(![bc][d{c(a!d)}])]
0x0198 (![ab][d{ac}])
0x018f !{(c!(ab))(d{ab})}
0x06f1 ![d(!c[a(b!(a!d))])]
0x0183 !{[bc][b(a[cd])]}
0x0182 (!(bd)(![bc][ad]))
0x0181 !{[a(b!(ad))][c(b!(ad))]}
0x07bc [[cd](b![d(a[cd])])]
0x03c3 ![b(c!(bd))]
0x0199 !{[ab](d{bc})}
0x19e3 ![{b(ac)}(!(!ad)[cd])]
0x003c (!d[bc])
0x0016 (!{d(ab)}[a[bc]])
0x0779 !({c[b[a[cd]]]}!([cd]!(a[b[a[cd]]])))
0x0359 ![{ad}(!c[bd])]
0x0006 ([ab]!{cd})
0x016e (!(c![ab])[d{ab}])
0x1698 ({b[ac]}![[bd]{a(d[ac])}])
0x01e9 ![{c(ab)}({ab}!(d{c(ab)}))]
0x16bc [c[b(a[d(bc)])]]
0x166b ![d([a[bc]]!(a![bd]))]
0x0118 (![a(b!(ac))][c[d(b!(ac))]])
0x017f ![d([cd]([ad][bd]))]
0x0001 !{{ab}{cd}}
0x0187 !{[c(ab)](d{ab})}
0x07e1 ![c{(a!d)(b![d(a!c)])}]
0x067e [d{[c(a!d)][a[bd]]}]
0x0117 ![(!d(!(ab)[c{ab}])){{ab}(!(ab)[c{ab}])}]
0x013e [{d(bc)}{a{bc}}]
0x033c [b[c(d!(bc))]]
0x07e6 [{c(ab)}{d[c{ab}]}]
0x036b !({bc}!(!d[a(bc)]))
0x012f !{(b[cd])[c(a[cd])]}
0x0356 [{bc}{ad}]
0x011b ![{b{a(cd)}}(!{cd}{a(cd)})]
0x01ef ![d(!b(!a[cd]))]
0x037c [{bc}{d(a(bc))}]
0x012d !{(d{ab})[b[c{ab}]]}
0x169e [c[a(b!(a![cd]))]]
0x01ae (!(!ac)[d{ab}])
0x01ea ([d{ab}]!(!a[bc]))
0x0019 !{d[a(b!(ac))]}
0x067a {(!d[a[cd]])([cd]![b[a[cd]]])}
0x007f !{d(c(ab))}
0x0776 (!(cd)[a{b(!a{cd})}])
0x006b !{d[c[b(a{bc})]]}
0x17ac [[d{bc}](!a[c(bd)])]
0x011a ([d[ac]][c{a[bd]}])
0x013c ([c[bd]]!(d!(!a[bd])))
0x07f1 ![d(!c{[ad][bd]})]
0x067b ![{d(a![bc])}(!c[a[bc]])]
0x037d ![d({ad}!{[bc](cd)})]
0x0003 !{d{bc}}
0x0069 !{d[c[ab]]}
0x003f !{d(bc)}
0x012c ([b[cd]]![d(!a[cd])])
0x0196 (!(d!(!b[ad]))[b[c[ad]]])
0x001e (!d[c{ab}])
0x0169 !{(d{ab})[b[ac]]}
0x07e2 (!(cd)[{ad}(b[ac])])
0x0693 ![(a[cd])[b(d!(bc))]]
0x016b ![{bc}([a(bc)][d{bc}])]
0x03c0 ([bd][cd])
0x037e [d{[b(a!d)][c(a!d)]}]
0x000f !{cd}
0x001b !{d[b(a[bc])]}
0x0357 !({bc}{ad})
0x0018 (!d([ac][bc]))
0x1689 ![[ad]{[b(!ac)](c![ad])}]
0x0673 !({bd}!([ab][cd]))
0x03cf ![c(b[cd])]
0x069f ![c(![ab][cd])]
0x1697 ![c(![ab]{[ad][cd]})]
0x03de [d{b[c(a!d)]}]
0x179a [a[{c[b(!ad)]}(b!(d[b(!ad)]))]]
0x0017 !{(ab){d(c[ab])}}

View File

@ -1,339 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file xag_dec.hpp
*
* @brief Deompose a truth table into an XAG signal by combined
* decompostion methods (DSD, Shannon, and NPN )
*
* @author Zhufei Chu
* @since 0.1
*/
#ifndef XAG_DEC_HPP
#define XAG_DEC_HPP
#include "../../core/misc.hpp"
#include "build_xag_db.hpp"
namespace phyLS
{
/*! \brief Parameters for xag_dec */
struct xag_dec_params
{
/*! \brief Apply NPN4. */
bool with_npn4{true};
};
class xag_dec_impl
{
private:
std::vector<uint8_t> get_func_supports( kitty::dynamic_truth_table const& spec )
{
std::vector<uint8_t> supports;
for( auto i = 0u; i < spec.num_vars(); ++i )
{
if( kitty::has_var( spec, i ) )
{
supports.push_back( i );
}
}
return supports;
}
public:
xag_dec_impl( xag_network& ntk, kitty::dynamic_truth_table const& func, std::vector<xag_network::signal> const& children,
std::unordered_map<std::string, std::string>& opt_xags,
xag_dec_params const& ps )
: _ntk( ntk ),
_func( func ),
pis( children ),
opt_xags( opt_xags ),
_ps( ps )
{
}
xag_network::signal decompose( kitty::dynamic_truth_table& remainder, std::vector<xag_network::signal> const& children )
{
auto sup = get_func_supports( remainder );
/* check constants */
if ( kitty::is_const0( remainder ) )
{
return _ntk.get_constant( false );
}
if ( kitty::is_const0( ~remainder ) )
{
return _ntk.get_constant( true );
}
/* check primary inputs */
if( sup.size() == 1u )
{
auto var = remainder.construct();
kitty::create_nth_var( var, sup.front() );
if( remainder == var )
{
return children[sup.front()];
}
else
{
assert( remainder == ~var );
return _ntk.create_not( children[sup.front()] );
}
assert( false && "ERROR for primary inputs" );
}
/* top decomposition */
for( auto var : sup )
{
if ( auto res = kitty::is_top_decomposable( remainder, var, &remainder, true );
res != kitty::top_decomposition::none )
{
const auto right = decompose( remainder, children );
switch ( res )
{
default:
assert( false );
case kitty::top_decomposition::and_:
return _ntk.create_and( children[var], right );
case kitty::top_decomposition::or_:
return _ntk.create_or( children[var], right );
case kitty::top_decomposition::lt_:
return _ntk.create_lt( children[var], right );
case kitty::top_decomposition::le_:
return _ntk.create_le( children[var], right );
case kitty::top_decomposition::xor_:
return _ntk.create_xor( children[var], right );
}
}
}
/* bottom decomposition */
for ( auto j = 1u; j < sup.size(); ++j )
{
for ( auto i = 0u; i < j; ++i )
{
if ( auto res = kitty::is_bottom_decomposable( remainder, sup[i], sup[j], &remainder, true );
res != kitty::bottom_decomposition::none ) /* allow XOR */
{
auto copy = children;
switch ( res )
{
default:
assert( false );
case kitty::bottom_decomposition::and_:
copy[sup[i]] = _ntk.create_and( copy[sup[i]], copy[sup[j]] );
break;
case kitty::bottom_decomposition::or_:
copy[sup[i]] = _ntk.create_or( copy[sup[i]], copy[sup[j]] );
break;
case kitty::bottom_decomposition::lt_:
copy[sup[i]] = _ntk.create_lt( copy[sup[i]], copy[sup[j]] );
break;
case kitty::bottom_decomposition::le_:
copy[sup[i]] = _ntk.create_le( copy[sup[i]], copy[sup[j]] );
break;
case kitty::bottom_decomposition::xor_:
copy[sup[i]] = _ntk.create_xor( copy[sup[i]], copy[sup[j]] );
break;
}
return decompose( remainder, copy );
}
}
}
if( sup.size() > 4u || !_ps.with_npn4 )
{
/* shannon decomposition */
auto var = sup.front();
auto c0 = kitty::cofactor0( remainder, var );
auto c1 = kitty::cofactor1( remainder, var );
const auto f0 = decompose( c0, children );
const auto f1 = decompose( c1, children );
return _ntk.create_ite( children[var], f1, f0 );
}
else
{
/* NPN transformation */
return xag_from_npn( remainder, children );
}
assert( false );
}
xag_network::signal xag_from_npn( kitty::dynamic_truth_table const& remainder, std::vector<xag_network::signal> const& children )
{
/* get pi signals */
auto sup = get_func_supports( remainder );
std::vector<xag_network::signal> small_pis;
for( auto const i : sup )
{
small_pis.push_back( children[i] );
}
auto copy = remainder;
const auto support = kitty::min_base_inplace( copy );
const auto small_func = kitty::shrink_to( copy, static_cast<unsigned int>( support.size() ) );
auto tt = small_func;
auto ttsup = get_func_supports( tt );
const auto config = kitty::exact_npn_canonization( tt );
auto func_str = "0x" + kitty::to_hex( std::get<0>( config ) );
//std::cout << " process function " << func_str << std::endl;
const auto it = opt_xags.find( func_str );
assert( it != opt_xags.end() );
std::vector<xag_network::signal> pis( support.size(), _ntk.get_constant( false ) );
std::copy( small_pis.begin(), small_pis.end(), pis.begin() );
std::vector<xag_network::signal> pis_perm( support.size() );
auto perm = std::get<2>( config );
for ( auto i = 0; i < support.size(); ++i )
{
pis_perm[i] = pis[perm[i]];
}
const auto& phase = std::get<1>( config );
for ( auto i = 0; i < support.size(); ++i )
{
if ( ( phase >> perm[i] ) & 1 )
{
pis_perm[i] = !pis_perm[i];
}
}
auto res = create_xag_from_str( it->second, pis_perm );
return ( ( phase >> support.size() ) & 1 ) ? !res : res;
}
xag_network::signal create_xag_from_str( const std::string& str, const std::vector<xag_network::signal>& pis_perm )
{
std::stack<int> polar;
std::stack<xag_network::signal> inputs;
for ( auto i = 0ul; i < str.size(); i++ )
{
// operators polarity
if ( str[i] == '[' || str[i] == '(' || str[i] == '{' )
{
polar.push( (i > 0 && str[i - 1] == '!') ? 1 : 0 );
}
//input signals
if ( str[i] >= 'a' && str[i] <= 'd' )
{
inputs.push( pis_perm[str[i] - 'a'] );
polar.push( ( i > 0 && str[i - 1] == '!' ) ? 1 : 0 );
}
//create signals
if ( str[i] == ']' )
{
assert( inputs.size() >= 2u );
auto x1 = inputs.top();
inputs.pop();
auto x2 = inputs.top();
inputs.pop();
assert( polar.size() >= 3u );
auto p1 = polar.top();
polar.pop();
auto p2 = polar.top();
polar.pop();
auto p3 = polar.top();
polar.pop();
inputs.push( _ntk.create_xor( x1 ^ p1, x2 ^ p2 ) ^ p3 );
polar.push( 0 );
}
if ( str[i] == ')' )
{
assert( inputs.size() >= 2u );
auto x1 = inputs.top();
inputs.pop();
auto x2 = inputs.top();
inputs.pop();
assert( polar.size() >= 3u );
auto p1 = polar.top();
polar.pop();
auto p2 = polar.top();
polar.pop();
auto p3 = polar.top();
polar.pop();
inputs.push( _ntk.create_and( x1 ^ p1, x2 ^ p2 ) ^ p3 );
polar.push( 0 );
}
if ( str[i] == '}' )
{
assert( inputs.size() >= 2u );
auto x1 = inputs.top();
inputs.pop();
auto x2 = inputs.top();
inputs.pop();
assert( polar.size() >= 3u );
auto p1 = polar.top();
polar.pop();
auto p2 = polar.top();
polar.pop();
auto p3 = polar.top();
polar.pop();
inputs.push( _ntk.create_or( x1 ^ p1, x2 ^ p2 ) ^ p3 );
polar.push( 0 );
}
}
assert( !polar.empty() );
auto po = polar.top();
polar.pop();
return inputs.top() ^ po;
}
xag_network::signal run()
{
return decompose( _func, pis );
}
private:
xag_network& _ntk;
kitty::dynamic_truth_table _func;
std::vector<xag_network::signal> pis;
std::unordered_map<std::string, std::string>& opt_xags;
xag_dec_params const& _ps;
};
xag_network::signal xag_dec( xag_network& ntk, kitty::dynamic_truth_table const& func, std::vector<xag_network::signal> const& children,
std::unordered_map<std::string, std::string>& opt_xags,
xag_dec_params const& ps = {} )
{
xag_dec_impl impl( ntk, func, children, opt_xags, ps );
return impl.run();
}
} //end of namespace
#endif

View File

@ -1,45 +0,0 @@
/* phyLS: powerful heightened yielded Logic Synthesis
* Copyright (C) 2023 */
/**
* @file xag_lut_dec.hpp
*
* @brief resynthesis using xag decomposition
*
* @author Zhufei
* @since 0.1
*/
#ifndef XAG_LUT_DEC_HPP
#define XAG_LUT_DEC_HPP
#include "xag_dec.hpp"
#include "build_xag_db.hpp"
namespace mockturtle
{
template<class Ntk>
class xag_lut_dec_resynthesis
{
public:
explicit xag_lut_dec_resynthesis( std::unordered_map<std::string, std::string>& opt_xags )
: opt_xags( opt_xags )
{
}
template<typename LeavesIterator, typename Fn>
void operator()( Ntk& ntk, kitty::dynamic_truth_table const& function, LeavesIterator begin, LeavesIterator end, Fn&& fn ) const
{
const auto f = phyLS::xag_dec( ntk, function, std::vector<signal<Ntk>>( begin, end ), opt_xags );
fn( f );
}
private:
std::unordered_map<std::string, std::string>& opt_xags;
};
}
#endif

Some files were not shown because too many files have changed in this diff Show More