Commit 5e0f86a2 by Alan Mishchenko

Version abc51128

parent 3a1ca9fa
No preview for this file type
...@@ -71,9 +71,6 @@ alias resynl "b; rw -l; rwz -l; b; rwz -l; b" ...@@ -71,9 +71,6 @@ alias resynl "b; rw -l; rwz -l; b; rwz -l; b"
alias resyn2 "b; rw; rf; b; rw; rwz; b; rfz; rwz; b" alias resyn2 "b; rw; rf; b; rw; rwz; b; rfz; rwz; b"
alias resyn2l "b; rw -l; rf -l; b; rw -l; rwz -l; b; rfz -l; rwz -l; b" alias resyn2l "b; rw -l; rf -l; b; rw -l; rwz -l; b; rfz -l; rwz -l; b"
alias thin "rwz; rfz; b; ps" alias thin "rwz; rfz; b; ps"
alias reti "st; seq; ret; unseq; st" alias choice "fsto; resynl; fsto; resyn2l; fsto; fres"
alias retis "st; seq; ret; unseq -s; st" alias t "r iscas2/s3330_edf.blif; st; seq; smap"
alias choice "fraig_store; resyn; fraig_store; resyn2; fraig_store; fraig_restore"
alias stest "st; ps; seq; ps; unseq; st; ps; sec"
alias t "r pan2.blif; st; seq; sfpga; sec"
...@@ -235,8 +235,8 @@ Abc_Ntk_t * Abc_NtkStartRead( char * pName ) ...@@ -235,8 +235,8 @@ Abc_Ntk_t * Abc_NtkStartRead( char * pName )
// allocate the empty network // allocate the empty network
pNtkNew = Abc_NtkAlloc( ABC_NTK_NETLIST, ABC_FUNC_SOP ); pNtkNew = Abc_NtkAlloc( ABC_NTK_NETLIST, ABC_FUNC_SOP );
// set the specs // set the specs
pNtkNew->pName = util_strsav( pName ); pNtkNew->pName = util_strsav( Extra_FileNameGeneric(pName) );
pNtkNew->pSpec = util_strsav( pName ); pNtkNew->pSpec = util_strsav( Extra_FileNameGeneric(pName) );
return pNtkNew; return pNtkNew;
} }
...@@ -313,7 +313,11 @@ Abc_Ntk_t * Abc_NtkDup( Abc_Ntk_t * pNtk ) ...@@ -313,7 +313,11 @@ Abc_Ntk_t * Abc_NtkDup( Abc_Ntk_t * pNtk )
// copy the nodes // copy the nodes
Abc_NtkForEachObj( pNtk, pObj, i ) Abc_NtkForEachObj( pNtk, pObj, i )
if ( pObj->pCopy == NULL ) if ( pObj->pCopy == NULL )
{
Abc_NtkDupObj(pNtkNew, pObj); Abc_NtkDupObj(pNtkNew, pObj);
pObj->pCopy->Level = pObj->Level;
pObj->pCopy->fPhase = pObj->fPhase;
}
// connect the nodes // connect the nodes
Abc_NtkForEachObj( pNtk, pObj, i ) Abc_NtkForEachObj( pNtk, pObj, i )
{ {
......
...@@ -5100,17 +5100,16 @@ int Abc_CommandRetime( Abc_Frame_t * pAbc, int argc, char ** argv ) ...@@ -5100,17 +5100,16 @@ int Abc_CommandRetime( Abc_Frame_t * pAbc, int argc, char ** argv )
if ( Abc_NtkHasAig(pNtk) ) if ( Abc_NtkHasAig(pNtk) )
{ {
// quit if there are choice nodes
if ( Abc_NtkGetChoiceNum(pNtk) )
{
fprintf( pErr, "Currently cannot retime networks with choice nodes.\n" );
return 0;
}
if ( Abc_NtkIsStrash(pNtk) ) if ( Abc_NtkIsStrash(pNtk) )
pNtkRes = Abc_NtkAigToSeq(pNtk); pNtkRes = Abc_NtkAigToSeq(pNtk);
else else
{
if ( Abc_NtkGetChoiceNum(pNtk) )
{
fprintf( pErr, "Currently cannot retime networks with choice nodes.\n" );
return 0;
}
pNtkRes = Abc_NtkDup(pNtk); pNtkRes = Abc_NtkDup(pNtk);
}
// retime the network // retime the network
if ( fForward ) if ( fForward )
Seq_NtkSeqRetimeForward( pNtkRes, fInitial, fVerbose ); Seq_NtkSeqRetimeForward( pNtkRes, fInitial, fVerbose );
...@@ -5118,11 +5117,13 @@ int Abc_CommandRetime( Abc_Frame_t * pAbc, int argc, char ** argv ) ...@@ -5118,11 +5117,13 @@ int Abc_CommandRetime( Abc_Frame_t * pAbc, int argc, char ** argv )
Seq_NtkSeqRetimeBackward( pNtkRes, fInitial, fVerbose ); Seq_NtkSeqRetimeBackward( pNtkRes, fInitial, fVerbose );
else else
Seq_NtkSeqRetimeDelay( pNtkRes, nMaxIters, fInitial, fVerbose ); Seq_NtkSeqRetimeDelay( pNtkRes, nMaxIters, fInitial, fVerbose );
// convert from the sequential AIG // if the network is an AIG, convert the result into an AIG
if ( Abc_NtkIsStrash(pNtk) ) if ( Abc_NtkIsStrash(pNtk) )
{ {
pNtkRes = Abc_NtkSeqToLogicSop( pNtkTemp = pNtkRes ); pNtkRes = Abc_NtkSeqToLogicSop( pNtkTemp = pNtkRes );
Abc_NtkDelete( pNtkTemp ); Abc_NtkDelete( pNtkTemp );
pNtkRes = Abc_NtkStrash( pNtkTemp = pNtkRes, 0, 0 );
Abc_NtkDelete( pNtkTemp );
} }
} }
else else
...@@ -5162,7 +5163,7 @@ usage: ...@@ -5162,7 +5163,7 @@ usage:
int Abc_CommandSeqFpga( Abc_Frame_t * pAbc, int argc, char ** argv ) int Abc_CommandSeqFpga( Abc_Frame_t * pAbc, int argc, char ** argv )
{ {
FILE * pOut, * pErr; FILE * pOut, * pErr;
Abc_Ntk_t * pNtk, * pNtkRes; Abc_Ntk_t * pNtk, * pNtkNew, * pNtkRes;
int c, nMaxIters; int c, nMaxIters;
int fVerbose; int fVerbose;
...@@ -5205,26 +5206,65 @@ int Abc_CommandSeqFpga( Abc_Frame_t * pAbc, int argc, char ** argv ) ...@@ -5205,26 +5206,65 @@ int Abc_CommandSeqFpga( Abc_Frame_t * pAbc, int argc, char ** argv )
return 1; return 1;
} }
if ( !Abc_NtkIsSeq(pNtk) ) if ( Abc_NtkHasAig(pNtk) )
{ {
fprintf( pErr, "Sequential FPGA mapping works only for sequential AIG (run \"seq\").\n" ); // quit if there are choice nodes
return 0; if ( Abc_NtkGetChoiceNum(pNtk) )
{
fprintf( pErr, "Currently cannot map/retime networks with choice nodes.\n" );
return 0;
}
if ( Abc_NtkIsStrash(pNtk) )
pNtkNew = Abc_NtkAigToSeq(pNtk);
else
pNtkNew = Abc_NtkDup(pNtk);
}
else
{
// strash and balance the network
pNtkNew = Abc_NtkStrash( pNtk, 0, 0 );
if ( pNtkNew == NULL )
{
fprintf( pErr, "Strashing before FPGA mapping/retiming has failed.\n" );
return 1;
}
pNtkNew = Abc_NtkBalance( pNtkRes = pNtkNew, 0 );
Abc_NtkDelete( pNtkRes );
if ( pNtkNew == NULL )
{
fprintf( pErr, "Balancing before FPGA mapping has failed.\n" );
return 1;
}
// convert into a sequential AIG
pNtkNew = Abc_NtkAigToSeq( pNtkRes = pNtkNew );
Abc_NtkDelete( pNtkRes );
if ( pNtkNew == NULL )
{
fprintf( pErr, "Converting into a seq AIG before FPGA mapping/retiming has failed.\n" );
return 1;
}
fprintf( pOut, "The network was strashed and balanced before FPGA mapping/retiming.\n" );
} }
// get the new network // get the new network
pNtkRes = Seq_NtkFpgaMapRetime( pNtk, nMaxIters, fVerbose ); pNtkRes = Seq_NtkFpgaMapRetime( pNtkNew, nMaxIters, fVerbose );
if ( pNtkRes == NULL ) if ( pNtkRes == NULL )
{ {
fprintf( pErr, "Sequential FPGA mapping has failed.\n" ); fprintf( pErr, "Sequential FPGA mapping has failed.\n" );
Abc_NtkDelete( pNtkNew );
return 0; return 0;
} }
Abc_NtkDelete( pNtkNew );
// replace the current network // replace the current network
Abc_FrameReplaceCurrentNetwork( pAbc, pNtkRes ); Abc_FrameReplaceCurrentNetwork( pAbc, pNtkRes );
return 0; return 0;
usage: usage:
fprintf( pErr, "usage: sfpga [-I num] [-vh]\n" ); fprintf( pErr, "usage: sfpga [-I num] [-vh]\n" );
fprintf( pErr, "\t performs integrated sequential FPGA mapping\n" ); fprintf( pErr, "\t performs integrated sequential FPGA mapping/retiming\n" );
fprintf( pErr, "\t-I num : max number of iterations of l-value computation [default = %d]\n", nMaxIters ); fprintf( pErr, "\t-I num : max number of iterations of l-value computation [default = %d]\n", nMaxIters );
fprintf( pErr, "\t-v : toggle verbose output [default = %s]\n", fVerbose? "yes": "no" ); fprintf( pErr, "\t-v : toggle verbose output [default = %s]\n", fVerbose? "yes": "no" );
fprintf( pErr, "\t-h : print the command usage\n"); fprintf( pErr, "\t-h : print the command usage\n");
...@@ -5245,7 +5285,7 @@ usage: ...@@ -5245,7 +5285,7 @@ usage:
int Abc_CommandSeqMap( Abc_Frame_t * pAbc, int argc, char ** argv ) int Abc_CommandSeqMap( Abc_Frame_t * pAbc, int argc, char ** argv )
{ {
FILE * pOut, * pErr; FILE * pOut, * pErr;
Abc_Ntk_t * pNtk, * pNtkRes; Abc_Ntk_t * pNtk, * pNtkNew, * pNtkRes;
int c, nMaxIters; int c, nMaxIters;
int fVerbose; int fVerbose;
...@@ -5255,7 +5295,7 @@ int Abc_CommandSeqMap( Abc_Frame_t * pAbc, int argc, char ** argv ) ...@@ -5255,7 +5295,7 @@ int Abc_CommandSeqMap( Abc_Frame_t * pAbc, int argc, char ** argv )
// set defaults // set defaults
nMaxIters = 15; nMaxIters = 15;
fVerbose = 1; fVerbose = 0;
util_getopt_reset(); util_getopt_reset();
while ( ( c = util_getopt( argc, argv, "Ivh" ) ) != EOF ) while ( ( c = util_getopt( argc, argv, "Ivh" ) ) != EOF )
{ {
...@@ -5288,28 +5328,66 @@ int Abc_CommandSeqMap( Abc_Frame_t * pAbc, int argc, char ** argv ) ...@@ -5288,28 +5328,66 @@ int Abc_CommandSeqMap( Abc_Frame_t * pAbc, int argc, char ** argv )
return 1; return 1;
} }
if ( !Abc_NtkIsSeq(pNtk) ) if ( Abc_NtkHasAig(pNtk) )
{ {
fprintf( pErr, "Sequential standard cell mapping works only for sequential AIG (run \"seq\").\n" ); // quit if there are choice nodes
return 1; if ( Abc_NtkGetChoiceNum(pNtk) )
{
fprintf( pErr, "Currently cannot map/retime networks with choice nodes.\n" );
return 0;
}
if ( Abc_NtkIsStrash(pNtk) )
pNtkNew = Abc_NtkAigToSeq(pNtk);
else
pNtkNew = Abc_NtkDup(pNtk);
}
else
{
// strash and balance the network
pNtkNew = Abc_NtkStrash( pNtk, 0, 0 );
if ( pNtkNew == NULL )
{
fprintf( pErr, "Strashing before SC mapping/retiming has failed.\n" );
return 1;
}
pNtkNew = Abc_NtkBalance( pNtkRes = pNtkNew, 0 );
Abc_NtkDelete( pNtkRes );
if ( pNtkNew == NULL )
{
fprintf( pErr, "Balancing before SC mapping/retiming has failed.\n" );
return 1;
}
// convert into a sequential AIG
pNtkNew = Abc_NtkAigToSeq( pNtkRes = pNtkNew );
Abc_NtkDelete( pNtkRes );
if ( pNtkNew == NULL )
{
fprintf( pErr, "Converting into a seq AIG before SC mapping/retiming has failed.\n" );
return 1;
}
fprintf( pOut, "The network was strashed and balanced before SC mapping/retiming.\n" );
} }
// printf( "This command is not yet implemented.\n" );
// return 0;
// get the new network // get the new network
pNtkRes = Seq_MapRetime( pNtk, nMaxIters, fVerbose ); pNtkRes = Seq_MapRetime( pNtkNew, nMaxIters, fVerbose );
if ( pNtkRes == NULL ) if ( pNtkRes == NULL )
{ {
fprintf( pErr, "Sequential standard-cell mapping has failed.\n" ); fprintf( pErr, "Sequential FPGA mapping has failed.\n" );
Abc_NtkDelete( pNtkNew );
return 1; return 1;
} }
Abc_NtkDelete( pNtkNew );
// replace the current network // replace the current network
Abc_FrameReplaceCurrentNetwork( pAbc, pNtkRes ); Abc_FrameReplaceCurrentNetwork( pAbc, pNtkRes );
return 0; return 0;
usage: usage:
fprintf( pErr, "usage: smap [-I num] [-vh]\n" ); fprintf( pErr, "usage: smap [-I num] [-vh]\n" );
fprintf( pErr, "\t performs integrated sequential standard-cell mapping" ); fprintf( pErr, "\t performs integrated sequential standard-cell mapping/retiming\n" );
fprintf( pErr, "\t-I num : max number of iterations of l-value computation [default = %d]\n", nMaxIters ); fprintf( pErr, "\t-I num : max number of iterations of l-value computation [default = %d]\n", nMaxIters );
fprintf( pErr, "\t-v : toggle verbose output [default = %s]\n", fVerbose? "yes": "no" ); fprintf( pErr, "\t-v : toggle verbose output [default = %s]\n", fVerbose? "yes": "no" );
fprintf( pErr, "\t-h : print the command usage\n"); fprintf( pErr, "\t-h : print the command usage\n");
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
static char * Abc_NtkPrintSop( char * pSop ); static char * Abc_NtkPrintSop( char * pSop );
static int Abc_NtkCountLogicNodes( Vec_Ptr_t * vNodes );
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS /// /// FUNCTION DEFINITIONS ///
...@@ -181,7 +182,7 @@ void Io_WriteDotAig( Abc_Ntk_t * pNtk, Vec_Ptr_t * vNodes, Vec_Ptr_t * vNodesSho ...@@ -181,7 +182,7 @@ void Io_WriteDotAig( Abc_Ntk_t * pNtk, Vec_Ptr_t * vNodes, Vec_Ptr_t * vNodesSho
fprintf( pFile, " fontsize=18,\n" ); fprintf( pFile, " fontsize=18,\n" );
fprintf( pFile, " fontname = \"Times-Roman\",\n" ); fprintf( pFile, " fontname = \"Times-Roman\",\n" );
fprintf( pFile, " label=\"" ); fprintf( pFile, " label=\"" );
fprintf( pFile, "The set contains %d nodes and spans %d levels.", vNodes->nSize, LevelMax - LevelMin + 1 ); fprintf( pFile, "The set contains %d logic nodes and spans %d levels.", Abc_NtkCountLogicNodes(vNodes), LevelMax - LevelMin + 1 );
fprintf( pFile, "\\n" ); fprintf( pFile, "\\n" );
fprintf( pFile, "\"\n" ); fprintf( pFile, "\"\n" );
fprintf( pFile, " ];\n" ); fprintf( pFile, " ];\n" );
...@@ -526,7 +527,7 @@ void Io_WriteDotNtk( Abc_Ntk_t * pNtk, Vec_Ptr_t * vNodes, Vec_Ptr_t * vNodesSho ...@@ -526,7 +527,7 @@ void Io_WriteDotNtk( Abc_Ntk_t * pNtk, Vec_Ptr_t * vNodes, Vec_Ptr_t * vNodesSho
fprintf( pFile, " fontsize=18,\n" ); fprintf( pFile, " fontsize=18,\n" );
fprintf( pFile, " fontname = \"Times-Roman\",\n" ); fprintf( pFile, " fontname = \"Times-Roman\",\n" );
fprintf( pFile, " label=\"" ); fprintf( pFile, " label=\"" );
fprintf( pFile, "The set contains %d nodes and spans %d levels.", vNodes->nSize, LevelMax - LevelMin + 1 ); fprintf( pFile, "The set contains %d logic nodes and spans %d levels.", Abc_NtkCountLogicNodes(vNodes), LevelMax - LevelMin + 1 );
fprintf( pFile, "\\n" ); fprintf( pFile, "\\n" );
fprintf( pFile, "\"\n" ); fprintf( pFile, "\"\n" );
fprintf( pFile, " ];\n" ); fprintf( pFile, " ];\n" );
...@@ -701,6 +702,32 @@ char * Abc_NtkPrintSop( char * pSop ) ...@@ -701,6 +702,32 @@ char * Abc_NtkPrintSop( char * pSop )
return Buffer; return Buffer;
} }
/**Function*************************************************************
Synopsis [Computes the printable SOP form.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NtkCountLogicNodes( Vec_Ptr_t * vNodes )
{
Abc_Obj_t * pObj;
int i, Counter = 0;
Vec_PtrForEachEntry( vNodes, pObj, i )
{
if ( !Abc_ObjIsNode(pObj) )
continue;
if ( Abc_ObjFaninNum(pObj) == 0 && Abc_ObjFanoutNum(pObj) == 0 )
continue;
Counter ++;
}
return Counter;
}
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
/// END OF FILE /// /// END OF FILE ///
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
......
...@@ -67,7 +67,7 @@ extern bool Abc_NtkSeqCheck( Abc_Ntk_t * pNtk ); ...@@ -67,7 +67,7 @@ extern bool Abc_NtkSeqCheck( Abc_Ntk_t * pNtk );
/*=== seqShare.c =============================================================*/ /*=== seqShare.c =============================================================*/
extern void Seq_NtkShareFanouts( Abc_Ntk_t * pNtk ); extern void Seq_NtkShareFanouts( Abc_Ntk_t * pNtk );
extern void Seq_NtkShareLatches( Abc_Ntk_t * pNtkNew, Abc_Ntk_t * pNtk ); extern void Seq_NtkShareLatches( Abc_Ntk_t * pNtkNew, Abc_Ntk_t * pNtk );
extern void Seq_NtkShareLatchesFpga( Abc_Ntk_t * pNtkNew, Abc_Ntk_t * pNtk, Vec_Ptr_t * vMapAnds ); extern void Seq_NtkShareLatchesMapping( Abc_Ntk_t * pNtkNew, Abc_Ntk_t * pNtk, Vec_Ptr_t * vMapAnds, int fFpga );
extern void Seq_NtkShareLatchesClean( Abc_Ntk_t * pNtk ); extern void Seq_NtkShareLatchesClean( Abc_Ntk_t * pNtk );
/*=== seqUtil.c ==============================================================*/ /*=== seqUtil.c ==============================================================*/
extern char * Seq_ObjFaninGetInitPrintable( Abc_Obj_t * pObj, int Edge ); extern char * Seq_ObjFaninGetInitPrintable( Abc_Obj_t * pObj, int Edge );
...@@ -78,6 +78,7 @@ extern int Seq_NtkLatchNumShared( Abc_Ntk_t * pNtk ); ...@@ -78,6 +78,7 @@ extern int Seq_NtkLatchNumShared( Abc_Ntk_t * pNtk );
extern void Seq_NtkLatchGetInitNums( Abc_Ntk_t * pNtk, int * pInits ); extern void Seq_NtkLatchGetInitNums( Abc_Ntk_t * pNtk, int * pInits );
extern int Seq_NtkLatchGetEqualFaninNum( Abc_Ntk_t * pNtk ); extern int Seq_NtkLatchGetEqualFaninNum( Abc_Ntk_t * pNtk );
extern int Seq_NtkCountNodesAboveLimit( Abc_Ntk_t * pNtk, int Limit ); extern int Seq_NtkCountNodesAboveLimit( Abc_Ntk_t * pNtk, int Limit );
extern int Seq_MapComputeAreaFlows( Abc_Ntk_t * pNtk, int fVerbose );
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
/// END OF FILE /// /// END OF FILE ///
......
...@@ -815,14 +815,14 @@ Vec_Ptr_t * Abc_NtkUtilRetimingGetMoves( Abc_Ntk_t * pNtk, Vec_Int_t * vSteps, b ...@@ -815,14 +815,14 @@ Vec_Ptr_t * Abc_NtkUtilRetimingGetMoves( Abc_Ntk_t * pNtk, Vec_Int_t * vSteps, b
if ( !fChange ) if ( !fChange )
{ {
printf( "Warning: %d strange steps (a minor bug to be fixed later).\n", Vec_IntSize(vSteps) ); printf( "Warning: %d strange steps (a minor bug to be fixed later).\n", Vec_IntSize(vSteps) );
/* /*
Vec_IntForEachEntry( vSteps, Number, i ) Vec_IntForEachEntry( vSteps, Number, i )
{ {
RetStep = Seq_Int2RetStep( Number ); RetStep = Seq_Int2RetStep( Number );
printf( "%d(%d) ", RetStep.iNode, RetStep.nLatches ); printf( "%d(%d) ", RetStep.iNode, RetStep.nLatches );
} }
printf( "\n" ); printf( "\n" );
*/ */
break; break;
} }
} }
......
...@@ -82,6 +82,7 @@ Abc_Ntk_t * Seq_NtkFpgaMapRetime( Abc_Ntk_t * pNtk, int nMaxIters, int fVerbose ...@@ -82,6 +82,7 @@ Abc_Ntk_t * Seq_NtkFpgaMapRetime( Abc_Ntk_t * pNtk, int nMaxIters, int fVerbose
// check the compatibility of initial states computed // check the compatibility of initial states computed
if ( RetValue = Seq_NtkFpgaInitCompatible( pNtkNew, fVerbose ) ) if ( RetValue = Seq_NtkFpgaInitCompatible( pNtkNew, fVerbose ) )
printf( "The number of LUTs with incompatible edges = %d.\n", RetValue ); printf( "The number of LUTs with incompatible edges = %d.\n", RetValue );
// create the final mapped network // create the final mapped network
pNtkMap = Seq_NtkSeqFpgaMapped( pNtkNew ); pNtkMap = Seq_NtkSeqFpgaMapped( pNtkNew );
Abc_NtkDelete( pNtkNew ); Abc_NtkDelete( pNtkNew );
...@@ -142,8 +143,6 @@ Abc_Ntk_t * Seq_NtkFpgaDup( Abc_Ntk_t * pNtk ) ...@@ -142,8 +143,6 @@ Abc_Ntk_t * Seq_NtkFpgaDup( Abc_Ntk_t * pNtk )
// transfer the mapping info to the new manager // transfer the mapping info to the new manager
Vec_PtrForEachEntry( p->vMapAnds, pObj, i ) Vec_PtrForEachEntry( p->vMapAnds, pObj, i )
{ {
// convert the root node
Vec_PtrWriteEntry( p->vMapAnds, i, pObj->pCopy );
// get the leaves of the cut // get the leaves of the cut
vLeaves = Vec_VecEntry( p->vMapCuts, i ); vLeaves = Vec_VecEntry( p->vMapCuts, i );
// convert the leaf nodes // convert the leaf nodes
...@@ -151,13 +150,14 @@ Abc_Ntk_t * Seq_NtkFpgaDup( Abc_Ntk_t * pNtk ) ...@@ -151,13 +150,14 @@ Abc_Ntk_t * Seq_NtkFpgaDup( Abc_Ntk_t * pNtk )
{ {
SeqEdge = (unsigned)pLeaf; SeqEdge = (unsigned)pLeaf;
pLeaf = Abc_NtkObj( pNtk, SeqEdge >> 8 ); pLeaf = Abc_NtkObj( pNtk, SeqEdge >> 8 );
// Lag = (SeqEdge & 255);// + Seq_NodeGetLag(pObj) - Seq_NodeGetLag(pLeaf);
Lag = (SeqEdge & 255) + Seq_NodeGetLag(pObj) - Seq_NodeGetLag(pLeaf); Lag = (SeqEdge & 255) + Seq_NodeGetLag(pObj) - Seq_NodeGetLag(pLeaf);
assert( Lag >= 0 ); assert( Lag >= 0 );
// translate the old leaf into the leaf in the new network // translate the old leaf into the leaf in the new network
Vec_PtrWriteEntry( vLeaves, k, (void *)((pLeaf->pCopy->Id << 8) | Lag) ); Vec_PtrWriteEntry( vLeaves, k, (void *)((pLeaf->pCopy->Id << 8) | Lag) );
// printf( "%d -> %d\n", pLeaf->Id, pLeaf->pCopy->Id ); // printf( "%d -> %d\n", pLeaf->Id, pLeaf->pCopy->Id );
} }
// convert the root node
Vec_PtrWriteEntry( p->vMapAnds, i, pObj->pCopy );
} }
pNew = pNtkNew->pManFunc; pNew = pNtkNew->pManFunc;
pNew->nVarsMax = p->nVarsMax; pNew->nVarsMax = p->nVarsMax;
...@@ -290,8 +290,9 @@ Abc_Ntk_t * Seq_NtkSeqFpgaMapped( Abc_Ntk_t * pNtk ) ...@@ -290,8 +290,9 @@ Abc_Ntk_t * Seq_NtkSeqFpgaMapped( Abc_Ntk_t * pNtk )
// duplicate the nodes used in the mapping // duplicate the nodes used in the mapping
Vec_PtrForEachEntry( p->vMapAnds, pObj, i ) Vec_PtrForEachEntry( p->vMapAnds, pObj, i )
pObj->pCopy = Abc_NtkCreateNode( pNtkMap ); pObj->pCopy = Abc_NtkCreateNode( pNtkMap );
// create and share the latches // create and share the latches
Seq_NtkShareLatchesFpga( pNtkMap, pNtk, p->vMapAnds ); Seq_NtkShareLatchesMapping( pNtkMap, pNtk, p->vMapAnds, 1 );
// connect the nodes // connect the nodes
Vec_PtrForEachEntry( p->vMapAnds, pObj, i ) Vec_PtrForEachEntry( p->vMapAnds, pObj, i )
......
...@@ -73,6 +73,9 @@ p->timeCuts = clock() - clk; ...@@ -73,6 +73,9 @@ p->timeCuts = clock() - clk;
if ( fVerbose ) if ( fVerbose )
Cut_ManPrintStats( p->pCutMan ); Cut_ManPrintStats( p->pCutMan );
// compute area flows
// Seq_MapComputeAreaFlows( pNtk, fVerbose );
// compute the delays // compute the delays
clk = clock(); clk = clock();
Seq_AigRetimeDelayLags( pNtk, fVerbose ); Seq_AigRetimeDelayLags( pNtk, fVerbose );
...@@ -170,6 +173,7 @@ Cut_Cut_t * Seq_FpgaMappingSelectCut( Abc_Obj_t * pAnd ) ...@@ -170,6 +173,7 @@ Cut_Cut_t * Seq_FpgaMappingSelectCut( Abc_Obj_t * pAnd )
if ( Abc_NodeIsTravIdCurrent(pFanin) ) if ( Abc_NodeIsTravIdCurrent(pFanin) )
continue; continue;
CostCur += (float)(1.0 / Abc_ObjFanoutNum(pFanin)); CostCur += (float)(1.0 / Abc_ObjFanoutNum(pFanin));
// CostCur += Seq_NodeGetFlow( pFanin );
} }
if ( CostMin > CostCur ) if ( CostMin > CostCur )
{ {
......
...@@ -64,6 +64,7 @@ struct Abc_Seq_t_ ...@@ -64,6 +64,7 @@ struct Abc_Seq_t_
Cut_Man_t * pCutMan; // cut manager Cut_Man_t * pCutMan; // cut manager
Map_SuperLib_t * pSuperLib; // the current supergate library Map_SuperLib_t * pSuperLib; // the current supergate library
// sequential arrival time computation // sequential arrival time computation
Vec_Int_t * vAFlows; // the area flow of each cut
Vec_Int_t * vLValues; // the arrival times (L-Values of nodes) Vec_Int_t * vLValues; // the arrival times (L-Values of nodes)
Vec_Int_t * vLValuesN; // the arrival times (L-Values of nodes) Vec_Int_t * vLValuesN; // the arrival times (L-Values of nodes)
Vec_Str_t * vLags; // the lags of the mapped nodes Vec_Str_t * vLags; // the lags of the mapped nodes
...@@ -73,6 +74,7 @@ struct Abc_Seq_t_ ...@@ -73,6 +74,7 @@ struct Abc_Seq_t_
Vec_Ptr_t * vMapAnds; // nodes visible in the mapping Vec_Ptr_t * vMapAnds; // nodes visible in the mapping
Vec_Vec_t * vMapCuts; // best cuts for each node Vec_Vec_t * vMapCuts; // best cuts for each node
Vec_Vec_t * vMapDelays; // the delay of each fanin Vec_Vec_t * vMapDelays; // the delay of each fanin
Vec_Vec_t * vMapFanins; // the delay of each fanin
// runtime stats // runtime stats
int timeCuts; // runtime to compute the cuts int timeCuts; // runtime to compute the cuts
int timeDelay; // runtime to compute the L-values int timeDelay; // runtime to compute the L-values
...@@ -117,7 +119,8 @@ struct Seq_Match_t_ // 3 words ...@@ -117,7 +119,8 @@ struct Seq_Match_t_ // 3 words
unsigned fCompl : 1; // the polarity of the AND gate unsigned fCompl : 1; // the polarity of the AND gate
unsigned fCutInv : 1; // the polarity of the cut unsigned fCutInv : 1; // the polarity of the cut
unsigned PolUse : 2; // the polarity use of this node unsigned PolUse : 2; // the polarity use of this node
unsigned uPhase : 28; // the phase assignment at the boundary unsigned uPhase : 14; // the phase assignment at the boundary
unsigned uPhaseR : 14; // the real phase assignment at the boundary
}; };
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
...@@ -157,8 +160,11 @@ static inline float Seq_NodeGetLValueP( Abc_Obj_t * pNode ) ...@@ -157,8 +160,11 @@ static inline float Seq_NodeGetLValueP( Abc_Obj_t * pNode )
static inline float Seq_NodeGetLValueN( Abc_Obj_t * pNode ) { return Abc_Int2Float( Vec_IntEntry( Seq_NodeLValuesN(pNode), (pNode)->Id ) ); } static inline float Seq_NodeGetLValueN( Abc_Obj_t * pNode ) { return Abc_Int2Float( Vec_IntEntry( Seq_NodeLValuesN(pNode), (pNode)->Id ) ); }
static inline void Seq_NodeSetLValueP( Abc_Obj_t * pNode, float Value ) { Vec_IntWriteEntry( Seq_NodeLValues(pNode), (pNode)->Id, Abc_Float2Int(Value) ); } static inline void Seq_NodeSetLValueP( Abc_Obj_t * pNode, float Value ) { Vec_IntWriteEntry( Seq_NodeLValues(pNode), (pNode)->Id, Abc_Float2Int(Value) ); }
static inline void Seq_NodeSetLValueN( Abc_Obj_t * pNode, float Value ) { Vec_IntWriteEntry( Seq_NodeLValuesN(pNode), (pNode)->Id, Abc_Float2Int(Value) ); } static inline void Seq_NodeSetLValueN( Abc_Obj_t * pNode, float Value ) { Vec_IntWriteEntry( Seq_NodeLValuesN(pNode), (pNode)->Id, Abc_Float2Int(Value) ); }
static inline int Seq_NodeComputeLag( int LValue, int Fi ) { return (LValue + 1024*Fi)/Fi - 1024 - (int)(LValue % Fi == 0); }
static inline int Seq_NodeComputeLagFloat( float LValue, float Fi ) { return ((int)ceil(LValue/Fi)) - 1; } // reading area flows
static inline Vec_Int_t * Seq_NodeFlow( Abc_Obj_t * pNode ) { return ((Abc_Seq_t *)(pNode)->pNtk->pManFunc)->vAFlows; }
static inline float Seq_NodeGetFlow( Abc_Obj_t * pNode ) { return Abc_Int2Float( Vec_IntEntry( Seq_NodeFlow(pNode), (pNode)->Id ) ); }
static inline void Seq_NodeSetFlow( Abc_Obj_t * pNode, float Value ) { Vec_IntWriteEntry( Seq_NodeFlow(pNode), (pNode)->Id, Abc_Float2Int(Value) ); }
// reading the contents of the lat // reading the contents of the lat
static inline Abc_InitType_t Seq_LatInit( Seq_Lat_t * pLat ) { return ((unsigned)pLat->pPrev) & 3; } static inline Abc_InitType_t Seq_LatInit( Seq_Lat_t * pLat ) { return ((unsigned)pLat->pPrev) & 3; }
...@@ -178,6 +184,8 @@ static inline char Seq_NodeGetLag( Abc_Obj_t * pNode ) ...@@ -178,6 +184,8 @@ static inline char Seq_NodeGetLag( Abc_Obj_t * pNode )
static inline char Seq_NodeGetLagN( Abc_Obj_t * pNode ) { return Vec_StrEntry( Seq_NodeLagsN(pNode), (pNode)->Id ); } static inline char Seq_NodeGetLagN( Abc_Obj_t * pNode ) { return Vec_StrEntry( Seq_NodeLagsN(pNode), (pNode)->Id ); }
static inline void Seq_NodeSetLag( Abc_Obj_t * pNode, char Value ) { Vec_StrWriteEntry( Seq_NodeLags(pNode), (pNode)->Id, (Value) ); } static inline void Seq_NodeSetLag( Abc_Obj_t * pNode, char Value ) { Vec_StrWriteEntry( Seq_NodeLags(pNode), (pNode)->Id, (Value) ); }
static inline void Seq_NodeSetLagN( Abc_Obj_t * pNode, char Value ) { Vec_StrWriteEntry( Seq_NodeLagsN(pNode), (pNode)->Id, (Value) ); } static inline void Seq_NodeSetLagN( Abc_Obj_t * pNode, char Value ) { Vec_StrWriteEntry( Seq_NodeLagsN(pNode), (pNode)->Id, (Value) ); }
static inline int Seq_NodeComputeLag( int LValue, int Fi ) { return (LValue + 1024*Fi)/Fi - 1024 - (int)(LValue % Fi == 0); }
static inline int Seq_NodeComputeLagFloat( float LValue, float Fi ) { return ((int)ceil(LValue/Fi)) - 1; }
// phase usage // phase usage
static inline Vec_Str_t * Seq_NodeUses( Abc_Obj_t * pNode ) { return ((Abc_Seq_t *)(pNode)->pNtk->pManFunc)->vUses; } static inline Vec_Str_t * Seq_NodeUses( Abc_Obj_t * pNode ) { return ((Abc_Seq_t *)(pNode)->pNtk->pManFunc)->vUses; }
......
...@@ -58,6 +58,7 @@ Abc_Seq_t * Seq_Create( Abc_Ntk_t * pNtk ) ...@@ -58,6 +58,7 @@ Abc_Seq_t * Seq_Create( Abc_Ntk_t * pNtk )
p->vLValues = Vec_IntStart( p->nSize ); p->vLValues = Vec_IntStart( p->nSize );
p->vLags = Vec_StrStart( p->nSize ); p->vLags = Vec_StrStart( p->nSize );
p->vLValuesN = Vec_IntStart( p->nSize ); p->vLValuesN = Vec_IntStart( p->nSize );
p->vAFlows = Vec_IntStart( p->nSize );
p->vLagsN = Vec_StrStart( p->nSize ); p->vLagsN = Vec_StrStart( p->nSize );
p->vUses = Vec_StrStart( p->nSize ); p->vUses = Vec_StrStart( p->nSize );
return p; return p;
...@@ -84,6 +85,7 @@ void Seq_Resize( Abc_Seq_t * p, int nMaxId ) ...@@ -84,6 +85,7 @@ void Seq_Resize( Abc_Seq_t * p, int nMaxId )
Vec_IntFill( p->vLValues, p->nSize, 0 ); Vec_IntFill( p->vLValues, p->nSize, 0 );
Vec_StrFill( p->vLags, p->nSize, 0 ); Vec_StrFill( p->vLags, p->nSize, 0 );
Vec_IntFill( p->vLValuesN, p->nSize, 0 ); Vec_IntFill( p->vLValuesN, p->nSize, 0 );
Vec_IntFill( p->vAFlows, p->nSize, 0 );
Vec_StrFill( p->vLagsN, p->nSize, 0 ); Vec_StrFill( p->vLagsN, p->nSize, 0 );
Vec_StrFill( p->vUses, p->nSize, 0 ); Vec_StrFill( p->vUses, p->nSize, 0 );
} }
...@@ -102,21 +104,24 @@ void Seq_Resize( Abc_Seq_t * p, int nMaxId ) ...@@ -102,21 +104,24 @@ void Seq_Resize( Abc_Seq_t * p, int nMaxId )
***********************************************************************/ ***********************************************************************/
void Seq_Delete( Abc_Seq_t * p ) void Seq_Delete( Abc_Seq_t * p )
{ {
if ( p->fStandCells ) if ( p->fStandCells && p->vMapAnds )
{ {
void * pVoid; int i; void * pVoid; int i;
Vec_PtrForEachEntry( p->vMapAnds, pVoid, i ) Vec_PtrForEachEntry( p->vMapAnds, pVoid, i )
free( pVoid ); free( pVoid );
} }
if ( p->vMapAnds ) Vec_PtrFree( p->vMapAnds ); // the nodes used in the mapping if ( p->vMapDelays ) Vec_VecFree( p->vMapDelays ); // the nodes used in the mapping
if ( p->vMapCuts ) Vec_VecFree( p->vMapCuts ); // the cuts used in the mapping if ( p->vMapFanins ) Vec_VecFree( p->vMapFanins ); // the cuts used in the mapping
if ( p->vLValues ) Vec_IntFree( p->vLValues ); // the arrival times (L-Values of nodes) if ( p->vMapAnds ) Vec_PtrFree( p->vMapAnds ); // the nodes used in the mapping
if ( p->vLags ) Vec_StrFree( p->vLags ); // the lags of the mapped nodes if ( p->vMapCuts ) Vec_VecFree( p->vMapCuts ); // the cuts used in the mapping
if ( p->vLValuesN ) Vec_IntFree( p->vLValuesN ); // the arrival times (L-Values of nodes) if ( p->vLValues ) Vec_IntFree( p->vLValues ); // the arrival times (L-Values of nodes)
if ( p->vLagsN ) Vec_StrFree( p->vLagsN ); // the lags of the mapped nodes if ( p->vLags ) Vec_StrFree( p->vLags ); // the lags of the mapped nodes
if ( p->vUses ) Vec_StrFree( p->vUses ); // the uses of phases if ( p->vLValuesN ) Vec_IntFree( p->vLValuesN ); // the arrival times (L-Values of nodes)
if ( p->vInits ) Vec_PtrFree( p->vInits ); // the initial values of the latches if ( p->vAFlows ) Vec_IntFree( p->vAFlows ); // the arrival times (L-Values of nodes)
if ( p->vNums ) Vec_IntFree( p->vNums ); // the numbers of latches if ( p->vLagsN ) Vec_StrFree( p->vLagsN ); // the lags of the mapped nodes
if ( p->vUses ) Vec_StrFree( p->vUses ); // the uses of phases
if ( p->vInits ) Vec_PtrFree( p->vInits ); // the initial values of the latches
if ( p->vNums ) Vec_IntFree( p->vNums ); // the numbers of latches
Extra_MmFixedStop( p->pMmInits, 0 ); Extra_MmFixedStop( p->pMmInits, 0 );
free( p ); free( p );
} }
......
...@@ -75,11 +75,18 @@ p->timeCuts = clock() - clk; ...@@ -75,11 +75,18 @@ p->timeCuts = clock() - clk;
// compute canonical forms of the truth tables of the cuts // compute canonical forms of the truth tables of the cuts
Seq_MapCanonicizeTruthTables( pNtk ); Seq_MapCanonicizeTruthTables( pNtk );
// compute area flows
// Seq_MapComputeAreaFlows( pNtk, fVerbose );
// compute the delays // compute the delays
clk = clock(); clk = clock();
FiBest = Seq_MapRetimeDelayLagsInternal( pNtk, fVerbose ); FiBest = Seq_MapRetimeDelayLagsInternal( pNtk, fVerbose );
p->timeDelay = clock() - clk; p->timeDelay = clock() - clk;
// clean the marks
Abc_NtkForEachObj( pNtk, pObj, i )
assert( !pObj->fMarkA && !pObj->fMarkB );
// collect the nodes and cuts used in the mapping // collect the nodes and cuts used in the mapping
p->vMapAnds = Vec_PtrAlloc( 1000 ); p->vMapAnds = Vec_PtrAlloc( 1000 );
p->vMapCuts = Vec_VecAlloc( 1000 ); p->vMapCuts = Vec_VecAlloc( 1000 );
...@@ -133,7 +140,7 @@ float Seq_MapRetimeDelayLagsInternal( Abc_Ntk_t * pNtk, int fVerbose ) ...@@ -133,7 +140,7 @@ float Seq_MapRetimeDelayLagsInternal( Abc_Ntk_t * pNtk, int fVerbose )
} }
// get the upper bound on the clock period // get the upper bound on the clock period
FiMax = Delta * (2 + Seq_NtkLevelMax(pNtk)); FiMax = Delta * (5 + Seq_NtkLevelMax(pNtk));
Delta /= 2; Delta /= 2;
// make sure this clock period is feasible // make sure this clock period is feasible
...@@ -155,11 +162,17 @@ float Seq_MapRetimeDelayLagsInternal( Abc_Ntk_t * pNtk, int fVerbose ) ...@@ -155,11 +162,17 @@ float Seq_MapRetimeDelayLagsInternal( Abc_Ntk_t * pNtk, int fVerbose )
Seq_NodeSetLag( pNode, NodeLag ); Seq_NodeSetLag( pNode, NodeLag );
NodeLag = Seq_NodeComputeLagFloat( Seq_NodeGetLValueN(pNode), FiBest ); NodeLag = Seq_NodeComputeLagFloat( Seq_NodeGetLValueN(pNode), FiBest );
Seq_NodeSetLagN( pNode, NodeLag ); Seq_NodeSetLagN( pNode, NodeLag );
//printf( "%6d=(%d,%d) ", pNode->Id, Seq_NodeGetLag(pNode), Seq_NodeGetLagN(pNode) );
// if ( Seq_NodeGetLag(pNode) != Seq_NodeGetLagN(pNode) )
// {
//printf( "%6d=(%d,%d) ", pNode->Id, Seq_NodeGetLag(pNode), Seq_NodeGetLagN(pNode) );
// }
} }
//printf( "\n\n" );
// print the result // print the result
if ( fVerbose ) // if ( fVerbose )
printf( "The best clock period is %6.2f.\n", FiBest ); printf( "The best clock period after mapping/retiming is %6.2f.\n", FiBest );
return FiBest; return FiBest;
} }
...@@ -209,7 +222,7 @@ int Seq_MapRetimeForPeriod( Abc_Ntk_t * pNtk, float Fi, int fVerbose ) ...@@ -209,7 +222,7 @@ int Seq_MapRetimeForPeriod( Abc_Ntk_t * pNtk, float Fi, int fVerbose )
// set l-values of all nodes to be minus infinity // set l-values of all nodes to be minus infinity
Vec_IntFill( p->vLValues, p->nSize, Abc_Float2Int( (float)-ABC_INFINITY ) ); Vec_IntFill( p->vLValues, p->nSize, Abc_Float2Int( (float)-ABC_INFINITY ) );
Vec_IntFill( p->vLValuesN, p->nSize, Abc_Float2Int( (float)-ABC_INFINITY ) ); Vec_IntFill( p->vLValuesN, p->nSize, Abc_Float2Int( (float)-ABC_INFINITY ) );
Vec_StrFill( p->vUses, p->nSize, 0 ); Vec_StrFill( p->vUses, p->nSize, 0 );
// set l-values of constants and PIs // set l-values of constants and PIs
pObj = Abc_NtkObj( pNtk, 0 ); pObj = Abc_NtkObj( pNtk, 0 );
...@@ -243,6 +256,7 @@ int Seq_MapRetimeForPeriod( Abc_Ntk_t * pNtk, float Fi, int fVerbose ) ...@@ -243,6 +256,7 @@ int Seq_MapRetimeForPeriod( Abc_Ntk_t * pNtk, float Fi, int fVerbose )
break; break;
if ( fChange == 0 ) if ( fChange == 0 )
break; break;
//printf( "\n\n" );
} }
if ( c == p->nMaxIters ) if ( c == p->nMaxIters )
{ {
...@@ -265,7 +279,6 @@ int Seq_MapRetimeForPeriod( Abc_Ntk_t * pNtk, float Fi, int fVerbose ) ...@@ -265,7 +279,6 @@ int Seq_MapRetimeForPeriod( Abc_Ntk_t * pNtk, float Fi, int fVerbose )
/**Function************************************************************* /**Function*************************************************************
Synopsis [Computes the l-value of the cut.] Synopsis [Computes the l-value of the cut.]
...@@ -325,6 +338,15 @@ float Seq_MapNodeComputeCut( Abc_Obj_t * pObj, Cut_Cut_t * pCut, int fCompl, fl ...@@ -325,6 +338,15 @@ float Seq_MapNodeComputeCut( Abc_Obj_t * pObj, Cut_Cut_t * pCut, int fCompl, fl
assert( pCut->nLeaves < 6 ); assert( pCut->nLeaves < 6 );
// get the canonical truth table of this cut // get the canonical truth table of this cut
uCanon[0] = uCanon[1] = (fCompl? pCut->uCanon0 : pCut->uCanon1); uCanon[0] = uCanon[1] = (fCompl? pCut->uCanon0 : pCut->uCanon1);
if ( uCanon[0] == 0 || ~uCanon[0] == 0 )
{
if ( pMatchBest )
{
memset( pMatchBest, 0, sizeof(Seq_Match_t) );
pMatchBest->pCut = pCut;
}
return (float)0.0;
}
// match the given phase of the cut // match the given phase of the cut
pSuperList = Map_SuperTableLookupC( p->pSuperLib, uCanon ); pSuperList = Map_SuperTableLookupC( p->pSuperLib, uCanon );
// compute the arrival times of each supergate // compute the arrival times of each supergate
...@@ -340,7 +362,7 @@ float Seq_MapNodeComputeCut( Abc_Obj_t * pObj, Cut_Cut_t * pCut, int fCompl, fl ...@@ -340,7 +362,7 @@ float Seq_MapNodeComputeCut( Abc_Obj_t * pObj, Cut_Cut_t * pCut, int fCompl, fl
pMatchCur->uPhase = (fCompl? pCut->Num0 : pCut->Num1) ^ pSuper->uPhases[i]; pMatchCur->uPhase = (fCompl? pCut->Num0 : pCut->Num1) ^ pSuper->uPhases[i];
// find the arrival time of this match // find the arrival time of this match
lValueCur = Seq_MapSuperGetArrival( pObj, Fi, pMatchCur, lValueBest ); lValueCur = Seq_MapSuperGetArrival( pObj, Fi, pMatchCur, lValueBest );
if ( lValueBest > lValueCur ) if ( lValueBest > lValueCur )//&& lValueCur > -ABC_INFINITY/2 )
{ {
lValueBest = lValueCur; lValueBest = lValueCur;
if ( pMatchBest ) if ( pMatchBest )
...@@ -348,6 +370,7 @@ float Seq_MapNodeComputeCut( Abc_Obj_t * pObj, Cut_Cut_t * pCut, int fCompl, fl ...@@ -348,6 +370,7 @@ float Seq_MapNodeComputeCut( Abc_Obj_t * pObj, Cut_Cut_t * pCut, int fCompl, fl
} }
} }
} }
// assert( lValueBest < ABC_INFINITY/2 );
return lValueBest; return lValueBest;
} }
...@@ -366,22 +389,23 @@ float Seq_MapNodeComputePhase( Abc_Obj_t * pObj, int fCompl, float Fi, Seq_Match ...@@ -366,22 +389,23 @@ float Seq_MapNodeComputePhase( Abc_Obj_t * pObj, int fCompl, float Fi, Seq_Match
{ {
Seq_Match_t Match, * pMatchCur = &Match; Seq_Match_t Match, * pMatchCur = &Match;
Cut_Cut_t * pList, * pCut; Cut_Cut_t * pList, * pCut;
float lValueNew, lValueCut; float lValueBest, lValueCut;
// get the list of cuts // get the list of cuts
pList = Abc_NodeReadCuts( Seq_NodeCutMan(pObj), pObj ); pList = Abc_NodeReadCuts( Seq_NodeCutMan(pObj), pObj );
// get the arrival time of the best non-trivial cut // get the arrival time of the best non-trivial cut
lValueNew = ABC_INFINITY; lValueBest = ABC_INFINITY;
for ( pCut = pList->pNext; pCut; pCut = pCut->pNext ) for ( pCut = pList->pNext; pCut; pCut = pCut->pNext )
{ {
lValueCut = Seq_MapNodeComputeCut( pObj, pCut, fCompl, Fi, pMatchBest? pMatchCur : NULL ); lValueCut = Seq_MapNodeComputeCut( pObj, pCut, fCompl, Fi, pMatchBest? pMatchCur : NULL );
if ( lValueNew > lValueCut ) if ( lValueBest > lValueCut )
{ {
lValueNew = lValueCut; lValueBest = lValueCut;
if ( pMatchBest ) if ( pMatchBest )
*pMatchBest = *pMatchCur; *pMatchBest = *pMatchCur;
} }
} }
return lValueNew; // assert( lValueBest < ABC_INFINITY/2 );
return lValueBest;
} }
/**Function************************************************************* /**Function*************************************************************
...@@ -434,11 +458,14 @@ int Seq_MapNodeUpdateLValue( Abc_Obj_t * pObj, float Fi, float DelayInv ) ...@@ -434,11 +458,14 @@ int Seq_MapNodeUpdateLValue( Abc_Obj_t * pObj, float Fi, float DelayInv )
// compare // compare
if ( lValue0 <= lValueOld0 + p->fEpsilon && lValue1 <= lValueOld1 + p->fEpsilon ) if ( lValue0 <= lValueOld0 + p->fEpsilon && lValue1 <= lValueOld1 + p->fEpsilon )
return SEQ_UPDATE_NO; return SEQ_UPDATE_NO;
assert( lValue0 < ABC_INFINITY/2 );
assert( lValue1 < ABC_INFINITY/2 );
// update the values // update the values
if ( lValue0 > lValueOld0 + p->fEpsilon ) if ( lValue0 > lValueOld0 + p->fEpsilon )
Seq_NodeSetLValueN( pObj, lValue0 ); Seq_NodeSetLValueN( pObj, lValue0 );
if ( lValue1 > lValueOld1 + p->fEpsilon ) if ( lValue1 > lValueOld1 + p->fEpsilon )
Seq_NodeSetLValueP( pObj, lValue1 ); Seq_NodeSetLValueP( pObj, lValue1 );
//printf( "%6d=(%4.2f,%4.2f) ", pObj->Id, Seq_NodeGetLValueP(pObj), Seq_NodeGetLValueN(pObj) );
return SEQ_UPDATE_YES; return SEQ_UPDATE_YES;
} }
...@@ -460,6 +487,7 @@ float Seq_MapCollectNode_rec( Abc_Obj_t * pAnd, float FiBest, Vec_Ptr_t * vMappi ...@@ -460,6 +487,7 @@ float Seq_MapCollectNode_rec( Abc_Obj_t * pAnd, float FiBest, Vec_Ptr_t * vMappi
Seq_Match_t * pMatch; Seq_Match_t * pMatch;
Abc_Obj_t * pFanin; Abc_Obj_t * pFanin;
int k, fCompl, Use; int k, fCompl, Use;
float AreaInv = Mio_LibraryReadAreaInv(Abc_FrameReadLibGen());
float Area; float Area;
// get the polarity of the node // get the polarity of the node
...@@ -467,42 +495,44 @@ float Seq_MapCollectNode_rec( Abc_Obj_t * pAnd, float FiBest, Vec_Ptr_t * vMappi ...@@ -467,42 +495,44 @@ float Seq_MapCollectNode_rec( Abc_Obj_t * pAnd, float FiBest, Vec_Ptr_t * vMappi
pAnd = Abc_ObjRegular(pAnd); pAnd = Abc_ObjRegular(pAnd);
// skip visited nodes // skip visited nodes
if ( fCompl ) if ( !fCompl )
{ { // need the positive polarity
if ( pAnd->fMarkB ) if ( pAnd->fMarkA )
return 0.0; return 0.0;
pAnd->fMarkB = 1; pAnd->fMarkA = 1;
} }
else else
{ { // need the negative polarity
if ( pAnd->fMarkA ) if ( pAnd->fMarkB )
return 0.0; return 0.0;
pAnd->fMarkA = 1; pAnd->fMarkB = 1;
} }
// skip if this is a non-PI node // skip if this is a PI or a constant
if ( !Abc_NodeIsAigAnd(pAnd) ) if ( !Abc_NodeIsAigAnd(pAnd) )
{ {
if ( Abc_ObjIsPi(pAnd) && fCompl ) if ( Abc_ObjIsPi(pAnd) && fCompl )
return Mio_LibraryReadAreaInv(Abc_FrameReadLibGen()); return AreaInv;
return 0.0; return 0.0;
} }
// check the uses of this node // check the uses of this node
Use = Seq_NodeGetUses( pAnd ); Use = Seq_NodeGetUses( pAnd );
if ( fCompl && Use == 2 ) // the neg phase is required; the pos phase is used if ( !fCompl && Use == 1 ) // the pos phase is required; only the neg phase is used
{ {
Area = Seq_MapCollectNode_rec( pAnd, FiBest, vMapping, vMapCuts ); Area = Seq_MapCollectNode_rec( Abc_ObjNot(pAnd), FiBest, vMapping, vMapCuts );
return Area + Mio_LibraryReadAreaInv(Abc_FrameReadLibGen()); return Area + AreaInv;
} }
if ( !fCompl && Use == 1 ) // the pos phase is required; the neg phase is used if ( fCompl && Use == 2 ) // the neg phase is required; only the pos phase is used
{ {
Area = Seq_MapCollectNode_rec( Abc_ObjNot(pAnd), FiBest, vMapping, vMapCuts ); Area = Seq_MapCollectNode_rec( pAnd, FiBest, vMapping, vMapCuts );
return Area + Mio_LibraryReadAreaInv(Abc_FrameReadLibGen()); return Area + AreaInv;
} }
// both phases are used; the needed one can be selected
// get the best match // get the best match
pMatch = ALLOC( Seq_Match_t, 1 ); pMatch = ALLOC( Seq_Match_t, 1 );
memset( pMatch, 1, sizeof(Seq_Match_t) );
Seq_MapNodeComputePhase( pAnd, fCompl, FiBest, pMatch ); Seq_MapNodeComputePhase( pAnd, fCompl, FiBest, pMatch );
pMatch->pAnd = pAnd; pMatch->pAnd = pAnd;
pMatch->fCompl = fCompl; pMatch->fCompl = fCompl;
...@@ -510,7 +540,7 @@ float Seq_MapCollectNode_rec( Abc_Obj_t * pAnd, float FiBest, Vec_Ptr_t * vMappi ...@@ -510,7 +540,7 @@ float Seq_MapCollectNode_rec( Abc_Obj_t * pAnd, float FiBest, Vec_Ptr_t * vMappi
pMatch->PolUse = Use; pMatch->PolUse = Use;
// call for the fanin cuts // call for the fanin cuts
Area = pMatch->pSuper->Area; Area = pMatch->pSuper? pMatch->pSuper->Area : (float)0.0;
for ( k = 0; k < (int)pMatch->pCut->nLeaves; k++ ) for ( k = 0; k < (int)pMatch->pCut->nLeaves; k++ )
{ {
pFanin = Abc_NtkObj( pAnd->pNtk, pMatch->pCut->pLeaves[k] >> 8 ); pFanin = Abc_NtkObj( pAnd->pNtk, pMatch->pCut->pLeaves[k] >> 8 );
...@@ -524,6 +554,9 @@ float Seq_MapCollectNode_rec( Abc_Obj_t * pAnd, float FiBest, Vec_Ptr_t * vMappi ...@@ -524,6 +554,9 @@ float Seq_MapCollectNode_rec( Abc_Obj_t * pAnd, float FiBest, Vec_Ptr_t * vMappi
for ( k = 0; k < (int)pMatch->pCut->nLeaves; k++ ) for ( k = 0; k < (int)pMatch->pCut->nLeaves; k++ )
Vec_VecPush( vMapCuts, Vec_PtrSize(vMapping)-1, (void *)pMatch->pCut->pLeaves[k] ); Vec_VecPush( vMapCuts, Vec_PtrSize(vMapping)-1, (void *)pMatch->pCut->pLeaves[k] );
// the cut will become unavailable when the cuts are deallocated
pMatch->pCut = NULL;
return Area; return Area;
} }
...@@ -551,6 +584,7 @@ void Seq_MapCanonicizeTruthTables( Abc_Ntk_t * pNtk ) ...@@ -551,6 +584,7 @@ void Seq_MapCanonicizeTruthTables( Abc_Ntk_t * pNtk )
} }
} }
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
/// END OF FILE /// /// END OF FILE ///
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
...@@ -31,6 +31,9 @@ static int Seq_NtkMappingForPeriod( Abc_Ntk_t * pNtk, float Fi, int fVerbose ) ...@@ -31,6 +31,9 @@ static int Seq_NtkMappingForPeriod( Abc_Ntk_t * pNtk, float Fi, int fVerbose )
static int Seq_NtkNodeUpdateLValue( Abc_Obj_t * pObj, float Fi, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vDelays ); static int Seq_NtkNodeUpdateLValue( Abc_Obj_t * pObj, float Fi, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vDelays );
static void Seq_NodeRetimeSetLag_rec( Abc_Obj_t * pNode, char Lag ); static void Seq_NodeRetimeSetLag_rec( Abc_Obj_t * pNode, char Lag );
static void Seq_NodePrintInfo( Abc_Obj_t * pNode );
static void Seq_NodePrintInfoPlus( Abc_Obj_t * pNode );
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS /// /// FUNCTION DEFINITIONS ///
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
...@@ -60,6 +63,7 @@ void Seq_NtkRetimeDelayLags( Abc_Ntk_t * pNtkOld, Abc_Ntk_t * pNtk, int fVerbose ...@@ -60,6 +63,7 @@ void Seq_NtkRetimeDelayLags( Abc_Ntk_t * pNtkOld, Abc_Ntk_t * pNtk, int fVerbose
assert( p->vMapAnds ); assert( p->vMapAnds );
assert( p->vMapCuts ); assert( p->vMapCuts );
assert( p->vMapDelays ); assert( p->vMapDelays );
assert( p->vMapFanins );
// guess the upper bound on the clock period // guess the upper bound on the clock period
if ( Abc_NtkHasMapping(pNtkOld) ) if ( Abc_NtkHasMapping(pNtkOld) )
...@@ -107,6 +111,11 @@ void Seq_NtkRetimeDelayLags( Abc_Ntk_t * pNtkOld, Abc_Ntk_t * pNtk, int fVerbose ...@@ -107,6 +111,11 @@ void Seq_NtkRetimeDelayLags( Abc_Ntk_t * pNtkOld, Abc_Ntk_t * pNtk, int fVerbose
Vec_StrFill( p->vLags, p->nSize, 0 ); Vec_StrFill( p->vLags, p->nSize, 0 );
Vec_PtrForEachEntry( p->vMapAnds, pNode, i ) Vec_PtrForEachEntry( p->vMapAnds, pNode, i )
{ {
if ( Vec_PtrSize( Vec_VecEntry(p->vMapCuts, i) ) == 0 )
{
Seq_NodeSetLag( pNode, 0 );
continue;
}
NodeLag = Seq_NodeComputeLagFloat( Seq_NodeGetLValueP(pNode), FiBest ); NodeLag = Seq_NodeComputeLagFloat( Seq_NodeGetLValueP(pNode), FiBest );
Seq_NodeRetimeSetLag_rec( pNode, NodeLag ); Seq_NodeRetimeSetLag_rec( pNode, NodeLag );
} }
...@@ -117,6 +126,8 @@ void Seq_NtkRetimeDelayLags( Abc_Ntk_t * pNtkOld, Abc_Ntk_t * pNtk, int fVerbose ...@@ -117,6 +126,8 @@ void Seq_NtkRetimeDelayLags( Abc_Ntk_t * pNtkOld, Abc_Ntk_t * pNtk, int fVerbose
// print the result // print the result
if ( fVerbose ) if ( fVerbose )
printf( "The best clock period is %6.2f.\n", FiBest ); printf( "The best clock period is %6.2f.\n", FiBest );
// Seq_NodePrintInfo( Abc_NtkObj(pNtk, 847) );
} }
/**Function************************************************************* /**Function*************************************************************
...@@ -181,6 +192,11 @@ int Seq_NtkMappingForPeriod( Abc_Ntk_t * pNtk, float Fi, int fVerbose ) ...@@ -181,6 +192,11 @@ int Seq_NtkMappingForPeriod( Abc_Ntk_t * pNtk, float Fi, int fVerbose )
Counter++; Counter++;
vLeaves = Vec_VecEntry( p->vMapCuts, i ); vLeaves = Vec_VecEntry( p->vMapCuts, i );
vDelays = Vec_VecEntry( p->vMapDelays, i ); vDelays = Vec_VecEntry( p->vMapDelays, i );
if ( Vec_PtrSize(vLeaves) == 0 )
{
Seq_NodeSetLValueP( pObj, 0.0 );
continue;
}
RetValue = Seq_NtkNodeUpdateLValue( pObj, Fi, vLeaves, vDelays ); RetValue = Seq_NtkNodeUpdateLValue( pObj, Fi, vLeaves, vDelays );
if ( RetValue == SEQ_UPDATE_YES ) if ( RetValue == SEQ_UPDATE_YES )
fChange = 1; fChange = 1;
...@@ -293,6 +309,72 @@ void Seq_NodeRetimeSetLag_rec( Abc_Obj_t * pNode, char Lag ) ...@@ -293,6 +309,72 @@ void Seq_NodeRetimeSetLag_rec( Abc_Obj_t * pNode, char Lag )
} }
/**Function*************************************************************
Synopsis [Add sequential edges.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Seq_NodePrintInfo( Abc_Obj_t * pNode )
{
Abc_Seq_t * p = pNode->pNtk->pManFunc;
Abc_Obj_t * pFanin, * pObj, * pLeaf;
Vec_Ptr_t * vLeaves;
unsigned SeqEdge;
int i, Number;
// print the node
printf( " Node = %6d. LValue = %7.2f. Lag = %2d.\n",
pNode->Id, Seq_NodeGetLValueP(pNode), Seq_NodeGetLag(pNode) );
// find the number
Vec_PtrForEachEntry( p->vMapAnds, pObj, Number )
if ( pObj == pNode )
break;
// get the leaves
vLeaves = Vec_VecEntry( p->vMapCuts, Number );
// print the leaves
Vec_PtrForEachEntry( vLeaves, pLeaf, i )
{
SeqEdge = (unsigned)pLeaf;
pFanin = Abc_NtkObj( pNode->pNtk, SeqEdge >> 8 );
// print the leaf
printf( " Fanin%d(%d) = %6d. LValue = %7.2f. Lag = %2d.\n", i, SeqEdge & 255,
pFanin->Id, Seq_NodeGetLValueP(pFanin), Seq_NodeGetLag(pFanin) );
}
}
/**Function*************************************************************
Synopsis [Add sequential edges.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Seq_NodePrintInfoPlus( Abc_Obj_t * pNode )
{
Abc_Obj_t * pFanout;
int i;
printf( "CENTRAL NODE:\n" );
Seq_NodePrintInfo( pNode );
Abc_ObjForEachFanout( pNode, pFanout, i )
{
printf( "FANOUT%d:\n", i );
Seq_NodePrintInfo( pFanout );
}
}
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
/// END OF FILE /// /// END OF FILE ///
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
......
...@@ -275,15 +275,17 @@ Abc_Obj_t * Seq_NtkShareLatches_rec( Abc_Ntk_t * pNtk, Abc_Obj_t * pObj, Seq_Lat ...@@ -275,15 +275,17 @@ Abc_Obj_t * Seq_NtkShareLatches_rec( Abc_Ntk_t * pNtk, Abc_Obj_t * pObj, Seq_Lat
***********************************************************************/ ***********************************************************************/
void Seq_NtkShareLatches( Abc_Ntk_t * pNtkNew, Abc_Ntk_t * pNtk ) void Seq_NtkShareLatches( Abc_Ntk_t * pNtkNew, Abc_Ntk_t * pNtk )
{ {
Abc_Obj_t * pObj; Abc_Obj_t * pObj, * pFanin;
stmm_table * tLatchMap; stmm_table * tLatchMap;
int i; int i;
assert( Abc_NtkIsSeq( pNtk ) ); assert( Abc_NtkIsSeq( pNtk ) );
tLatchMap = stmm_init_table( stmm_ptrcmp, stmm_ptrhash ); tLatchMap = stmm_init_table( stmm_ptrcmp, stmm_ptrhash );
Abc_AigForEachAnd( pNtk, pObj, i ) Abc_AigForEachAnd( pNtk, pObj, i )
{ {
Seq_NtkShareLatches_rec( pNtkNew, Abc_ObjFanin0(pObj)->pCopy, Seq_NodeGetRing(pObj,0), Seq_NodeCountLats(pObj,0), tLatchMap ); pFanin = Abc_ObjFanin0(pObj);
Seq_NtkShareLatches_rec( pNtkNew, Abc_ObjFanin1(pObj)->pCopy, Seq_NodeGetRing(pObj,1), Seq_NodeCountLats(pObj,1), tLatchMap ); Seq_NtkShareLatches_rec( pNtkNew, pFanin->pCopy, Seq_NodeGetRing(pObj,0), Seq_NodeCountLats(pObj,0), tLatchMap );
pFanin = Abc_ObjFanin1(pObj);
Seq_NtkShareLatches_rec( pNtkNew, pFanin->pCopy, Seq_NodeGetRing(pObj,1), Seq_NodeCountLats(pObj,1), tLatchMap );
} }
Abc_NtkForEachPo( pNtk, pObj, i ) Abc_NtkForEachPo( pNtk, pObj, i )
Seq_NtkShareLatches_rec( pNtkNew, Abc_ObjFanin0(pObj)->pCopy, Seq_NodeGetRing(pObj,0), Seq_NodeCountLats(pObj,0), tLatchMap ); Seq_NtkShareLatches_rec( pNtkNew, Abc_ObjFanin0(pObj)->pCopy, Seq_NodeGetRing(pObj,0), Seq_NodeCountLats(pObj,0), tLatchMap );
...@@ -303,22 +305,36 @@ void Seq_NtkShareLatches( Abc_Ntk_t * pNtkNew, Abc_Ntk_t * pNtk ) ...@@ -303,22 +305,36 @@ void Seq_NtkShareLatches( Abc_Ntk_t * pNtkNew, Abc_Ntk_t * pNtk )
SeeAlso [] SeeAlso []
***********************************************************************/ ***********************************************************************/
void Seq_NtkShareLatchesFpga( Abc_Ntk_t * pNtkNew, Abc_Ntk_t * pNtk, Vec_Ptr_t * vMapAnds ) void Seq_NtkShareLatchesMapping( Abc_Ntk_t * pNtkNew, Abc_Ntk_t * pNtk, Vec_Ptr_t * vMapAnds, int fFpga )
{ {
Seq_Match_t * pMatch;
Abc_Obj_t * pObj, * pFanout; Abc_Obj_t * pObj, * pFanout;
stmm_table * tLatchMap; stmm_table * tLatchMap;
int i, k, nOldNodes; Vec_Ptr_t * vNodes;
int i, k;
assert( Abc_NtkIsSeq( pNtk ) ); assert( Abc_NtkIsSeq( pNtk ) );
// start the table // start the table
tLatchMap = stmm_init_table( stmm_ptrcmp, stmm_ptrhash ); tLatchMap = stmm_init_table( stmm_ptrcmp, stmm_ptrhash );
// remember the old nodes
nOldNodes = Vec_PtrSize( vMapAnds ); // create the array of all nodes with sharable fanouts
// add constant and PIs vNodes = Vec_PtrAlloc( 100 );
Vec_PtrPush( vMapAnds, Abc_NtkConst1(pNtk) ); Vec_PtrPush( vNodes, Abc_NtkConst1(pNtk) );
Abc_NtkForEachPi( pNtk, pObj, i ) Abc_NtkForEachPi( pNtk, pObj, i )
Vec_PtrPush( vMapAnds, pObj ); Vec_PtrPush( vNodes, pObj );
if ( fFpga )
{
Vec_PtrForEachEntry( vMapAnds, pObj, i )
Vec_PtrPush( vNodes, pObj );
}
else
{
Vec_PtrForEachEntry( vMapAnds, pMatch, i )
Vec_PtrPush( vNodes, pMatch->pAnd );
}
// process nodes used in the mapping // process nodes used in the mapping
Vec_PtrForEachEntry( vMapAnds, pObj, i ) Vec_PtrForEachEntry( vNodes, pObj, i )
{ {
// make sure the label is clean // make sure the label is clean
Abc_ObjForEachFanout( pObj, pFanout, k ) Abc_ObjForEachFanout( pObj, pFanout, k )
...@@ -339,7 +355,7 @@ void Seq_NtkShareLatchesFpga( Abc_Ntk_t * pNtkNew, Abc_Ntk_t * pNtk, Vec_Ptr_t * ...@@ -339,7 +355,7 @@ void Seq_NtkShareLatchesFpga( Abc_Ntk_t * pNtkNew, Abc_Ntk_t * pNtk, Vec_Ptr_t *
} }
stmm_free_table( tLatchMap ); stmm_free_table( tLatchMap );
// return to the old array // return to the old array
Vec_PtrShrink( vMapAnds, nOldNodes ); Vec_PtrFree( vNodes );
} }
/**Function************************************************************* /**Function*************************************************************
......
...@@ -417,6 +417,50 @@ int Seq_NtkCountNodesAboveLimit( Abc_Ntk_t * pNtk, int Limit ) ...@@ -417,6 +417,50 @@ int Seq_NtkCountNodesAboveLimit( Abc_Ntk_t * pNtk, int Limit )
return Counter; return Counter;
} }
/**Function*************************************************************
Synopsis [Computes area flows.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Seq_MapComputeAreaFlows( Abc_Ntk_t * pNtk, int fVerbose )
{
Abc_Seq_t * p = pNtk->pManFunc;
Abc_Obj_t * pObj;
float AFlow;
int i, c;
assert( Abc_NtkIsSeq(pNtk) );
Vec_IntFill( p->vAFlows, p->nSize, Abc_Float2Int( (float)0.0 ) );
// update all values iteratively
for ( c = 0; c < 7; c++ )
{
Abc_AigForEachAnd( pNtk, pObj, i )
{
AFlow = (float)1.0 + Seq_NodeGetFlow( Abc_ObjFanin0(pObj) ) + Seq_NodeGetFlow( Abc_ObjFanin1(pObj) );
AFlow /= Abc_ObjFanoutNum(pObj);
pObj->pNext = (void *)Abc_Float2Int( AFlow );
}
Abc_AigForEachAnd( pNtk, pObj, i )
{
AFlow = Abc_Int2Float( (int)pObj->pNext );
pObj->pNext = NULL;
Seq_NodeSetFlow( pObj, AFlow );
// printf( "%5d : %6.1f\n", pObj->Id, Seq_NodeGetFlow(pObj) );
}
// printf( "\n" );
}
return 1;
}
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
/// END OF FILE /// /// END OF FILE ///
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment