Compare commits
4 Commits
Author | SHA1 | Date |
---|---|---|
panhongyang0 | 577a280b2e | |
panhongyang0 | a29f90f9f2 | |
panhongyang0 | 7686d75739 | |
panhongyang0 | b46512b41b |
|
@ -4,6 +4,3 @@
|
||||||
[submodule "lib/mockturtle"]
|
[submodule "lib/mockturtle"]
|
||||||
path = lib/mockturtle
|
path = lib/mockturtle
|
||||||
url = https://github.com/panhomyoung/mockturtle.git
|
url = https://github.com/panhomyoung/mockturtle.git
|
||||||
[submodule "lib/abc"]
|
|
||||||
path = lib/abc
|
|
||||||
url = https://github.com/panhomyoung/abc.git
|
|
||||||
|
|
14
README.md
14
README.md
|
@ -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
|
## How to Compile
|
||||||
```bash
|
```bash
|
||||||
git clone --recursive https://github.com/panhongyang0/phyLS.git
|
git clone -b aig --recursive https://github.com/panhongyang0/phyLS.git
|
||||||
cd phyLS
|
cd phyLS
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
|
@ -19,3 +19,15 @@ cmake ..
|
||||||
make
|
make
|
||||||
./bin/phyLS
|
./bin/phyLS
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## baseline scripts
|
||||||
|
```bash
|
||||||
|
read_aiger ../benchmarks/adder.aig;
|
||||||
|
ps -a;
|
||||||
|
resub;
|
||||||
|
balance;
|
||||||
|
rewrite;
|
||||||
|
read_genlib ../src/mcnc.genlib;
|
||||||
|
techmap;
|
||||||
|
quit;
|
||||||
|
```
|
|
@ -1,8 +1,3 @@
|
||||||
# Add alice and mockturtle sub directories
|
# Add alice and mockturtle sub directories
|
||||||
add_subdirectory(alice)
|
add_subdirectory(alice)
|
||||||
add_subdirectory(mockturtle)
|
add_subdirectory(mockturtle)
|
||||||
|
|
||||||
set(ABC_USE_NAMESPACE "pabc")
|
|
||||||
|
|
||||||
add_subdirectory(abc EXCLUDE_FROM_ALL)
|
|
||||||
target_compile_definitions(libabc-pic PUBLIC "LIN64")
|
|
1
lib/abc
1
lib/abc
|
@ -1 +0,0 @@
|
||||||
Subproject commit 9434b7438599b2fe94ec518946d0e1b6b2de3172
|
|
Binary file not shown.
|
@ -5,4 +5,4 @@ file(GLOB_RECURSE FILENAMES *.cpp)
|
||||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||||
|
|
||||||
add_executable(phyLS phyLS.cpp ${FILENAMES})
|
add_executable(phyLS phyLS.cpp ${FILENAMES})
|
||||||
target_link_libraries(phyLS alice mockturtle libabc-pic)
|
target_link_libraries(phyLS alice mockturtle)
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -13,15 +13,8 @@
|
||||||
#ifndef BALANCE_HPP
|
#ifndef BALANCE_HPP
|
||||||
#define 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/misc.hpp"
|
||||||
|
#include "../core/balance.hpp"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace mockturtle;
|
using namespace mockturtle;
|
||||||
|
@ -33,56 +26,21 @@ class balance_command : public command {
|
||||||
explicit balance_command(const environment::ptr& env)
|
explicit balance_command(const environment::ptr& env)
|
||||||
: command(env,
|
: command(env,
|
||||||
"transforms the current network into a well-balanced AIG") {
|
"transforms the current network into a well-balanced AIG") {
|
||||||
add_flag("--xmg, -x", "Balance for XMG");
|
|
||||||
add_flag("--strash, -s", "Balance AND finding structural hashing");
|
|
||||||
add_flag("--verbose, -v", "print the information");
|
add_flag("--verbose, -v", "print the information");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void execute() {
|
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)
|
if (store<aig_network>().size() == 0u)
|
||||||
std::cerr << "Error: Empty AIG network\n";
|
std::cerr << "Error: Empty AIG network\n";
|
||||||
else {
|
else {
|
||||||
auto aig = store<aig_network>().current();
|
auto aig = store<aig_network>().current();
|
||||||
if (is_set("strash")) {
|
phyLS::aig_balancing(aig);
|
||||||
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);
|
phyLS::print_stats(aig);
|
||||||
|
|
||||||
store<aig_network>().extend();
|
store<aig_network>().extend();
|
||||||
store<aig_network>().current() = aig;
|
store<aig_network>().current() = aig;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cout.setf(ios::fixed);
|
|
||||||
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ALICE_ADD_COMMAND(balance, "Synthesis")
|
ALICE_ADD_COMMAND(balance, "Synthesis")
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -13,25 +13,7 @@
|
||||||
#ifndef RESUB_HPP
|
#ifndef RESUB_HPP
|
||||||
#define RESUB_HPP
|
#define RESUB_HPP
|
||||||
|
|
||||||
#include <time.h>
|
#include "../core/resub.hpp"
|
||||||
|
|
||||||
#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/misc.hpp"
|
#include "../core/misc.hpp"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
@ -43,100 +25,21 @@ class resub_command : public command {
|
||||||
: command(
|
: command(
|
||||||
env,
|
env,
|
||||||
"performs technology-independent restructuring [default = AIG]") {
|
"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");
|
add_flag("--verbose, -v", "print the information");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void execute() {
|
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)
|
if (store<aig_network>().size() == 0u)
|
||||||
std::cerr << "Error: Empty AIG network\n";
|
std::cerr << "Error: Empty AIG network\n";
|
||||||
else {
|
else {
|
||||||
auto aig = store<aig_network>().current();
|
auto aig = store<aig_network>().current();
|
||||||
if (is_set("simulation")) {
|
phyLS::aig_resub(aig);
|
||||||
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);
|
phyLS::print_stats(aig);
|
||||||
store<aig_network>().extend();
|
store<aig_network>().extend();
|
||||||
store<aig_network>().current() = aig;
|
store<aig_network>().current() = aig;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cout.setf(ios::fixed);
|
|
||||||
cout << "[CPU time] " << setprecision(2) << totalTime << " s" << endl;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ALICE_ADD_COMMAND(resub, "Synthesis")
|
ALICE_ADD_COMMAND(resub, "Synthesis")
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -17,9 +17,6 @@
|
||||||
#include <mockturtle/io/genlib_reader.hpp>
|
#include <mockturtle/io/genlib_reader.hpp>
|
||||||
#include <mockturtle/io/write_verilog.hpp>
|
#include <mockturtle/io/write_verilog.hpp>
|
||||||
#include <mockturtle/networks/aig.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 <mockturtle/utils/tech_library.hpp>
|
||||||
|
|
||||||
#include "../core/properties.hpp"
|
#include "../core/properties.hpp"
|
||||||
|
@ -30,9 +27,6 @@ class techmap_command : public command {
|
||||||
public:
|
public:
|
||||||
explicit techmap_command(const environment::ptr& env)
|
explicit techmap_command(const environment::ptr& env)
|
||||||
: command(env, "Standard cell mapping [default = AIG]") {
|
: 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_option("--output, -o", filename, "the verilog filename");
|
||||||
add_flag("--verbose, -v", "print the information");
|
add_flag("--verbose, -v", "print the information");
|
||||||
}
|
}
|
||||||
|
@ -54,64 +48,6 @@ class techmap_command : public command {
|
||||||
mockturtle::map_params ps;
|
mockturtle::map_params ps;
|
||||||
mockturtle::map_stats st;
|
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);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (store<aig_network>().size() == 0u) {
|
if (store<aig_network>().size() == 0u) {
|
||||||
std::cerr << "[e] no AIG in the store\n";
|
std::cerr << "[e] no AIG in the store\n";
|
||||||
} else {
|
} else {
|
||||||
|
@ -120,16 +56,10 @@ class techmap_command : public command {
|
||||||
|
|
||||||
if (is_set("output")) write_verilog_with_binding(res, filename);
|
if (is_set("output")) write_verilog_with_binding(res, filename);
|
||||||
|
|
||||||
// std::cout << fmt::format(
|
std::cout << fmt::format(
|
||||||
// "Mapped AIG into #gates = {}, area = {:.2f}, delay = {:.2f}, "
|
"Mapped AIG into #gates = {}, area = {:.2f}, delay = {:.2f}, "
|
||||||
// "power = {:.2f}\n",
|
"power = {:.2f}\n",
|
||||||
// res.num_gates(), st.area, st.delay, st.power);
|
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
@ -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
|
@ -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
|
|
277
src/core/ps2.hpp
277
src/core/ps2.hpp
|
@ -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
|
|
|
@ -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"
|
||||||
|
}
|
||||||
|
}
|
|
@ -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:
|
|
@ -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"
|
||||||
|
}
|
||||||
|
}
|
|
@ -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`.
|
824
src/core/rm.hpp
824
src/core/rm.hpp
|
@ -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
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
1636
src/core/stp_sat.hpp
1636
src/core/stp_sat.hpp
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
|
@ -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
|
|
|
@ -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!(!a!b)]= (!ab) [!a!(!a!b)]= !(!ab)*/
|
|
||||||
bool reduce_depth_use_xor_or_convert( node<Ntk> const& n )
|
|
||||||
{
|
|
||||||
if ( ntk.level( n ) == 0 )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* get children of top node, ordered by node level (ascending). */
|
|
||||||
auto ocs = ordered_children( n );
|
|
||||||
|
|
||||||
/* depth of last child must be (significantly) higher than depth of second child */
|
|
||||||
if ( ntk.level( ntk.get_node( ocs[1] ) ) <= ntk.level( ntk.get_node( ocs[0] ) ) + 1 )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if ( !ntk.is_xor( n ) && !ntk.is_and( ntk.get_node( ocs[1] ) ) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto ocs2 = ordered_children(ntk.get_node(ocs[1]));
|
|
||||||
|
|
||||||
if (ocs[0].index == ocs2[0].index && ntk.is_complemented(ocs[1]) && ntk.is_complemented(ocs2[0]) && ntk.is_complemented(ocs2[1]) && ntk.fanout_size(ntk.get_node(ocs[1])) == 1 )
|
|
||||||
{
|
|
||||||
if(ntk.is_complemented(ocs[0]))
|
|
||||||
{
|
|
||||||
ocs2[1] = !ocs2[1];
|
|
||||||
auto opt = ntk.create_nand(ocs2[0], ocs2[1]);
|
|
||||||
ntk.substitute_node(n, opt);
|
|
||||||
ntk.update_levels();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ocs2[1] = !ocs2[1];
|
|
||||||
auto opt = ntk.create_and(ocs2[0], ocs2[1]);
|
|
||||||
ntk.substitute_node(n, opt);
|
|
||||||
ntk.update_levels();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
/**************************************************************************************************************/
|
|
||||||
/*{a!b} = {a[!ab]} = !(!a![!ab])); !{a!b} = (!ab)*/
|
|
||||||
bool reduce_depth_use_xor_or_convert2( node<Ntk> const& n )
|
|
||||||
{
|
|
||||||
if ( ntk.level( n ) == 0 )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* get children of top node, ordered by node level (ascending). */
|
|
||||||
const auto ocs = ordered_children( n );
|
|
||||||
|
|
||||||
/* depth of last child must be (significantly) higher than depth of second child */
|
|
||||||
if ( ntk.level( ntk.get_node( ocs[1] ) ) <= ntk.level( ntk.get_node( ocs[0] ) ) + 1 )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if ( !ntk.is_and( n ) && !ntk.is_xor( ntk.get_node( ocs[1] ) ) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto ocs2 = ordered_children( ntk.get_node( ocs[1] ) );
|
|
||||||
|
|
||||||
if(ntk.is_complemented(ocs[0]) && ntk.is_complemented(ocs[1]) && ocs[0] == ocs2[0] )
|
|
||||||
{
|
|
||||||
if(ntk.fanout_size(ntk.get_node(ocs[1])) == 1 && !ntk.is_complemented(ocs2[1]))
|
|
||||||
{
|
|
||||||
auto opt = ntk.create_or(ocs2[0], ocs2[1]);
|
|
||||||
ntk.substitute_node(n, opt);
|
|
||||||
ntk.update_levels();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
/*****************************************Optimization Functions End***********************************************************************/
|
|
||||||
|
|
||||||
/*****************************************Other Necessary Parts Begin**********************************************************************/
|
|
||||||
|
|
||||||
bool is_signal_equal( const signal<Ntk>& a, const signal<Ntk>& b )
|
|
||||||
{
|
|
||||||
return ( a == b ? true : false );
|
|
||||||
}
|
|
||||||
/**************************************************************************************************************/
|
|
||||||
/* used for the subsquent judgement of the common child-node. */
|
|
||||||
using children_t = std::array< signal<Ntk>, 2 >;
|
|
||||||
std::bitset<4> get_pair_pattern( const children_t& c1, const children_t& c2 )
|
|
||||||
{
|
|
||||||
std::bitset<4> equals;
|
|
||||||
|
|
||||||
equals.set( 0u, is_signal_equal( c1[0], c2[0] ) );
|
|
||||||
equals.set( 1u, is_signal_equal( c1[0], c2[1] ) );
|
|
||||||
equals.set( 2u, is_signal_equal( c1[1], c2[0] ) );
|
|
||||||
equals.set( 3u, is_signal_equal( c1[1], c2[1] ) );
|
|
||||||
|
|
||||||
return equals;
|
|
||||||
}
|
|
||||||
/**************************************************************************************************************/
|
|
||||||
/* used to judge which two nodes are common. */
|
|
||||||
std::vector<size_t> equal_idx( const std::bitset<4> pattern )
|
|
||||||
{
|
|
||||||
std::vector<size_t> r;
|
|
||||||
for( size_t idx = 0; idx < pattern.size(); idx++ )
|
|
||||||
{
|
|
||||||
if( pattern.test( idx ) )
|
|
||||||
{
|
|
||||||
r.push_back( idx );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
/**************************************************************************************************************/
|
|
||||||
struct grand_children_pair_t
|
|
||||||
{
|
|
||||||
signal<Ntk> x;
|
|
||||||
signal<Ntk> y;
|
|
||||||
signal<Ntk> a; //common grand child a
|
|
||||||
};
|
|
||||||
/**************************************************************************************************************/
|
|
||||||
std::optional<grand_children_pair_t> find_common_grand_child_two( const children_t& c1, const children_t& c2 )
|
|
||||||
{
|
|
||||||
grand_children_pair_t r;
|
|
||||||
auto p = get_pair_pattern( c1, c2 );
|
|
||||||
|
|
||||||
std::vector<signal<Ntk>> common;
|
|
||||||
|
|
||||||
for( size_t idx = 0; idx < p.size(); idx++ )
|
|
||||||
{
|
|
||||||
if( p.test(idx) )
|
|
||||||
{
|
|
||||||
assert( c1[idx / 2] == c2[ idx % 2 ] );
|
|
||||||
common.push_back( c1[ idx / 2] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* for xor children, require at least one common children */
|
|
||||||
if( common.size() != 1u )
|
|
||||||
return std::nullopt;
|
|
||||||
|
|
||||||
/* save the records */
|
|
||||||
r.a = common[0u];
|
|
||||||
|
|
||||||
for( auto i = 0u; i < 2u; i++ )
|
|
||||||
{
|
|
||||||
if( c1[i] != common[0u] && c1[i] != common[0u] )
|
|
||||||
{
|
|
||||||
r.x = c1[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if( c2[i] != common[0u] && c2[i] != common[0u] )
|
|
||||||
{
|
|
||||||
r.y = c2[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
/**************************************************************************************************************/
|
|
||||||
|
|
||||||
std::array<signal<Ntk>, 2> ordered_children( node<Ntk> const& n ) const
|
|
||||||
{
|
|
||||||
std::array<signal<Ntk>, 2> children;
|
|
||||||
ntk.foreach_fanin( n, [&children]( auto const& f, auto i ) { children[i] = f; } );
|
|
||||||
std::sort( children.begin(), children.end(), [this]( auto const& c1, auto const& c2 ) {
|
|
||||||
if( ntk.level( ntk.get_node( c1 ) ) == ntk.level( ntk.get_node( c2 ) ) )
|
|
||||||
{
|
|
||||||
return c1.index < c2.index;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return ntk.level( ntk.get_node( c1 ) ) < ntk.level( ntk.get_node( c2 ) );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
return children;
|
|
||||||
}
|
|
||||||
/**************************************************************************************************************/
|
|
||||||
void mark_critical_path( node<Ntk> const& n )
|
|
||||||
{
|
|
||||||
if ( ntk.is_pi( n ) || ntk.is_constant( n ) || ntk.value( n ) )
|
|
||||||
return;
|
|
||||||
|
|
||||||
const auto level = ntk.level( n );
|
|
||||||
ntk.set_value( n, 1 );
|
|
||||||
ntk.foreach_fanin( n, [this, level]( auto const& f ) {
|
|
||||||
if ( ntk.level( ntk.get_node( f ) ) == level - 1 )
|
|
||||||
{
|
|
||||||
mark_critical_path( ntk.get_node( f ) );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
/**************************************************************************************************************/
|
|
||||||
void mark_critical_paths()
|
|
||||||
{
|
|
||||||
ntk.clear_values();
|
|
||||||
ntk.foreach_po( [this]( auto const& f ) {
|
|
||||||
if ( ntk.level( ntk.get_node( f ) ) == ntk.depth() )
|
|
||||||
{
|
|
||||||
mark_critical_path( ntk.get_node( f ) );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
/*****************************************Other Necessary Parts End************************************************************************/
|
|
||||||
private:
|
|
||||||
Ntk& ntk;
|
|
||||||
xag_depth_rewriting_params const& ps;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
/*! \brief xag algebraic depth rewriting.
|
|
||||||
*
|
|
||||||
* This algorithm tries to rewrite a network with majority gates for depth
|
|
||||||
* optimization using the associativity and distributivity rule in
|
|
||||||
* majority-of-3 logic. It can be applied to networks other than xags, but
|
|
||||||
* only considers pairs of nodes which both implement the majority-of-3
|
|
||||||
* function and the XOR function.
|
|
||||||
*
|
|
||||||
* **Required network functions:**
|
|
||||||
* - `get_node`
|
|
||||||
* - `level`
|
|
||||||
* - `update_levels`
|
|
||||||
* - `create_maj`
|
|
||||||
* - `substitute_node`
|
|
||||||
* - `foreach_node`
|
|
||||||
* - `foreach_po`
|
|
||||||
* - `foreach_fanin`
|
|
||||||
* - `is_maj`
|
|
||||||
* - `clear_values`
|
|
||||||
* - `set_value`
|
|
||||||
* - `value`
|
|
||||||
* - `fanout_size`
|
|
||||||
*
|
|
||||||
\verbatim embed:rst
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
\endverbatim
|
|
||||||
*/
|
|
||||||
template<class Ntk>
|
|
||||||
void xag_depth_rewriting( Ntk& ntk, xag_depth_rewriting_params const& ps = {} )
|
|
||||||
{
|
|
||||||
static_assert( is_network_type_v<Ntk>, "Ntk is not a network type" );
|
|
||||||
static_assert( has_get_node_v<Ntk>, "Ntk does not implement the get_node method" );
|
|
||||||
static_assert( has_level_v<Ntk>, "Ntk does not implement the level method" );
|
|
||||||
static_assert( has_create_maj_v<Ntk>, "Ntk does not implement the create_maj method" );
|
|
||||||
static_assert( has_create_xor_v<Ntk>, "Ntk does not implement the create_maj method" );
|
|
||||||
static_assert( has_substitute_node_v<Ntk>, "Ntk does not implement the substitute_node method" );
|
|
||||||
static_assert( has_update_levels_v<Ntk>, "Ntk does not implement the update_levels method" );
|
|
||||||
static_assert( has_foreach_node_v<Ntk>, "Ntk does not implement the foreach_node method" );
|
|
||||||
static_assert( has_foreach_po_v<Ntk>, "Ntk does not implement the foreach_po method" );
|
|
||||||
static_assert( has_foreach_fanin_v<Ntk>, "Ntk does not implement the foreach_fanin method" );
|
|
||||||
static_assert( has_is_and_v<Ntk>, "Ntk does not implement the is_and method" );
|
|
||||||
static_assert( has_is_xor_v<Ntk>, "Ntk does not implement the is_xor method" );
|
|
||||||
static_assert( has_clear_values_v<Ntk>, "Ntk does not implement the clear_values method" );
|
|
||||||
static_assert( has_set_value_v<Ntk>, "Ntk does not implement the set_value method" );
|
|
||||||
static_assert( has_value_v<Ntk>, "Ntk does not implement the value method" );
|
|
||||||
static_assert( has_fanout_size_v<Ntk>, "Ntk does not implement the fanout_size method" );
|
|
||||||
|
|
||||||
detail::xag_depth_rewriting_impl<Ntk> p( ntk, ps );
|
|
||||||
p.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* namespace mockturtle */
|
|
|
@ -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 */
|
|
|
@ -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
|
|
|
@ -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 */
|
|
|
@ -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
|
|
335636
src/lzmlib.aig
335636
src/lzmlib.aig
File diff suppressed because one or more lines are too long
|
@ -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
|
@ -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])}}
|
|
|
@ -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
|
|
|
@ -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
Loading…
Reference in New Issue