From 4812c90424dfc40d26725244723887a2d16ddfd9 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 1 Oct 2007 08:01:00 -0700 Subject: Version abc71001 --- src/opt/cut/abcCut.c | 492 +++++++++++++++++++++++ src/opt/cut/cut.h | 165 ++++++++ src/opt/cut/cutApi.c | 197 ++++++++++ src/opt/cut/cutCut.c | 359 +++++++++++++++++ src/opt/cut/cutExpand.c | 184 +++++++++ src/opt/cut/cutInt.h | 157 ++++++++ src/opt/cut/cutList.h | 207 ++++++++++ src/opt/cut/cutMan.c | 326 ++++++++++++++++ src/opt/cut/cutMerge.c | 657 +++++++++++++++++++++++++++++++ src/opt/cut/cutNode.c | 992 +++++++++++++++++++++++++++++++++++++++++++++++ src/opt/cut/cutOracle.c | 428 ++++++++++++++++++++ src/opt/cut/cutPre22.c | 988 ++++++++++++++++++++++++++++++++++++++++++++++ src/opt/cut/cutSeq.c | 227 +++++++++++ src/opt/cut/cutTruth.c | 226 +++++++++++ src/opt/cut/module.make | 9 + src/opt/dec/dec.h | 719 ++++++++++++++++++++++++++++++++++ src/opt/dec/decAbc.c | 305 +++++++++++++++ src/opt/dec/decFactor.c | 392 +++++++++++++++++++ src/opt/dec/decMan.c | 83 ++++ src/opt/dec/decPrint.c | 284 ++++++++++++++ src/opt/dec/decUtil.c | 134 +++++++ src/opt/dec/module.make | 5 + src/opt/fxu/fxu.c | 254 ++++++++++++ src/opt/fxu/fxu.h | 93 +++++ src/opt/fxu/fxuCreate.c | 431 ++++++++++++++++++++ src/opt/fxu/fxuHeapD.c | 445 +++++++++++++++++++++ src/opt/fxu/fxuHeapS.c | 444 +++++++++++++++++++++ src/opt/fxu/fxuInt.h | 539 +++++++++++++++++++++++++ src/opt/fxu/fxuList.c | 522 +++++++++++++++++++++++++ src/opt/fxu/fxuMatrix.c | 374 ++++++++++++++++++ src/opt/fxu/fxuPair.c | 555 ++++++++++++++++++++++++++ src/opt/fxu/fxuPrint.c | 195 ++++++++++ src/opt/fxu/fxuReduce.c | 204 ++++++++++ src/opt/fxu/fxuSelect.c | 603 ++++++++++++++++++++++++++++ src/opt/fxu/fxuSingle.c | 284 ++++++++++++++ src/opt/fxu/fxuUpdate.c | 806 ++++++++++++++++++++++++++++++++++++++ src/opt/fxu/module.make | 12 + src/opt/lpk/lpk.h | 84 ++++ src/opt/lpk/lpkAbcDec.c | 290 ++++++++++++++ src/opt/lpk/lpkAbcDsd.c | 603 ++++++++++++++++++++++++++++ src/opt/lpk/lpkAbcMux.c | 235 +++++++++++ src/opt/lpk/lpkAbcUtil.c | 244 ++++++++++++ src/opt/lpk/lpkCore.c | 659 +++++++++++++++++++++++++++++++ src/opt/lpk/lpkCut.c | 683 ++++++++++++++++++++++++++++++++ src/opt/lpk/lpkInt.h | 246 ++++++++++++ src/opt/lpk/lpkMan.c | 122 ++++++ src/opt/lpk/lpkMap.c | 205 ++++++++++ src/opt/lpk/lpkMulti.c | 495 +++++++++++++++++++++++ src/opt/lpk/lpkMux.c | 247 ++++++++++++ src/opt/lpk/lpkSets.c | 440 +++++++++++++++++++++ src/opt/lpk/lpk_.c | 48 +++ src/opt/lpk/module.make | 11 + src/opt/res/module.make | 7 + src/opt/res/res.h | 75 ++++ src/opt/res/resCore.c | 415 ++++++++++++++++++++ src/opt/res/resDivs.c | 285 ++++++++++++++ src/opt/res/resFilter.c | 434 +++++++++++++++++++++ src/opt/res/resInt.h | 137 +++++++ src/opt/res/resSat.c | 407 +++++++++++++++++++ src/opt/res/resSim.c | 790 +++++++++++++++++++++++++++++++++++++ src/opt/res/resSim_old.c | 521 +++++++++++++++++++++++++ src/opt/res/resStrash.c | 117 ++++++ src/opt/res/resWin.c | 485 +++++++++++++++++++++++ src/opt/res/res_.c | 50 +++ src/opt/ret/module.make | 8 + src/opt/ret/retArea.c | 540 ++++++++++++++++++++++++++ src/opt/ret/retCore.c | 132 +++++++ src/opt/ret/retDelay.c | 305 +++++++++++++++ src/opt/ret/retFlow.c | 783 +++++++++++++++++++++++++++++++++++++ src/opt/ret/retIncrem.c | 464 ++++++++++++++++++++++ src/opt/ret/retInit.c | 349 +++++++++++++++++ src/opt/ret/retInt.h | 80 ++++ src/opt/ret/retLvalue.c | 395 +++++++++++++++++++ src/opt/ret/ret_.c | 48 +++ src/opt/rwr/module.make | 7 + src/opt/rwr/rwr.h | 169 ++++++++ src/opt/rwr/rwrDec.c | 150 +++++++ src/opt/rwr/rwrEva.c | 588 ++++++++++++++++++++++++++++ src/opt/rwr/rwrExp.c | 333 ++++++++++++++++ src/opt/rwr/rwrLib.c | 362 +++++++++++++++++ src/opt/rwr/rwrMan.c | 318 +++++++++++++++ src/opt/rwr/rwrPrint.c | 266 +++++++++++++ src/opt/rwr/rwrTemp.c | 121 ++++++ src/opt/rwr/rwrUtil.c | 659 +++++++++++++++++++++++++++++++ src/opt/sim/module.make | 10 + src/opt/sim/sim.h | 233 +++++++++++ src/opt/sim/simMan.c | 288 ++++++++++++++ src/opt/sim/simSat.c | 48 +++ src/opt/sim/simSeq.c | 171 ++++++++ src/opt/sim/simSupp.c | 597 ++++++++++++++++++++++++++++ src/opt/sim/simSwitch.c | 107 +++++ src/opt/sim/simSym.c | 142 +++++++ src/opt/sim/simSymSat.c | 199 ++++++++++ src/opt/sim/simSymSim.c | 173 +++++++++ src/opt/sim/simSymStr.c | 488 +++++++++++++++++++++++ src/opt/sim/simUtils.c | 711 +++++++++++++++++++++++++++++++++ 96 files changed, 30876 insertions(+) create mode 100644 src/opt/cut/abcCut.c create mode 100644 src/opt/cut/cut.h create mode 100644 src/opt/cut/cutApi.c create mode 100644 src/opt/cut/cutCut.c create mode 100644 src/opt/cut/cutExpand.c create mode 100644 src/opt/cut/cutInt.h create mode 100644 src/opt/cut/cutList.h create mode 100644 src/opt/cut/cutMan.c create mode 100644 src/opt/cut/cutMerge.c create mode 100644 src/opt/cut/cutNode.c create mode 100644 src/opt/cut/cutOracle.c create mode 100644 src/opt/cut/cutPre22.c create mode 100644 src/opt/cut/cutSeq.c create mode 100644 src/opt/cut/cutTruth.c create mode 100644 src/opt/cut/module.make create mode 100644 src/opt/dec/dec.h create mode 100644 src/opt/dec/decAbc.c create mode 100644 src/opt/dec/decFactor.c create mode 100644 src/opt/dec/decMan.c create mode 100644 src/opt/dec/decPrint.c create mode 100644 src/opt/dec/decUtil.c create mode 100644 src/opt/dec/module.make create mode 100644 src/opt/fxu/fxu.c create mode 100644 src/opt/fxu/fxu.h create mode 100644 src/opt/fxu/fxuCreate.c create mode 100644 src/opt/fxu/fxuHeapD.c create mode 100644 src/opt/fxu/fxuHeapS.c create mode 100644 src/opt/fxu/fxuInt.h create mode 100644 src/opt/fxu/fxuList.c create mode 100644 src/opt/fxu/fxuMatrix.c create mode 100644 src/opt/fxu/fxuPair.c create mode 100644 src/opt/fxu/fxuPrint.c create mode 100644 src/opt/fxu/fxuReduce.c create mode 100644 src/opt/fxu/fxuSelect.c create mode 100644 src/opt/fxu/fxuSingle.c create mode 100644 src/opt/fxu/fxuUpdate.c create mode 100644 src/opt/fxu/module.make create mode 100644 src/opt/lpk/lpk.h create mode 100644 src/opt/lpk/lpkAbcDec.c create mode 100644 src/opt/lpk/lpkAbcDsd.c create mode 100644 src/opt/lpk/lpkAbcMux.c create mode 100644 src/opt/lpk/lpkAbcUtil.c create mode 100644 src/opt/lpk/lpkCore.c create mode 100644 src/opt/lpk/lpkCut.c create mode 100644 src/opt/lpk/lpkInt.h create mode 100644 src/opt/lpk/lpkMan.c create mode 100644 src/opt/lpk/lpkMap.c create mode 100644 src/opt/lpk/lpkMulti.c create mode 100644 src/opt/lpk/lpkMux.c create mode 100644 src/opt/lpk/lpkSets.c create mode 100644 src/opt/lpk/lpk_.c create mode 100644 src/opt/lpk/module.make create mode 100644 src/opt/res/module.make create mode 100644 src/opt/res/res.h create mode 100644 src/opt/res/resCore.c create mode 100644 src/opt/res/resDivs.c create mode 100644 src/opt/res/resFilter.c create mode 100644 src/opt/res/resInt.h create mode 100644 src/opt/res/resSat.c create mode 100644 src/opt/res/resSim.c create mode 100644 src/opt/res/resSim_old.c create mode 100644 src/opt/res/resStrash.c create mode 100644 src/opt/res/resWin.c create mode 100644 src/opt/res/res_.c create mode 100644 src/opt/ret/module.make create mode 100644 src/opt/ret/retArea.c create mode 100644 src/opt/ret/retCore.c create mode 100644 src/opt/ret/retDelay.c create mode 100644 src/opt/ret/retFlow.c create mode 100644 src/opt/ret/retIncrem.c create mode 100644 src/opt/ret/retInit.c create mode 100644 src/opt/ret/retInt.h create mode 100644 src/opt/ret/retLvalue.c create mode 100644 src/opt/ret/ret_.c create mode 100644 src/opt/rwr/module.make create mode 100644 src/opt/rwr/rwr.h create mode 100644 src/opt/rwr/rwrDec.c create mode 100644 src/opt/rwr/rwrEva.c create mode 100644 src/opt/rwr/rwrExp.c create mode 100644 src/opt/rwr/rwrLib.c create mode 100644 src/opt/rwr/rwrMan.c create mode 100644 src/opt/rwr/rwrPrint.c create mode 100644 src/opt/rwr/rwrTemp.c create mode 100644 src/opt/rwr/rwrUtil.c create mode 100644 src/opt/sim/module.make create mode 100644 src/opt/sim/sim.h create mode 100644 src/opt/sim/simMan.c create mode 100644 src/opt/sim/simSat.c create mode 100644 src/opt/sim/simSeq.c create mode 100644 src/opt/sim/simSupp.c create mode 100644 src/opt/sim/simSwitch.c create mode 100644 src/opt/sim/simSym.c create mode 100644 src/opt/sim/simSymSat.c create mode 100644 src/opt/sim/simSymSim.c create mode 100644 src/opt/sim/simSymStr.c create mode 100644 src/opt/sim/simUtils.c (limited to 'src/opt') diff --git a/src/opt/cut/abcCut.c b/src/opt/cut/abcCut.c new file mode 100644 index 00000000..9bbd5790 --- /dev/null +++ b/src/opt/cut/abcCut.c @@ -0,0 +1,492 @@ +/**CFile**************************************************************** + + FileName [abcCut.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Network and node package.] + + Synopsis [Interface to cut computation.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: abcCut.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "cut.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static void Abc_NtkPrintCuts( void * p, Abc_Ntk_t * pNtk, int fSeq ); +static void Abc_NtkPrintCuts_( void * p, Abc_Ntk_t * pNtk, int fSeq ); + + +extern int nTotal, nGood, nEqual; + +// temporary +//Vec_Int_t * Abc_NtkGetNodeAttributes( Abc_Ntk_t * pNtk ) { return NULL; } +Vec_Int_t * Abc_NtkGetNodeAttributes( Abc_Ntk_t * pNtk ) +{ + Vec_Int_t * vAttrs = Vec_IntStart( Abc_NtkObjNumMax(pNtk) + 1 ); + int i; + Abc_Obj_t * pObj; + +// Abc_NtkForEachCi( pNtk, pObj, i ) +// Vec_IntWriteEntry( vAttrs, pObj->Id, 1 ); + + Abc_NtkForEachObj( pNtk, pObj, i ) + { +// if ( Abc_ObjIsNode(pObj) && (rand() % 4 == 0) ) + if ( Abc_ObjIsNode(pObj) && Abc_ObjFanoutNum(pObj) > 1 && !Abc_NodeIsMuxControlType(pObj) && (rand() % 3 == 0) ) + Vec_IntWriteEntry( vAttrs, pObj->Id, 1 ); + } + return vAttrs; +} + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Computes the cuts for the network.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_Man_t * Abc_NtkCuts( Abc_Ntk_t * pNtk, Cut_Params_t * pParams ) +{ + ProgressBar * pProgress; + Cut_Man_t * p; + Abc_Obj_t * pObj, * pNode; + Vec_Ptr_t * vNodes; + Vec_Int_t * vChoices; + int i; + int clk = clock(); + + extern void Abc_NtkBalanceAttach( Abc_Ntk_t * pNtk ); + extern void Abc_NtkBalanceDetach( Abc_Ntk_t * pNtk ); + + nTotal = nGood = nEqual = 0; + + assert( Abc_NtkIsStrash(pNtk) ); + // start the manager + pParams->nIdsMax = Abc_NtkObjNumMax( pNtk ); + p = Cut_ManStart( pParams ); + // compute node attributes if local or global cuts are requested + if ( pParams->fGlobal || pParams->fLocal ) + { + extern Vec_Int_t * Abc_NtkGetNodeAttributes( Abc_Ntk_t * pNtk ); + Cut_ManSetNodeAttrs( p, Abc_NtkGetNodeAttributes(pNtk) ); + } + // prepare for cut dropping + if ( pParams->fDrop ) + Cut_ManSetFanoutCounts( p, Abc_NtkFanoutCounts(pNtk) ); + // set cuts for PIs + Abc_NtkForEachCi( pNtk, pObj, i ) + if ( Abc_ObjFanoutNum(pObj) > 0 ) + Cut_NodeSetTriv( p, pObj->Id ); + // compute cuts for internal nodes + vNodes = Abc_AigDfs( pNtk, 0, 1 ); // collects POs + vChoices = Vec_IntAlloc( 100 ); + pProgress = Extra_ProgressBarStart( stdout, Vec_PtrSize(vNodes) ); + Vec_PtrForEachEntry( vNodes, pObj, i ) + { + // when we reached a CO, it is time to deallocate the cuts + if ( Abc_ObjIsCo(pObj) ) + { + if ( pParams->fDrop ) + Cut_NodeTryDroppingCuts( p, Abc_ObjFaninId0(pObj) ); + continue; + } + // skip constant node, it has no cuts +// if ( Abc_NodeIsConst(pObj) ) +// continue; + Extra_ProgressBarUpdate( pProgress, i, NULL ); + // compute the cuts to the internal node + Abc_NodeGetCuts( p, pObj, pParams->fDag, pParams->fTree ); + // consider dropping the fanins cuts + if ( pParams->fDrop ) + { + Cut_NodeTryDroppingCuts( p, Abc_ObjFaninId0(pObj) ); + Cut_NodeTryDroppingCuts( p, Abc_ObjFaninId1(pObj) ); + } + // add cuts due to choices + if ( Abc_AigNodeIsChoice(pObj) ) + { + Vec_IntClear( vChoices ); + for ( pNode = pObj; pNode; pNode = pNode->pData ) + Vec_IntPush( vChoices, pNode->Id ); + Cut_NodeUnionCuts( p, vChoices ); + } + } + Extra_ProgressBarStop( pProgress ); + Vec_PtrFree( vNodes ); + Vec_IntFree( vChoices ); +PRT( "Total", clock() - clk ); +//Abc_NtkPrintCuts( p, pNtk, 0 ); +// Cut_ManPrintStatsToFile( p, pNtk->pSpec, clock() - clk ); + + // temporary printout of stats + if ( nTotal ) + printf( "Total cuts = %d. Good cuts = %d. Ratio = %5.2f\n", nTotal, nGood, ((double)nGood)/nTotal ); + return p; +} + +/**Function************************************************************* + + Synopsis [Cut computation using the oracle.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NtkCutsOracle( Abc_Ntk_t * pNtk, Cut_Oracle_t * p ) +{ + Abc_Obj_t * pObj; + Vec_Ptr_t * vNodes; + int i, clk = clock(); + int fDrop = Cut_OracleReadDrop(p); + + assert( Abc_NtkIsStrash(pNtk) ); + + // prepare cut droppping + if ( fDrop ) + Cut_OracleSetFanoutCounts( p, Abc_NtkFanoutCounts(pNtk) ); + + // set cuts for PIs + Abc_NtkForEachCi( pNtk, pObj, i ) + if ( Abc_ObjFanoutNum(pObj) > 0 ) + Cut_OracleNodeSetTriv( p, pObj->Id ); + + // compute cuts for internal nodes + vNodes = Abc_AigDfs( pNtk, 0, 1 ); // collects POs + Vec_PtrForEachEntry( vNodes, pObj, i ) + { + // when we reached a CO, it is time to deallocate the cuts + if ( Abc_ObjIsCo(pObj) ) + { + if ( fDrop ) + Cut_OracleTryDroppingCuts( p, Abc_ObjFaninId0(pObj) ); + continue; + } + // skip constant node, it has no cuts +// if ( Abc_NodeIsConst(pObj) ) +// continue; + // compute the cuts to the internal node + Cut_OracleComputeCuts( p, pObj->Id, Abc_ObjFaninId0(pObj), Abc_ObjFaninId1(pObj), + Abc_ObjFaninC0(pObj), Abc_ObjFaninC1(pObj) ); + // consider dropping the fanins cuts + if ( fDrop ) + { + Cut_OracleTryDroppingCuts( p, Abc_ObjFaninId0(pObj) ); + Cut_OracleTryDroppingCuts( p, Abc_ObjFaninId1(pObj) ); + } + } + Vec_PtrFree( vNodes ); +//PRT( "Total", clock() - clk ); +//Abc_NtkPrintCuts_( p, pNtk, 0 ); +} + + +/**Function************************************************************* + + Synopsis [Computes the cuts for the network.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_Man_t * Abc_NtkSeqCuts( Abc_Ntk_t * pNtk, Cut_Params_t * pParams ) +{ +/* + Cut_Man_t * p; + Abc_Obj_t * pObj, * pNode; + int i, nIters, fStatus; + Vec_Int_t * vChoices; + int clk = clock(); + + assert( Abc_NtkIsSeq(pNtk) ); + assert( pParams->fSeq ); +// assert( Abc_NtkIsDfsOrdered(pNtk) ); + + // start the manager + pParams->nIdsMax = Abc_NtkObjNumMax( pNtk ); + pParams->nCutSet = Abc_NtkCutSetNodeNum( pNtk ); + p = Cut_ManStart( pParams ); + + // set cuts for the constant node and the PIs + pObj = Abc_AigConst1(pNtk); + if ( Abc_ObjFanoutNum(pObj) > 0 ) + Cut_NodeSetTriv( p, pObj->Id ); + Abc_NtkForEachPi( pNtk, pObj, i ) + { +//printf( "Setting trivial cut %d.\n", pObj->Id ); + Cut_NodeSetTriv( p, pObj->Id ); + } + // label the cutset nodes and set their number in the array + // assign the elementary cuts to the cutset nodes + Abc_SeqForEachCutsetNode( pNtk, pObj, i ) + { + assert( pObj->fMarkC == 0 ); + pObj->fMarkC = 1; + pObj->pCopy = (Abc_Obj_t *)i; + Cut_NodeSetTriv( p, pObj->Id ); +//printf( "Setting trivial cut %d.\n", pObj->Id ); + } + + // process the nodes + vChoices = Vec_IntAlloc( 100 ); + for ( nIters = 0; nIters < 10; nIters++ ) + { +//printf( "ITERATION %d:\n", nIters ); + // compute the cuts for the internal nodes + Abc_AigForEachAnd( pNtk, pObj, i ) + { + Abc_NodeGetCutsSeq( p, pObj, nIters==0 ); + // add cuts due to choices + if ( Abc_AigNodeIsChoice(pObj) ) + { + Vec_IntClear( vChoices ); + for ( pNode = pObj; pNode; pNode = pNode->pData ) + Vec_IntPush( vChoices, pNode->Id ); + Cut_NodeUnionCutsSeq( p, vChoices, (pObj->fMarkC ? (int)pObj->pCopy : -1), nIters==0 ); + } + } + // merge the new cuts with the old cuts + Abc_NtkForEachPi( pNtk, pObj, i ) + Cut_NodeNewMergeWithOld( p, pObj->Id ); + Abc_AigForEachAnd( pNtk, pObj, i ) + Cut_NodeNewMergeWithOld( p, pObj->Id ); + // for the cutset, transfer temp cuts to new cuts + fStatus = 0; + Abc_SeqForEachCutsetNode( pNtk, pObj, i ) + fStatus |= Cut_NodeTempTransferToNew( p, pObj->Id, i ); + if ( fStatus == 0 ) + break; + } + Vec_IntFree( vChoices ); + + // if the status is not finished, transfer new to old for the cutset + Abc_SeqForEachCutsetNode( pNtk, pObj, i ) + Cut_NodeNewMergeWithOld( p, pObj->Id ); + + // transfer the old cuts to the new positions + Abc_NtkForEachObj( pNtk, pObj, i ) + Cut_NodeOldTransferToNew( p, pObj->Id ); + + // unlabel the cutset nodes + Abc_SeqForEachCutsetNode( pNtk, pObj, i ) + pObj->fMarkC = 0; +if ( pParams->fVerbose ) +{ +PRT( "Total", clock() - clk ); +printf( "Converged after %d iterations.\n", nIters ); +} +//Abc_NtkPrintCuts( p, pNtk, 1 ); + return p; +*/ +} + +/**Function************************************************************* + + Synopsis [Computes the cuts for the network.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void * Abc_NodeGetCutsRecursive( void * p, Abc_Obj_t * pObj, int fDag, int fTree ) +{ + void * pList; + if ( pList = Abc_NodeReadCuts( p, pObj ) ) + return pList; + Abc_NodeGetCutsRecursive( p, Abc_ObjFanin0(pObj), fDag, fTree ); + Abc_NodeGetCutsRecursive( p, Abc_ObjFanin1(pObj), fDag, fTree ); + return Abc_NodeGetCuts( p, pObj, fDag, fTree ); +} + +/**Function************************************************************* + + Synopsis [Computes the cuts for the network.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void * Abc_NodeGetCuts( void * p, Abc_Obj_t * pObj, int fDag, int fTree ) +{ + Abc_Obj_t * pFanin; + int fDagNode, fTriv, TreeCode = 0; +// assert( Abc_NtkIsStrash(pObj->pNtk) ); + assert( Abc_ObjFaninNum(pObj) == 2 ); + + + // check if the node is a DAG node + fDagNode = (Abc_ObjFanoutNum(pObj) > 1 && !Abc_NodeIsMuxControlType(pObj)); + // increment the counter of DAG nodes + if ( fDagNode ) Cut_ManIncrementDagNodes( p ); + // add the trivial cut if the node is a DAG node, or if we compute all cuts + fTriv = fDagNode || !fDag; + // check if fanins are DAG nodes + if ( fTree ) + { + pFanin = Abc_ObjFanin0(pObj); + TreeCode |= (Abc_ObjFanoutNum(pFanin) > 1 && !Abc_NodeIsMuxControlType(pFanin)); + pFanin = Abc_ObjFanin1(pObj); + TreeCode |= ((Abc_ObjFanoutNum(pFanin) > 1 && !Abc_NodeIsMuxControlType(pFanin)) << 1); + } + + + // changes due to the global/local cut computation + { + Cut_Params_t * pParams = Cut_ManReadParams(p); + if ( pParams->fLocal ) + { + Vec_Int_t * vNodeAttrs = Cut_ManReadNodeAttrs(p); + fDagNode = Vec_IntEntry( vNodeAttrs, pObj->Id ); + if ( fDagNode ) Cut_ManIncrementDagNodes( p ); +// fTriv = fDagNode || !pParams->fGlobal; + fTriv = !Vec_IntEntry( vNodeAttrs, pObj->Id ); + TreeCode = 0; + pFanin = Abc_ObjFanin0(pObj); + TreeCode |= Vec_IntEntry( vNodeAttrs, pFanin->Id ); + pFanin = Abc_ObjFanin1(pObj); + TreeCode |= (Vec_IntEntry( vNodeAttrs, pFanin->Id ) << 1); + } + } + return Cut_NodeComputeCuts( p, pObj->Id, Abc_ObjFaninId0(pObj), Abc_ObjFaninId1(pObj), + Abc_ObjFaninC0(pObj), Abc_ObjFaninC1(pObj), fTriv, TreeCode ); +} + +/**Function************************************************************* + + Synopsis [Computes the cuts for the network.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NodeGetCutsSeq( void * p, Abc_Obj_t * pObj, int fTriv ) +{ + int CutSetNum; + assert( Abc_NtkIsSeq(pObj->pNtk) ); + assert( Abc_ObjFaninNum(pObj) == 2 ); + fTriv = pObj->fMarkC ? 0 : fTriv; + CutSetNum = pObj->fMarkC ? (int)pObj->pCopy : -1; + Cut_NodeComputeCutsSeq( p, pObj->Id, Abc_ObjFaninId0(pObj), Abc_ObjFaninId1(pObj), + Abc_ObjFaninC0(pObj), Abc_ObjFaninC1(pObj), Seq_ObjFaninL0(pObj), Seq_ObjFaninL1(pObj), fTriv, CutSetNum ); +} + +/**Function************************************************************* + + Synopsis [Computes the cuts for the network.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void * Abc_NodeReadCuts( void * p, Abc_Obj_t * pObj ) +{ + return Cut_NodeReadCutsNew( p, pObj->Id ); +} + +/**Function************************************************************* + + Synopsis [Computes the cuts for the network.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NodeFreeCuts( void * p, Abc_Obj_t * pObj ) +{ + Cut_NodeFreeCuts( p, pObj->Id ); +} + +/**Function************************************************************* + + Synopsis [Computes the cuts for the network.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NtkPrintCuts( void * p, Abc_Ntk_t * pNtk, int fSeq ) +{ + Cut_Man_t * pMan = p; + Cut_Cut_t * pList; + Abc_Obj_t * pObj; + int i; + printf( "Cuts of the network:\n" ); + Abc_NtkForEachObj( pNtk, pObj, i ) + { + pList = Abc_NodeReadCuts( p, pObj ); + printf( "Node %s:\n", Abc_ObjName(pObj) ); + Cut_CutPrintList( pList, fSeq ); + } +} + +/**Function************************************************************* + + Synopsis [Computes the cuts for the network.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NtkPrintCuts_( void * p, Abc_Ntk_t * pNtk, int fSeq ) +{ + Cut_Man_t * pMan = p; + Cut_Cut_t * pList; + Abc_Obj_t * pObj; + pObj = Abc_NtkObj( pNtk, 2 * Abc_NtkObjNum(pNtk) / 3 ); + pList = Abc_NodeReadCuts( p, pObj ); + printf( "Node %s:\n", Abc_ObjName(pObj) ); + Cut_CutPrintList( pList, fSeq ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/cut/cut.h b/src/opt/cut/cut.h new file mode 100644 index 00000000..dee05dfc --- /dev/null +++ b/src/opt/cut/cut.h @@ -0,0 +1,165 @@ +/**CFile**************************************************************** + + FileName [cut.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [K-feasible cut computation package.] + + Synopsis [External declarations.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: .h,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef __CUT_H__ +#define __CUT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +#define CUT_SIZE_MIN 3 // the min K of the K-feasible cut computation +#define CUT_SIZE_MAX 12 // the max K of the K-feasible cut computation + +#define CUT_SHIFT 8 // the number of bits for storing latch number in the cut leaves +#define CUT_MASK 0xFF // the mask to get the stored latch number + +//////////////////////////////////////////////////////////////////////// +/// BASIC TYPES /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Cut_ManStruct_t_ Cut_Man_t; +typedef struct Cut_OracleStruct_t_ Cut_Oracle_t; +typedef struct Cut_CutStruct_t_ Cut_Cut_t; +typedef struct Cut_ParamsStruct_t_ Cut_Params_t; + +struct Cut_ParamsStruct_t_ +{ + int nVarsMax; // the max cut size ("k" of the k-feasible cuts) + int nKeepMax; // the max number of cuts kept at a node + int nIdsMax; // the max number of IDs of cut objects + int nBitShift; // the number of bits used for the latch counter of an edge + int nCutSet; // the number of nodes in the cut set + int fTruth; // compute truth tables + int fFilter; // filter dominated cuts + int fSeq; // compute sequential cuts + int fDrop; // drop cuts on the fly + int fDag; // compute only DAG cuts + int fTree; // compute only tree cuts + int fGlobal; // compute only global cuts + int fLocal; // compute only local cuts + int fRecord; // record the cut computation flow + int fFancy; // perform fancy computations + int fMap; // computes delay of FPGA mapping with cuts + int fVerbose; // the verbosiness flag +}; + +struct Cut_CutStruct_t_ +{ + unsigned Num0 : 11; // temporary number + unsigned Num1 : 11; // temporary number + unsigned fSimul : 1; // the value of cut's output at 000.. pattern + unsigned fCompl : 1; // the cut is complemented + unsigned nVarsMax : 4; // the max number of vars [4-6] + unsigned nLeaves : 4; // the number of leaves [4-6] + unsigned uSign; // the signature + unsigned uCanon0; // the canonical form + unsigned uCanon1; // the canonical form + Cut_Cut_t * pNext; // the next cut in the list + int pLeaves[0]; // the array of leaves +}; + +static inline int Cut_CutReadLeaveNum( Cut_Cut_t * p ) { return p->nLeaves; } +static inline int * Cut_CutReadLeaves( Cut_Cut_t * p ) { return p->pLeaves; } +static inline unsigned * Cut_CutReadTruth( Cut_Cut_t * p ) { return (unsigned *)(p->pLeaves + p->nVarsMax); } +static inline void Cut_CutWriteTruth( Cut_Cut_t * p, unsigned * puTruth ) { + int i; + for ( i = (p->nVarsMax <= 5) ? 0 : ((1 << (p->nVarsMax - 5)) - 1); i >= 0; i-- ) + p->pLeaves[p->nVarsMax + i] = (int)puTruth[i]; +} + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +/*=== cutApi.c ==========================================================*/ +extern Cut_Cut_t * Cut_NodeReadCutsNew( Cut_Man_t * p, int Node ); +extern Cut_Cut_t * Cut_NodeReadCutsOld( Cut_Man_t * p, int Node ); +extern Cut_Cut_t * Cut_NodeReadCutsTemp( Cut_Man_t * p, int Node ); +extern void Cut_NodeWriteCutsNew( Cut_Man_t * p, int Node, Cut_Cut_t * pList ); +extern void Cut_NodeWriteCutsOld( Cut_Man_t * p, int Node, Cut_Cut_t * pList ); +extern void Cut_NodeWriteCutsTemp( Cut_Man_t * p, int Node, Cut_Cut_t * pList ); +extern void Cut_NodeSetTriv( Cut_Man_t * p, int Node ); +extern void Cut_NodeTryDroppingCuts( Cut_Man_t * p, int Node ); +extern void Cut_NodeFreeCuts( Cut_Man_t * p, int Node ); +/*=== cutCut.c ==========================================================*/ +extern void Cut_CutPrint( Cut_Cut_t * pCut, int fSeq ); +extern void Cut_CutPrintList( Cut_Cut_t * pList, int fSeq ); +extern int Cut_CutCountList( Cut_Cut_t * pList ); +/*=== cutMan.c ==========================================================*/ +extern Cut_Man_t * Cut_ManStart( Cut_Params_t * pParams ); +extern void Cut_ManStop( Cut_Man_t * p ); +extern void Cut_ManPrintStats( Cut_Man_t * p ); +extern void Cut_ManPrintStatsToFile( Cut_Man_t * p, char * pFileName, int TimeTotal ); +extern void Cut_ManSetFanoutCounts( Cut_Man_t * p, Vec_Int_t * vFanCounts ); +extern void Cut_ManSetNodeAttrs( Cut_Man_t * p, Vec_Int_t * vFanCounts ); +extern int Cut_ManReadVarsMax( Cut_Man_t * p ); +extern Cut_Params_t * Cut_ManReadParams( Cut_Man_t * p ); +extern Vec_Int_t * Cut_ManReadNodeAttrs( Cut_Man_t * p ); +extern void Cut_ManIncrementDagNodes( Cut_Man_t * p ); +/*=== cutNode.c ==========================================================*/ +extern Cut_Cut_t * Cut_NodeComputeCuts( Cut_Man_t * p, int Node, int Node0, int Node1, int fCompl0, int fCompl1, int fTriv, int TreeCode ); +extern Cut_Cut_t * Cut_NodeUnionCuts( Cut_Man_t * p, Vec_Int_t * vNodes ); +extern Cut_Cut_t * Cut_NodeUnionCutsSeq( Cut_Man_t * p, Vec_Int_t * vNodes, int CutSetNum, int fFirst ); +extern int Cut_ManMappingArea_rec( Cut_Man_t * p, int Node ); +/*=== cutSeq.c ==========================================================*/ +extern void Cut_NodeComputeCutsSeq( Cut_Man_t * p, int Node, int Node0, int Node1, int fCompl0, int fCompl1, int nLat0, int nLat1, int fTriv, int CutSetNum ); +extern void Cut_NodeNewMergeWithOld( Cut_Man_t * p, int Node ); +extern int Cut_NodeTempTransferToNew( Cut_Man_t * p, int Node, int CutSetNum ); +extern void Cut_NodeOldTransferToNew( Cut_Man_t * p, int Node ); +/*=== cutOracle.c ==========================================================*/ +extern Cut_Oracle_t * Cut_OracleStart( Cut_Man_t * pMan ); +extern void Cut_OracleStop( Cut_Oracle_t * p ); +extern void Cut_OracleSetFanoutCounts( Cut_Oracle_t * p, Vec_Int_t * vFanCounts ); +extern int Cut_OracleReadDrop( Cut_Oracle_t * p ); +extern void Cut_OracleNodeSetTriv( Cut_Oracle_t * p, int Node ); +extern Cut_Cut_t * Cut_OracleComputeCuts( Cut_Oracle_t * p, int Node, int Node0, int Node1, int fCompl0, int fCompl1 ); +extern void Cut_OracleTryDroppingCuts( Cut_Oracle_t * p, int Node ); +/*=== cutTruth.c ==========================================================*/ +extern void Cut_TruthNCanonicize( Cut_Cut_t * pCut ); +/*=== cutPre22.c ==========================================================*/ +extern void Cut_CellPrecompute(); +extern void Cut_CellLoad(); +extern int Cut_CellIsRunning(); +extern void Cut_CellDumpToFile(); +extern int Cut_CellTruthLookup( unsigned * pTruth, int nVars ); + +#ifdef __cplusplus +} +#endif + +#endif + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + diff --git a/src/opt/cut/cutApi.c b/src/opt/cut/cutApi.c new file mode 100644 index 00000000..980c6b12 --- /dev/null +++ b/src/opt/cut/cutApi.c @@ -0,0 +1,197 @@ +/**CFile**************************************************************** + + FileName [cutNode.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [K-feasible cut computation package.] + + Synopsis [Procedures to compute cuts for a node.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: cutNode.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "cutInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Returns the pointer to the linked list of cuts.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_Cut_t * Cut_NodeReadCutsNew( Cut_Man_t * p, int Node ) +{ + if ( Node >= p->vCutsNew->nSize ) + return NULL; + return Vec_PtrEntry( p->vCutsNew, Node ); +} + +/**Function************************************************************* + + Synopsis [Returns the pointer to the linked list of cuts.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_Cut_t * Cut_NodeReadCutsOld( Cut_Man_t * p, int Node ) +{ + assert( Node < p->vCutsOld->nSize ); + return Vec_PtrEntry( p->vCutsOld, Node ); +} + +/**Function************************************************************* + + Synopsis [Returns the pointer to the linked list of cuts.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_Cut_t * Cut_NodeReadCutsTemp( Cut_Man_t * p, int Node ) +{ + assert( Node < p->vCutsTemp->nSize ); + return Vec_PtrEntry( p->vCutsTemp, Node ); +} + +/**Function************************************************************* + + Synopsis [Returns the pointer to the linked list of cuts.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_NodeWriteCutsNew( Cut_Man_t * p, int Node, Cut_Cut_t * pList ) +{ + Vec_PtrWriteEntry( p->vCutsNew, Node, pList ); +} + +/**Function************************************************************* + + Synopsis [Returns the pointer to the linked list of cuts.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_NodeWriteCutsOld( Cut_Man_t * p, int Node, Cut_Cut_t * pList ) +{ + Vec_PtrWriteEntry( p->vCutsOld, Node, pList ); +} + +/**Function************************************************************* + + Synopsis [Returns the pointer to the linked list of cuts.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_NodeWriteCutsTemp( Cut_Man_t * p, int Node, Cut_Cut_t * pList ) +{ + Vec_PtrWriteEntry( p->vCutsTemp, Node, pList ); +} + +/**Function************************************************************* + + Synopsis [Sets the trivial cut for the node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_NodeSetTriv( Cut_Man_t * p, int Node ) +{ + assert( Cut_NodeReadCutsNew(p, Node) == NULL ); + Cut_NodeWriteCutsNew( p, Node, Cut_CutCreateTriv(p, Node) ); +} + +/**Function************************************************************* + + Synopsis [Consider dropping cuts if they are useless by now.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_NodeTryDroppingCuts( Cut_Man_t * p, int Node ) +{ + int nFanouts; + assert( p->vFanCounts ); + nFanouts = Vec_IntEntry( p->vFanCounts, Node ); + assert( nFanouts > 0 ); + if ( --nFanouts == 0 ) + Cut_NodeFreeCuts( p, Node ); + Vec_IntWriteEntry( p->vFanCounts, Node, nFanouts ); +} + +/**Function************************************************************* + + Synopsis [Deallocates the cuts at the node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_NodeFreeCuts( Cut_Man_t * p, int Node ) +{ + Cut_Cut_t * pList, * pCut, * pCut2; + pList = Cut_NodeReadCutsNew( p, Node ); + if ( pList == NULL ) + return; + Cut_ListForEachCutSafe( pList, pCut, pCut2 ) + Cut_CutRecycle( p, pCut ); + Cut_NodeWriteCutsNew( p, Node, NULL ); +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/cut/cutCut.c b/src/opt/cut/cutCut.c new file mode 100644 index 00000000..94147278 --- /dev/null +++ b/src/opt/cut/cutCut.c @@ -0,0 +1,359 @@ +/**CFile**************************************************************** + + FileName [cutNode.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [K-feasible cut computation package.] + + Synopsis [Procedures to compute cuts for a node.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: cutNode.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "cutInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Allocates the cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_Cut_t * Cut_CutAlloc( Cut_Man_t * p ) +{ + Cut_Cut_t * pCut; + // cut allocation + pCut = (Cut_Cut_t *)Extra_MmFixedEntryFetch( p->pMmCuts ); + memset( pCut, 0, sizeof(Cut_Cut_t) ); + pCut->nVarsMax = p->pParams->nVarsMax; + pCut->fSimul = p->fSimul; + // statistics + p->nCutsAlloc++; + p->nCutsCur++; + if ( p->nCutsPeak < p->nCutsAlloc - p->nCutsDealloc ) + p->nCutsPeak = p->nCutsAlloc - p->nCutsDealloc; + return pCut; +} + +/**Function************************************************************* + + Synopsis [Recybles the cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_CutRecycle( Cut_Man_t * p, Cut_Cut_t * pCut ) +{ + p->nCutsDealloc++; + p->nCutsCur--; + if ( pCut->nLeaves == 1 ) + p->nCutsTriv--; + Extra_MmFixedEntryRecycle( p->pMmCuts, (char *)pCut ); +} + +/**Function************************************************************* + + Synopsis [Compares two cuts.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Cut_CutCompare( Cut_Cut_t * pCut1, Cut_Cut_t * pCut2 ) +{ + int i; + if ( pCut1->nLeaves < pCut2->nLeaves ) + return -1; + if ( pCut1->nLeaves > pCut2->nLeaves ) + return 1; + for ( i = 0; i < (int)pCut1->nLeaves; i++ ) + { + if ( pCut1->pLeaves[i] < pCut2->pLeaves[i] ) + return -1; + if ( pCut1->pLeaves[i] > pCut2->pLeaves[i] ) + return 1; + } + return 0; +} + +/**Function************************************************************* + + Synopsis [Duplicates the list.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_Cut_t * Cut_CutDupList( Cut_Man_t * p, Cut_Cut_t * pList ) +{ + Cut_Cut_t * pHead = NULL, ** ppTail = &pHead; + Cut_Cut_t * pTemp, * pCopy; + if ( pList == NULL ) + return NULL; + Cut_ListForEachCut( pList, pTemp ) + { + pCopy = (Cut_Cut_t *)Extra_MmFixedEntryFetch( p->pMmCuts ); + memcpy( pCopy, pTemp, p->EntrySize ); + *ppTail = pCopy; + ppTail = &pCopy->pNext; + } + *ppTail = NULL; + return pHead; +} + +/**Function************************************************************* + + Synopsis [Recycles the list.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_CutRecycleList( Cut_Man_t * p, Cut_Cut_t * pList ) +{ + Cut_Cut_t * pCut, * pCut2; + Cut_ListForEachCutSafe( pList, pCut, pCut2 ) + Extra_MmFixedEntryRecycle( p->pMmCuts, (char *)pCut ); +} + +/**Function************************************************************* + + Synopsis [Counts the number of cuts in the list.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Cut_CutCountList( Cut_Cut_t * pList ) +{ + int Counter = 0; + Cut_ListForEachCut( pList, pList ) + Counter++; + return Counter; +} + +/**Function************************************************************* + + Synopsis [Merges two NULL-terminated linked lists.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_Cut_t * Cut_CutMergeLists( Cut_Cut_t * pList1, Cut_Cut_t * pList2 ) +{ + Cut_Cut_t * pList = NULL, ** ppTail = &pList; + Cut_Cut_t * pCut; + while ( pList1 && pList2 ) + { + if ( Cut_CutCompare(pList1, pList2) < 0 ) + { + pCut = pList1; + pList1 = pList1->pNext; + } + else + { + pCut = pList2; + pList2 = pList2->pNext; + } + *ppTail = pCut; + ppTail = &pCut->pNext; + } + *ppTail = pList1? pList1: pList2; + return pList; +} + +/**Function************************************************************* + + Synopsis [Sets the number of the cuts in the list.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_CutNumberList( Cut_Cut_t * pList ) +{ + Cut_Cut_t * pCut; + int i = 0; + Cut_ListForEachCut( pList, pCut ) + pCut->Num0 = i++; +} + +/**Function************************************************************* + + Synopsis [Creates the trivial cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_Cut_t * Cut_CutCreateTriv( Cut_Man_t * p, int Node ) +{ + Cut_Cut_t * pCut; + if ( p->pParams->fSeq ) + Node <<= CUT_SHIFT; + pCut = Cut_CutAlloc( p ); + pCut->nLeaves = 1; + pCut->pLeaves[0] = Node; + pCut->uSign = Cut_NodeSign( Node ); + if ( p->pParams->fTruth ) + { +/* + if ( pCut->nVarsMax == 4 ) + Cut_CutWriteTruth( pCut, p->uTruthVars[0] ); + else + Extra_BitCopy( pCut->nLeaves, p->uTruths[0], (uint8*)Cut_CutReadTruth(pCut) ); +*/ + unsigned * pTruth = Cut_CutReadTruth(pCut); + int i; + for ( i = 0; i < p->nTruthWords; i++ ) + pTruth[i] = 0xAAAAAAAA; + } + p->nCutsTriv++; + return pCut; +} + + +/**Function************************************************************* + + Synopsis [Print the cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_CutPrint( Cut_Cut_t * pCut, int fSeq ) +{ + int i; + assert( pCut->nLeaves > 0 ); + printf( "%d : {", pCut->nLeaves ); + for ( i = 0; i < (int)pCut->nLeaves; i++ ) + { + if ( fSeq ) + { + printf( " %d", pCut->pLeaves[i] >> CUT_SHIFT ); + if ( pCut->pLeaves[i] & CUT_MASK ) + printf( "(%d)", pCut->pLeaves[i] & CUT_MASK ); + } + else + printf( " %d", pCut->pLeaves[i] ); + } + printf( " }" ); +// printf( "\nSign = " ); +// Extra_PrintBinary( stdout, &pCut->uSign, 32 ); +} + +/**Function************************************************************* + + Synopsis [Print the cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_CutPrintList( Cut_Cut_t * pList, int fSeq ) +{ + Cut_Cut_t * pCut; + for ( pCut = pList; pCut; pCut = pCut->pNext ) + Cut_CutPrint( pCut, fSeq ), printf( "\n" ); +} + +/**Function************************************************************* + + Synopsis [Consider dropping cuts if they are useless by now.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_CutPrintMerge( Cut_Cut_t * pCut, Cut_Cut_t * pCut0, Cut_Cut_t * pCut1 ) +{ + printf( "\n" ); + printf( "%d : %5d %5d %5d %5d %5d\n", + pCut0->nLeaves, + pCut0->nLeaves > 0 ? pCut0->pLeaves[0] : -1, + pCut0->nLeaves > 1 ? pCut0->pLeaves[1] : -1, + pCut0->nLeaves > 2 ? pCut0->pLeaves[2] : -1, + pCut0->nLeaves > 3 ? pCut0->pLeaves[3] : -1, + pCut0->nLeaves > 4 ? pCut0->pLeaves[4] : -1 + ); + printf( "%d : %5d %5d %5d %5d %5d\n", + pCut1->nLeaves, + pCut1->nLeaves > 0 ? pCut1->pLeaves[0] : -1, + pCut1->nLeaves > 1 ? pCut1->pLeaves[1] : -1, + pCut1->nLeaves > 2 ? pCut1->pLeaves[2] : -1, + pCut1->nLeaves > 3 ? pCut1->pLeaves[3] : -1, + pCut1->nLeaves > 4 ? pCut1->pLeaves[4] : -1 + ); + if ( pCut == NULL ) + printf( "Cannot merge\n" ); + else + printf( "%d : %5d %5d %5d %5d %5d\n", + pCut->nLeaves, + pCut->nLeaves > 0 ? pCut->pLeaves[0] : -1, + pCut->nLeaves > 1 ? pCut->pLeaves[1] : -1, + pCut->nLeaves > 2 ? pCut->pLeaves[2] : -1, + pCut->nLeaves > 3 ? pCut->pLeaves[3] : -1, + pCut->nLeaves > 4 ? pCut->pLeaves[4] : -1 + ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/cut/cutExpand.c b/src/opt/cut/cutExpand.c new file mode 100644 index 00000000..d389ef7a --- /dev/null +++ b/src/opt/cut/cutExpand.c @@ -0,0 +1,184 @@ +/**CFile**************************************************************** + + FileName [cutExpand.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [K-feasible cut computation package.] + + Synopsis [Computes the truth table of the cut after expansion.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: cutExpand.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "cutInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +#define CUT_CELL_MVAR 9 + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Computes the stretching phase of the cut w.r.t. the merged cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline unsigned Cut_TruthPhase( Cut_Cut_t * pCut, Cut_Cut_t * pCut1 ) +{ + unsigned uPhase = 0; + int i, k; + for ( i = k = 0; i < (int)pCut->nLeaves; i++ ) + { + if ( k == (int)pCut1->nLeaves ) + break; + if ( pCut->pLeaves[i] < pCut1->pLeaves[k] ) + continue; + assert( pCut->pLeaves[i] == pCut1->pLeaves[k] ); + uPhase |= (1 << i); + k++; + } + return uPhase; +} + +/**Function************************************************************* + + Synopsis [Computes the truth table of the composition of cuts.] + + Description [Inputs are: + - a factor cut (truth table is stored inside) + - a node in the factor cut + - a tree cut to be substituted (truth table is stored inside) + - the resulting cut (truth table will be filled in). + Note that all cuts, including the resulting one, should be already + computed and the nodes should be stored in the ascending order.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_TruthCompose( Cut_Cut_t * pCutF, int Node, Cut_Cut_t * pCutT, Cut_Cut_t * pCutRes ) +{ + static unsigned uCof0[1<<(CUT_CELL_MVAR-5)]; + static unsigned uCof1[1<<(CUT_CELL_MVAR-5)]; + static unsigned uTemp[1<<(CUT_CELL_MVAR-5)]; + unsigned * pIn, * pOut, * pTemp; + unsigned uPhase; + int NodeIndex, i, k; + + // sanity checks + assert( pCutF->nVarsMax == pCutT->nVarsMax ); + assert( pCutF->nVarsMax == pCutRes->nVarsMax ); + assert( pCutF->nVarsMax <= CUT_CELL_MVAR ); + // the factor cut (pCutF) should have its nodes sorted in the ascending order + assert( pCutF->nLeaves <= pCutF->nVarsMax ); + for ( i = 0; i < (int)pCutF->nLeaves - 1; i++ ) + assert( pCutF->pLeaves[i] < pCutF->pLeaves[i+1] ); + // the tree cut (pCutT) should have its nodes sorted in the ascending order + assert( pCutT->nLeaves <= pCutT->nVarsMax ); + for ( i = 0; i < (int)pCutT->nLeaves - 1; i++ ) + assert( pCutT->pLeaves[i] < pCutT->pLeaves[i+1] ); + // the resulting cut (pCutRes) should have its nodes sorted in the ascending order + assert( pCutRes->nLeaves <= pCutRes->nVarsMax ); + for ( i = 0; i < (int)pCutRes->nLeaves - 1; i++ ) + assert( pCutRes->pLeaves[i] < pCutRes->pLeaves[i+1] ); + // make sure that every node in pCutF (except Node) appears in pCutRes + for ( i = 0; i < (int)pCutF->nLeaves; i++ ) + { + if ( pCutF->pLeaves[i] == Node ) + continue; + for ( k = 0; k < (int)pCutRes->nLeaves; k++ ) + if ( pCutF->pLeaves[i] == pCutRes->pLeaves[k] ) + break; + assert( k < (int)pCutRes->nLeaves ); // node i from pCutF is not found in pCutRes!!! + } + // make sure that every node in pCutT appears in pCutRes + for ( i = 0; i < (int)pCutT->nLeaves; i++ ) + { + for ( k = 0; k < (int)pCutRes->nLeaves; k++ ) + if ( pCutT->pLeaves[i] == pCutRes->pLeaves[k] ) + break; + assert( k < (int)pCutRes->nLeaves ); // node i from pCutT is not found in pCutRes!!! + } + + + // find the index of the given node in the factor cut + NodeIndex = -1; + for ( NodeIndex = 0; NodeIndex < (int)pCutF->nLeaves; NodeIndex++ ) + if ( pCutF->pLeaves[NodeIndex] == Node ) + break; + assert( NodeIndex >= 0 ); // Node should be in pCutF + + // copy the truth table + Extra_TruthCopy( uTemp, Cut_CutReadTruth(pCutF), pCutF->nLeaves ); + + // bubble-move the NodeIndex variable to be the last one (the most significant one) + pIn = uTemp; pOut = uCof0; // uCof0 is used for temporary storage here + for ( i = NodeIndex; i < (int)pCutF->nLeaves - 1; i++ ) + { + Extra_TruthSwapAdjacentVars( pOut, pIn, pCutF->nLeaves, i ); + pTemp = pIn; pIn = pOut; pOut = pTemp; + } + if ( (pCutF->nLeaves - 1 - NodeIndex) & 1 ) + Extra_TruthCopy( pOut, pIn, pCutF->nLeaves ); + // the result of stretching is in uTemp + + // cofactor the factor cut with respect to the node + Extra_TruthCopy( uCof0, uTemp, pCutF->nLeaves ); + Extra_TruthCofactor0( uCof0, pCutF->nLeaves, pCutF->nLeaves-1 ); + Extra_TruthCopy( uCof1, uTemp, pCutF->nLeaves ); + Extra_TruthCofactor1( uCof1, pCutF->nLeaves, pCutF->nLeaves-1 ); + + // temporarily shrink the factor cut's variables by removing Node + for ( i = NodeIndex; i < (int)pCutF->nLeaves - 1; i++ ) + pCutF->pLeaves[i] = pCutF->pLeaves[i+1]; + pCutF->nLeaves--; + + // spread out the cofactors' truth tables to the same var order as the resulting cut + uPhase = Cut_TruthPhase(pCutRes, pCutF); + assert( Extra_WordCountOnes(uPhase) == (int)pCutF->nLeaves ); + Extra_TruthStretch( uTemp, uCof0, pCutF->nLeaves, pCutF->nVarsMax, uPhase ); + Extra_TruthCopy( uCof0, uTemp, pCutF->nVarsMax ); + Extra_TruthStretch( uTemp, uCof1, pCutF->nLeaves, pCutF->nVarsMax, uPhase ); + Extra_TruthCopy( uCof1, uTemp, pCutF->nVarsMax ); + + // spread out the tree cut's truth table to the same var order as the resulting cut + uPhase = Cut_TruthPhase(pCutRes, pCutT); + assert( Extra_WordCountOnes(uPhase) == (int)pCutT->nLeaves ); + Extra_TruthStretch( uTemp, Cut_CutReadTruth(pCutT), pCutT->nLeaves, pCutT->nVarsMax, uPhase ); + + // create the resulting truth table + pTemp = Cut_CutReadTruth(pCutRes); + for ( i = Extra_TruthWordNum(pCutRes->nLeaves)-1; i >= 0; i-- ) + pTemp[i] = (uCof0[i] & ~uTemp[i]) | (uCof1[i] & uTemp[i]); + + // undo the removal of the node from the cut + for ( i = (int)pCutF->nLeaves - 1; i >= NodeIndex; --i ) + pCutF->pLeaves[i+1] = pCutF->pLeaves[i]; + pCutF->pLeaves[NodeIndex] = Node; + pCutF->nLeaves++; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/cut/cutInt.h b/src/opt/cut/cutInt.h new file mode 100644 index 00000000..17f268c7 --- /dev/null +++ b/src/opt/cut/cutInt.h @@ -0,0 +1,157 @@ +/**CFile**************************************************************** + + FileName [cutInt.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [K-feasible cut computation package.] + + Synopsis [External declarations.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: cutInt.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef __CUT_INT_H__ +#define __CUT_INT_H__ + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +#include +#include "extra.h" +#include "vec.h" +#include "cut.h" +#include "cutList.h" + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// BASIC TYPES /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Cut_HashTableStruct_t_ Cut_HashTable_t; + +struct Cut_ManStruct_t_ +{ + // user preferences + Cut_Params_t * pParams; // computation parameters + Vec_Int_t * vFanCounts; // the array of fanout counters + Vec_Int_t * vNodeAttrs; // node attributes (1 = global; 0 = local) + // storage for cuts + Vec_Ptr_t * vCutsNew; // new cuts by node ID + Vec_Ptr_t * vCutsOld; // old cuts by node ID + Vec_Ptr_t * vCutsTemp; // temp cuts for cutset nodes by cutset node number + // memory management + Extra_MmFixed_t * pMmCuts; + int EntrySize; + int nTruthWords; + // temporary variables + Cut_Cut_t * pReady; + Vec_Ptr_t * vTemp; + int fCompl0; + int fCompl1; + int fSimul; + int nNodeCuts; + Cut_Cut_t * pStore0[2]; + Cut_Cut_t * pStore1[2]; + Cut_Cut_t * pCompareOld; + Cut_Cut_t * pCompareNew; + unsigned * puTemp[4]; + // record of the cut computation + Vec_Int_t * vNodeCuts; // the number of cuts for each node + Vec_Int_t * vNodeStarts; // the number of the starting cut of each node + Vec_Int_t * vCutPairs; // the pairs of parent cuts for each cut + // minimum delay mapping with the given cuts + Vec_Ptr_t * vCutsMax; + Vec_Int_t * vDelays; + Vec_Int_t * vDelays2; + int nDelayMin; + // statistics + int nCutsCur; + int nCutsAlloc; + int nCutsDealloc; + int nCutsPeak; + int nCutsTriv; + int nCutsFilter; + int nCutsLimit; + int nNodes; + int nNodesDag; + int nNodesNoCuts; + // runtime + int timeMerge; + int timeUnion; + int timeTruth; + int timeFilter; + int timeHash; + int timeMap; +}; + +// iterator through all the cuts of the list +#define Cut_ListForEachCut( pList, pCut ) \ + for ( pCut = pList; \ + pCut; \ + pCut = pCut->pNext ) +#define Cut_ListForEachCutStop( pList, pCut, pStop ) \ + for ( pCut = pList; \ + pCut != pStop; \ + pCut = pCut->pNext ) +#define Cut_ListForEachCutSafe( pList, pCut, pCut2 ) \ + for ( pCut = pList, \ + pCut2 = pCut? pCut->pNext: NULL; \ + pCut; \ + pCut = pCut2, \ + pCut2 = pCut? pCut->pNext: NULL ) + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +// computes signature of the node +static inline unsigned Cut_NodeSign( int Node ) { return (1 << (Node % 31)); } +static inline int Cut_TruthWords( int nVarsMax ) { return nVarsMax <= 5 ? 1 : (1 << (nVarsMax - 5)); } + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +/*=== cutCut.c ==========================================================*/ +extern Cut_Cut_t * Cut_CutAlloc( Cut_Man_t * p ); +extern void Cut_CutRecycle( Cut_Man_t * p, Cut_Cut_t * pCut ); +extern int Cut_CutCompare( Cut_Cut_t * pCut1, Cut_Cut_t * pCut2 ); +extern Cut_Cut_t * Cut_CutDupList( Cut_Man_t * p, Cut_Cut_t * pList ); +extern void Cut_CutRecycleList( Cut_Man_t * p, Cut_Cut_t * pList ); +extern Cut_Cut_t * Cut_CutMergeLists( Cut_Cut_t * pList1, Cut_Cut_t * pList2 ); +extern void Cut_CutNumberList( Cut_Cut_t * pList ); +extern Cut_Cut_t * Cut_CutCreateTriv( Cut_Man_t * p, int Node ); +extern void Cut_CutPrintMerge( Cut_Cut_t * pCut, Cut_Cut_t * pCut0, Cut_Cut_t * pCut1 ); +/*=== cutMerge.c ==========================================================*/ +extern Cut_Cut_t * Cut_CutMergeTwo( Cut_Man_t * p, Cut_Cut_t * pCut0, Cut_Cut_t * pCut1 ); +/*=== cutNode.c ==========================================================*/ +extern void Cut_NodeDoComputeCuts( Cut_Man_t * p, Cut_List_t * pSuper, int Node, int fCompl0, int fCompl1, Cut_Cut_t * pList0, Cut_Cut_t * pList1, int fTriv, int TreeCode ); +extern int Cut_CutListVerify( Cut_Cut_t * pList ); +/*=== cutTable.c ==========================================================*/ +extern Cut_HashTable_t * Cut_TableStart( int Size ); +extern void Cut_TableStop( Cut_HashTable_t * pTable ); +extern int Cut_TableLookup( Cut_HashTable_t * pTable, Cut_Cut_t * pCut, int fStore ); +extern void Cut_TableClear( Cut_HashTable_t * pTable ); +extern int Cut_TableReadTime( Cut_HashTable_t * pTable ); +/*=== cutTruth.c ==========================================================*/ +extern void Cut_TruthComputeOld( Cut_Cut_t * pCut, Cut_Cut_t * pCut0, Cut_Cut_t * pCut1, int fCompl0, int fCompl1 ); +extern void Cut_TruthCompute( Cut_Man_t * p, Cut_Cut_t * pCut, Cut_Cut_t * pCut0, Cut_Cut_t * pCut1, int fCompl0, int fCompl1 ); + +#endif + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + diff --git a/src/opt/cut/cutList.h b/src/opt/cut/cutList.h new file mode 100644 index 00000000..a03ec9d5 --- /dev/null +++ b/src/opt/cut/cutList.h @@ -0,0 +1,207 @@ +/**CFile**************************************************************** + + FileName [cutList.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Implementation of layered listed list of cuts.] + + Synopsis [External declarations.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: cutList.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef __CUT_LIST_H__ +#define __CUT_LIST_H__ + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// BASIC TYPES /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Cut_ListStruct_t_ Cut_List_t; +struct Cut_ListStruct_t_ +{ + Cut_Cut_t * pHead[CUT_SIZE_MAX+1]; + Cut_Cut_t ** ppTail[CUT_SIZE_MAX+1]; +}; + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Start the cut list.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Cut_ListStart( Cut_List_t * p ) +{ + int i; + for ( i = 1; i <= CUT_SIZE_MAX; i++ ) + { + p->pHead[i] = 0; + p->ppTail[i] = &p->pHead[i]; + } +} + +/**Function************************************************************* + + Synopsis [Adds one cut to the cut list.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Cut_ListAdd( Cut_List_t * p, Cut_Cut_t * pCut ) +{ + assert( pCut->nLeaves > 0 && pCut->nLeaves <= CUT_SIZE_MAX ); + *p->ppTail[pCut->nLeaves] = pCut; + p->ppTail[pCut->nLeaves] = &pCut->pNext; +} + +/**Function************************************************************* + + Synopsis [Adds one cut to the cut list while preserving order.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Cut_ListAdd2( Cut_List_t * p, Cut_Cut_t * pCut ) +{ + extern int Cut_CutCompare( Cut_Cut_t * pCut1, Cut_Cut_t * pCut2 ); + Cut_Cut_t * pTemp, ** ppSpot; + assert( pCut->nLeaves > 0 && pCut->nLeaves <= CUT_SIZE_MAX ); + if ( p->pHead[pCut->nLeaves] != NULL ) + { + ppSpot = &p->pHead[pCut->nLeaves]; + for ( pTemp = p->pHead[pCut->nLeaves]; pTemp; pTemp = pTemp->pNext ) + { + if ( Cut_CutCompare(pCut, pTemp) < 0 ) + { + *ppSpot = pCut; + pCut->pNext = pTemp; + return; + } + else + ppSpot = &pTemp->pNext; + } + } + *p->ppTail[pCut->nLeaves] = pCut; + p->ppTail[pCut->nLeaves] = &pCut->pNext; +} + +/**Function************************************************************* + + Synopsis [Derive the super list from the linked list of cuts.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Cut_ListDerive( Cut_List_t * p, Cut_Cut_t * pList ) +{ + Cut_Cut_t * pPrev; + int nLeaves; + Cut_ListStart( p ); + while ( pList != NULL ) + { + nLeaves = pList->nLeaves; + p->pHead[nLeaves] = pList; + for ( pPrev = pList, pList = pList->pNext; pList; pPrev = pList, pList = pList->pNext ) + if ( nLeaves < (int)pList->nLeaves ) + break; + p->ppTail[nLeaves] = &pPrev->pNext; + pPrev->pNext = NULL; + } +} + +/**Function************************************************************* + + Synopsis [Adds the second list to the first list.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Cut_ListAddList( Cut_List_t * pOld, Cut_List_t * pNew ) +{ + int i; + for ( i = 1; i <= CUT_SIZE_MAX; i++ ) + { + if ( pNew->pHead[i] == NULL ) + continue; + *pOld->ppTail[i] = pNew->pHead[i]; + pOld->ppTail[i] = pNew->ppTail[i]; + } +} + +/**Function************************************************************* + + Synopsis [Returns the cut list linked into one sequence of cuts.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Cut_Cut_t * Cut_ListFinish( Cut_List_t * p ) +{ + Cut_Cut_t * pHead = NULL, ** ppTail = &pHead; + int i; + for ( i = 1; i <= CUT_SIZE_MAX; i++ ) + { + if ( p->pHead[i] == NULL ) + continue; + *ppTail = p->pHead[i]; + ppTail = p->ppTail[i]; + } + *ppTail = NULL; + return pHead; +} + +#endif + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + diff --git a/src/opt/cut/cutMan.c b/src/opt/cut/cutMan.c new file mode 100644 index 00000000..8593ef93 --- /dev/null +++ b/src/opt/cut/cutMan.c @@ -0,0 +1,326 @@ +/**CFile**************************************************************** + + FileName [cutMan.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [K-feasible cut computation package.] + + Synopsis [Cut manager.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: cutMan.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "cutInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +extern void Npn_StartTruth8( uint8 uTruths[][32] ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Starts the cut manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_Man_t * Cut_ManStart( Cut_Params_t * pParams ) +{ + Cut_Man_t * p; + int clk = clock(); +// extern int nTruthDsd; +// nTruthDsd = 0; + assert( pParams->nVarsMax >= 3 && pParams->nVarsMax <= CUT_SIZE_MAX ); + p = ALLOC( Cut_Man_t, 1 ); + memset( p, 0, sizeof(Cut_Man_t) ); + // set and correct parameters + p->pParams = pParams; + // prepare storage for cuts + p->vCutsNew = Vec_PtrAlloc( pParams->nIdsMax ); + Vec_PtrFill( p->vCutsNew, pParams->nIdsMax, NULL ); + // prepare storage for sequential cuts + if ( pParams->fSeq ) + { + p->pParams->fFilter = 1; + p->vCutsOld = Vec_PtrAlloc( pParams->nIdsMax ); + Vec_PtrFill( p->vCutsOld, pParams->nIdsMax, NULL ); + p->vCutsTemp = Vec_PtrAlloc( pParams->nCutSet ); + Vec_PtrFill( p->vCutsTemp, pParams->nCutSet, NULL ); + if ( pParams->fTruth && pParams->nVarsMax > 5 ) + { + pParams->fTruth = 0; + printf( "Skipping computation of truth tables for sequential cuts with more than 5 inputs.\n" ); + } + } + // entry size + p->EntrySize = sizeof(Cut_Cut_t) + pParams->nVarsMax * sizeof(int); + if ( pParams->fTruth ) + { + if ( pParams->nVarsMax > 14 ) + { + pParams->fTruth = 0; + printf( "Skipping computation of truth table for more than %d inputs.\n", 14 ); + } + else + { + p->nTruthWords = Cut_TruthWords( pParams->nVarsMax ); + p->EntrySize += p->nTruthWords * sizeof(unsigned); + } + p->puTemp[0] = ALLOC( unsigned, 4 * p->nTruthWords ); + p->puTemp[1] = p->puTemp[0] + p->nTruthWords; + p->puTemp[2] = p->puTemp[1] + p->nTruthWords; + p->puTemp[3] = p->puTemp[2] + p->nTruthWords; + } + // enable cut computation recording + if ( pParams->fRecord ) + { + p->vNodeCuts = Vec_IntStart( pParams->nIdsMax ); + p->vNodeStarts = Vec_IntStart( pParams->nIdsMax ); + p->vCutPairs = Vec_IntAlloc( 0 ); + } + // allocate storage for delays + if ( pParams->fMap && !p->pParams->fSeq ) + { + p->vDelays = Vec_IntStart( pParams->nIdsMax ); + p->vDelays2 = Vec_IntStart( pParams->nIdsMax ); + p->vCutsMax = Vec_PtrStart( pParams->nIdsMax ); + } + // memory for cuts + p->pMmCuts = Extra_MmFixedStart( p->EntrySize ); + p->vTemp = Vec_PtrAlloc( 100 ); + return p; +} + +/**Function************************************************************* + + Synopsis [Stops the cut manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_ManStop( Cut_Man_t * p ) +{ + Cut_Cut_t * pCut; + int i; +// extern int nTruthDsd; +// printf( "Decomposable cuts = %d.\n", nTruthDsd ); + + Vec_PtrForEachEntry( p->vCutsNew, pCut, i ) + if ( pCut != NULL ) + { + int k = 0; + } + if ( p->vCutsNew ) Vec_PtrFree( p->vCutsNew ); + if ( p->vCutsOld ) Vec_PtrFree( p->vCutsOld ); + if ( p->vCutsTemp ) Vec_PtrFree( p->vCutsTemp ); + if ( p->vFanCounts ) Vec_IntFree( p->vFanCounts ); + if ( p->vTemp ) Vec_PtrFree( p->vTemp ); + + if ( p->vCutsMax ) Vec_PtrFree( p->vCutsMax ); + if ( p->vDelays ) Vec_IntFree( p->vDelays ); + if ( p->vDelays2 ) Vec_IntFree( p->vDelays2 ); + if ( p->vNodeCuts ) Vec_IntFree( p->vNodeCuts ); + if ( p->vNodeStarts ) Vec_IntFree( p->vNodeStarts ); + if ( p->vCutPairs ) Vec_IntFree( p->vCutPairs ); + if ( p->puTemp[0] ) free( p->puTemp[0] ); + + Extra_MmFixedStop( p->pMmCuts ); + free( p ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_ManPrintStats( Cut_Man_t * p ) +{ + if ( p->pReady ) + { + Cut_CutRecycle( p, p->pReady ); + p->pReady = NULL; + } + printf( "Cut computation statistics:\n" ); + printf( "Current cuts = %8d. (Trivial = %d.)\n", p->nCutsCur-p->nCutsTriv, p->nCutsTriv ); + printf( "Peak cuts = %8d.\n", p->nCutsPeak ); + printf( "Total allocated = %8d.\n", p->nCutsAlloc ); + printf( "Total deallocated = %8d.\n", p->nCutsDealloc ); + printf( "Cuts filtered = %8d.\n", p->nCutsFilter ); + printf( "Nodes saturated = %8d. (Max cuts = %d.)\n", p->nCutsLimit, p->pParams->nKeepMax ); + printf( "Cuts per node = %8.1f\n", ((float)(p->nCutsCur-p->nCutsTriv))/p->nNodes ); + printf( "The cut size = %8d bytes.\n", p->EntrySize ); + printf( "Peak memory = %8.2f Mb.\n", (float)p->nCutsPeak * p->EntrySize / (1<<20) ); + printf( "Total nodes = %8d.\n", p->nNodes ); + if ( p->pParams->fDag || p->pParams->fTree ) + { + printf( "DAG nodes = %8d.\n", p->nNodesDag ); + printf( "Tree nodes = %8d.\n", p->nNodes - p->nNodesDag ); + } + printf( "Nodes w/o cuts = %8d.\n", p->nNodesNoCuts ); + if ( p->pParams->fMap && !p->pParams->fSeq ) + printf( "Mapping delay = %8d.\n", p->nDelayMin ); + + PRT( "Merge ", p->timeMerge ); + PRT( "Union ", p->timeUnion ); + PRT( "Filter", p->timeFilter ); + PRT( "Truth ", p->timeTruth ); + PRT( "Map ", p->timeMap ); +// printf( "Nodes = %d. Multi = %d. Cuts = %d. Multi = %d.\n", +// p->nNodes, p->nNodesMulti, p->nCutsCur-p->nCutsTriv, p->nCutsMulti ); +// printf( "Count0 = %d. Count1 = %d. Count2 = %d.\n\n", p->Count0, p->Count1, p->Count2 ); +} + + +/**Function************************************************************* + + Synopsis [Prints some interesting stats.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_ManPrintStatsToFile( Cut_Man_t * p, char * pFileName, int TimeTotal ) +{ + FILE * pTable; + pTable = fopen( "cut_stats.txt", "a+" ); + fprintf( pTable, "%-20s ", pFileName ); + fprintf( pTable, "%8d ", p->nNodes ); + fprintf( pTable, "%6.1f ", ((float)(p->nCutsCur))/p->nNodes ); + fprintf( pTable, "%6.2f ", ((float)(100.0 * p->nCutsLimit))/p->nNodes ); + fprintf( pTable, "%6.2f ", (float)p->nCutsPeak * p->EntrySize / (1<<20) ); + fprintf( pTable, "%6.2f ", (float)(TimeTotal)/(float)(CLOCKS_PER_SEC) ); + fprintf( pTable, "\n" ); + fclose( pTable ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_ManSetFanoutCounts( Cut_Man_t * p, Vec_Int_t * vFanCounts ) +{ + p->vFanCounts = vFanCounts; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_ManSetNodeAttrs( Cut_Man_t * p, Vec_Int_t * vNodeAttrs ) +{ + p->vNodeAttrs = vNodeAttrs; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Cut_ManReadVarsMax( Cut_Man_t * p ) +{ + return p->pParams->nVarsMax; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_Params_t * Cut_ManReadParams( Cut_Man_t * p ) +{ + return p->pParams; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Int_t * Cut_ManReadNodeAttrs( Cut_Man_t * p ) +{ + return p->vNodeAttrs; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_ManIncrementDagNodes( Cut_Man_t * p ) +{ + p->nNodesDag++; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/cut/cutMerge.c b/src/opt/cut/cutMerge.c new file mode 100644 index 00000000..d8a9989c --- /dev/null +++ b/src/opt/cut/cutMerge.c @@ -0,0 +1,657 @@ +/**CFile**************************************************************** + + FileName [cutMerge.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [K-feasible cut computation package.] + + Synopsis [Procedure to merge two cuts.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: cutMerge.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "cutInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Merges two cuts.] + + Description [This procedure works.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_Cut_t * Cut_CutMergeTwo2( Cut_Man_t * p, Cut_Cut_t * pCut0, Cut_Cut_t * pCut1 ) +{ + static int M[7][3] = {{0},{0},{0},{0},{0},{0},{0}}; + Cut_Cut_t * pRes; + int * pRow; + int nLeaves0, nLeaves1, Limit; + int i, k, Count, nNodes; + + assert( pCut0->nLeaves >= pCut1->nLeaves ); + + // the case of the largest cut sizes + Limit = p->pParams->nVarsMax; + nLeaves0 = pCut0->nLeaves; + nLeaves1 = pCut1->nLeaves; + if ( nLeaves0 == Limit && nLeaves1 == Limit ) + { + for ( i = 0; i < nLeaves0; i++ ) + if ( pCut0->pLeaves[i] != pCut1->pLeaves[i] ) + return NULL; + pRes = Cut_CutAlloc( p ); + for ( i = 0; i < nLeaves0; i++ ) + pRes->pLeaves[i] = pCut0->pLeaves[i]; + pRes->nLeaves = nLeaves0; + return pRes; + } + // the case when one of the cuts is the largest + if ( nLeaves0 == Limit ) + { + for ( i = 0; i < nLeaves1; i++ ) + { + for ( k = nLeaves0 - 1; k >= 0; k-- ) + if ( pCut0->pLeaves[k] == pCut1->pLeaves[i] ) + break; + if ( k == -1 ) // did not find + return NULL; + } + pRes = Cut_CutAlloc( p ); + for ( i = 0; i < nLeaves0; i++ ) + pRes->pLeaves[i] = pCut0->pLeaves[i]; + pRes->nLeaves = nLeaves0; + return pRes; + } + // other cases + nNodes = nLeaves0; + for ( i = 0; i < nLeaves1; i++ ) + { + for ( k = nLeaves0 - 1; k >= 0; k-- ) + { + if ( pCut0->pLeaves[k] > pCut1->pLeaves[i] ) + continue; + if ( pCut0->pLeaves[k] < pCut1->pLeaves[i] ) + { + pRow = M[k+1]; + if ( pRow[0] == 0 ) + pRow[0] = pCut1->pLeaves[i], pRow[1] = 0; + else if ( pRow[1] == 0 ) + pRow[1] = pCut1->pLeaves[i], pRow[2] = 0; + else if ( pRow[2] == 0 ) + pRow[2] = pCut1->pLeaves[i]; + else + assert( 0 ); + if ( ++nNodes > Limit ) + { + for ( i = 0; i <= nLeaves0; i++ ) + M[i][0] = 0; + return NULL; + } + } + break; + } + if ( k == -1 ) + { + pRow = M[0]; + if ( pRow[0] == 0 ) + pRow[0] = pCut1->pLeaves[i], pRow[1] = 0; + else if ( pRow[1] == 0 ) + pRow[1] = pCut1->pLeaves[i], pRow[2] = 0; + else if ( pRow[2] == 0 ) + pRow[2] = pCut1->pLeaves[i]; + else + assert( 0 ); + if ( ++nNodes > Limit ) + { + for ( i = 0; i <= nLeaves0; i++ ) + M[i][0] = 0; + return NULL; + } + continue; + } + } + + pRes = Cut_CutAlloc( p ); + for ( Count = 0, i = 0; i <= nLeaves0; i++ ) + { + if ( i > 0 ) + pRes->pLeaves[Count++] = pCut0->pLeaves[i-1]; + pRow = M[i]; + if ( pRow[0] ) + { + pRes->pLeaves[Count++] = pRow[0]; + if ( pRow[1] ) + { + pRes->pLeaves[Count++] = pRow[1]; + if ( pRow[2] ) + pRes->pLeaves[Count++] = pRow[2]; + } + pRow[0] = 0; + } + } + assert( Count == nNodes ); + pRes->nLeaves = nNodes; + return pRes; +} + +/**Function************************************************************* + + Synopsis [Merges two cuts.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_Cut_t * Cut_CutMergeTwo( Cut_Man_t * p, Cut_Cut_t * pCut0, Cut_Cut_t * pCut1 ) +{ + Cut_Cut_t * pRes; + int * pLeaves; + int Limit, nLeaves0, nLeaves1; + int i, k, c; + + assert( pCut0->nLeaves >= pCut1->nLeaves ); + + // consider two cuts + nLeaves0 = pCut0->nLeaves; + nLeaves1 = pCut1->nLeaves; + + // the case of the largest cut sizes + Limit = p->pParams->nVarsMax; + if ( nLeaves0 == Limit && nLeaves1 == Limit ) + { + for ( i = 0; i < nLeaves0; i++ ) + if ( pCut0->pLeaves[i] != pCut1->pLeaves[i] ) + return NULL; + pRes = Cut_CutAlloc( p ); + for ( i = 0; i < nLeaves0; i++ ) + pRes->pLeaves[i] = pCut0->pLeaves[i]; + pRes->nLeaves = pCut0->nLeaves; + return pRes; + } + // the case when one of the cuts is the largest + if ( nLeaves0 == Limit ) + { + for ( i = 0; i < nLeaves1; i++ ) + { + for ( k = nLeaves0 - 1; k >= 0; k-- ) + if ( pCut0->pLeaves[k] == pCut1->pLeaves[i] ) + break; + if ( k == -1 ) // did not find + return NULL; + } + pRes = Cut_CutAlloc( p ); + for ( i = 0; i < nLeaves0; i++ ) + pRes->pLeaves[i] = pCut0->pLeaves[i]; + pRes->nLeaves = pCut0->nLeaves; + return pRes; + } + + // prepare the cut + if ( p->pReady == NULL ) + p->pReady = Cut_CutAlloc( p ); + pLeaves = p->pReady->pLeaves; + + // compare two cuts with different numbers + i = k = 0; + for ( c = 0; c < Limit; c++ ) + { + if ( k == nLeaves1 ) + { + if ( i == nLeaves0 ) + { + p->pReady->nLeaves = c; + pRes = p->pReady; p->pReady = NULL; + return pRes; + } + pLeaves[c] = pCut0->pLeaves[i++]; + continue; + } + if ( i == nLeaves0 ) + { + if ( k == nLeaves1 ) + { + p->pReady->nLeaves = c; + pRes = p->pReady; p->pReady = NULL; + return pRes; + } + pLeaves[c] = pCut1->pLeaves[k++]; + continue; + } + if ( pCut0->pLeaves[i] < pCut1->pLeaves[k] ) + { + pLeaves[c] = pCut0->pLeaves[i++]; + continue; + } + if ( pCut0->pLeaves[i] > pCut1->pLeaves[k] ) + { + pLeaves[c] = pCut1->pLeaves[k++]; + continue; + } + pLeaves[c] = pCut0->pLeaves[i++]; + k++; + } + if ( i < nLeaves0 || k < nLeaves1 ) + return NULL; + p->pReady->nLeaves = c; + pRes = p->pReady; p->pReady = NULL; + return pRes; +} + + +/**Function************************************************************* + + Synopsis [Merges two cuts.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_Cut_t * Cut_CutMergeTwo3( Cut_Man_t * p, Cut_Cut_t * pCut0, Cut_Cut_t * pCut1 ) +{ + Cut_Cut_t * pRes; + int * pLeaves; + int Limit, nLeaves0, nLeaves1; + int i, k, c; + + assert( pCut0->nLeaves >= pCut1->nLeaves ); + + // prepare the cut + if ( p->pReady == NULL ) + p->pReady = Cut_CutAlloc( p ); + pLeaves = p->pReady->pLeaves; + + // consider two cuts + Limit = p->pParams->nVarsMax; + nLeaves0 = pCut0->nLeaves; + nLeaves1 = pCut1->nLeaves; + if ( nLeaves0 == Limit ) + { // the case when one of the cuts is the largest + if ( nLeaves1 == Limit ) + { // the case when both cuts are the largest + for ( i = 0; i < nLeaves0; i++ ) + { + pLeaves[i] = pCut0->pLeaves[i]; + if ( pLeaves[i] != pCut1->pLeaves[i] ) + return NULL; + } + } + else + { + for ( i = k = 0; i < nLeaves0; i++ ) + { + pLeaves[i] = pCut0->pLeaves[i]; + if ( k == (int)nLeaves1 ) + continue; + if ( pLeaves[i] < pCut1->pLeaves[k] ) + continue; + if ( pLeaves[i] == pCut1->pLeaves[k++] ) + continue; + return NULL; + } + if ( k < nLeaves1 ) + return NULL; + } + p->pReady->nLeaves = nLeaves0; + pRes = p->pReady; p->pReady = NULL; + return pRes; + } + + // compare two cuts with different numbers + i = k = 0; + for ( c = 0; c < Limit; c++ ) + { + if ( k == nLeaves1 ) + { + if ( i == nLeaves0 ) + { + p->pReady->nLeaves = c; + pRes = p->pReady; p->pReady = NULL; + return pRes; + } + pLeaves[c] = pCut0->pLeaves[i++]; + continue; + } + if ( i == nLeaves0 ) + { + if ( k == nLeaves1 ) + { + p->pReady->nLeaves = c; + pRes = p->pReady; p->pReady = NULL; + return pRes; + } + pLeaves[c] = pCut1->pLeaves[k++]; + continue; + } + if ( pCut0->pLeaves[i] < pCut1->pLeaves[k] ) + { + pLeaves[c] = pCut0->pLeaves[i++]; + continue; + } + if ( pCut0->pLeaves[i] > pCut1->pLeaves[k] ) + { + pLeaves[c] = pCut1->pLeaves[k++]; + continue; + } + pLeaves[c] = pCut0->pLeaves[i++]; + k++; + } + if ( i < nLeaves0 || k < nLeaves1 ) + return NULL; + p->pReady->nLeaves = c; + pRes = p->pReady; p->pReady = NULL; + return pRes; +} + +/**Function************************************************************* + + Synopsis [Merges two cuts.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_Cut_t * Cut_CutMergeTwo4( Cut_Man_t * p, Cut_Cut_t * pCut0, Cut_Cut_t * pCut1 ) +{ + Cut_Cut_t * pRes; + int * pLeaves; + int i, k, min, NodeTemp, Limit, nTotal; + + assert( pCut0->nLeaves >= pCut1->nLeaves ); + + // prepare the cut + if ( p->pReady == NULL ) + p->pReady = Cut_CutAlloc( p ); + pLeaves = p->pReady->pLeaves; + + // consider two cuts + Limit = p->pParams->nVarsMax; + if ( pCut0->nLeaves == (unsigned)Limit ) + { // the case when one of the cuts is the largest + if ( pCut1->nLeaves == (unsigned)Limit ) + { // the case when both cuts are the largest + for ( i = 0; i < (int)pCut0->nLeaves; i++ ) + { + pLeaves[i] = pCut0->pLeaves[i]; + if ( pLeaves[i] != pCut1->pLeaves[i] ) + return NULL; + } + } + else + { + for ( i = k = 0; i < (int)pCut0->nLeaves; i++ ) + { + pLeaves[i] = pCut0->pLeaves[i]; + if ( k == (int)pCut1->nLeaves ) + continue; + if ( pLeaves[i] < pCut1->pLeaves[k] ) + continue; + if ( pLeaves[i] == pCut1->pLeaves[k++] ) + continue; + return NULL; + } + if ( k < (int)pCut1->nLeaves ) + return NULL; + } + p->pReady->nLeaves = pCut0->nLeaves; + pRes = p->pReady; p->pReady = NULL; + return pRes; + } + + // count the number of unique entries in pCut1 + nTotal = pCut0->nLeaves; + for ( i = 0; i < (int)pCut1->nLeaves; i++ ) + { + // try to find this entry among the leaves of pCut0 + for ( k = 0; k < (int)pCut0->nLeaves; k++ ) + if ( pCut1->pLeaves[i] == pCut0->pLeaves[k] ) + break; + if ( k < (int)pCut0->nLeaves ) // found + continue; + // we found a new entry to add + if ( nTotal == Limit ) + return NULL; + pLeaves[nTotal++] = pCut1->pLeaves[i]; + } + // we know that the feasible cut exists + + // add the starting entries + for ( k = 0; k < (int)pCut0->nLeaves; k++ ) + pLeaves[k] = pCut0->pLeaves[k]; + + // selection-sort the entries + for ( i = 0; i < nTotal - 1; i++ ) + { + min = i; + for ( k = i+1; k < nTotal; k++ ) + if ( pLeaves[k] < pLeaves[min] ) + min = k; + NodeTemp = pLeaves[i]; + pLeaves[i] = pLeaves[min]; + pLeaves[min] = NodeTemp; + } + p->pReady->nLeaves = nTotal; + pRes = p->pReady; p->pReady = NULL; + return pRes; +} + +/**Function************************************************************* + + Synopsis [Merges two cuts.] + + Description [This procedure works.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_Cut_t * Cut_CutMergeTwo5( Cut_Man_t * p, Cut_Cut_t * pCut0, Cut_Cut_t * pCut1 ) +{ + static int M[7][3] = {{0},{0},{0},{0},{0},{0},{0}}; + Cut_Cut_t * pRes; + int * pRow; + unsigned uSign0, uSign1; + int i, k, nNodes, Count; + unsigned Limit = p->pParams->nVarsMax; + + assert( pCut0->nLeaves >= pCut1->nLeaves ); + + // the case of the largest cut sizes + if ( pCut0->nLeaves == Limit && pCut1->nLeaves == Limit ) + { + for ( i = 0; i < (int)pCut0->nLeaves; i++ ) + if ( pCut0->pLeaves[i] != pCut1->pLeaves[i] ) + return NULL; + pRes = Cut_CutAlloc( p ); + for ( i = 0; i < (int)pCut0->nLeaves; i++ ) + pRes->pLeaves[i] = pCut0->pLeaves[i]; + pRes->nLeaves = pCut0->nLeaves; + return pRes; + } + // the case when one of the cuts is the largest + if ( pCut0->nLeaves == Limit ) + { + if ( !p->pParams->fTruth ) + { + for ( i = 0; i < (int)pCut1->nLeaves; i++ ) + { + for ( k = pCut0->nLeaves - 1; k >= 0; k-- ) + if ( pCut0->pLeaves[k] == pCut1->pLeaves[i] ) + break; + if ( k == -1 ) // did not find + return NULL; + } + pRes = Cut_CutAlloc( p ); + } + else + { + uSign1 = 0; + for ( i = 0; i < (int)pCut1->nLeaves; i++ ) + { + for ( k = pCut0->nLeaves - 1; k >= 0; k-- ) + if ( pCut0->pLeaves[k] == pCut1->pLeaves[i] ) + { + uSign1 |= (1 << i); + break; + } + if ( k == -1 ) // did not find + return NULL; + } + pRes = Cut_CutAlloc( p ); + pRes->Num1 = uSign1; + } + for ( i = 0; i < (int)pCut0->nLeaves; i++ ) + pRes->pLeaves[i] = pCut0->pLeaves[i]; + pRes->nLeaves = pCut0->nLeaves; + return pRes; + } + // other cases + nNodes = pCut0->nLeaves; + for ( i = 0; i < (int)pCut1->nLeaves; i++ ) + { + for ( k = pCut0->nLeaves - 1; k >= 0; k-- ) + { + if ( pCut0->pLeaves[k] > pCut1->pLeaves[i] ) + continue; + if ( pCut0->pLeaves[k] < pCut1->pLeaves[i] ) + { + pRow = M[k+1]; + if ( pRow[0] == 0 ) + pRow[0] = pCut1->pLeaves[i], pRow[1] = 0; + else if ( pRow[1] == 0 ) + pRow[1] = pCut1->pLeaves[i], pRow[2] = 0; + else if ( pRow[2] == 0 ) + pRow[2] = pCut1->pLeaves[i]; + else + assert( 0 ); + if ( ++nNodes > (int)Limit ) + { + for ( i = 0; i <= (int)pCut0->nLeaves; i++ ) + M[i][0] = 0; + return NULL; + } + } + break; + } + if ( k == -1 ) + { + pRow = M[0]; + if ( pRow[0] == 0 ) + pRow[0] = pCut1->pLeaves[i], pRow[1] = 0; + else if ( pRow[1] == 0 ) + pRow[1] = pCut1->pLeaves[i], pRow[2] = 0; + else if ( pRow[2] == 0 ) + pRow[2] = pCut1->pLeaves[i]; + else + assert( 0 ); + if ( ++nNodes > (int)Limit ) + { + for ( i = 0; i <= (int)pCut0->nLeaves; i++ ) + M[i][0] = 0; + return NULL; + } + continue; + } + } + + pRes = Cut_CutAlloc( p ); + if ( !p->pParams->fTruth ) + { + for ( Count = 0, i = 0; i <= (int)pCut0->nLeaves; i++ ) + { + if ( i > 0 ) + pRes->pLeaves[Count++] = pCut0->pLeaves[i-1]; + pRow = M[i]; + if ( pRow[0] ) + { + pRes->pLeaves[Count++] = pRow[0]; + if ( pRow[1] ) + { + pRes->pLeaves[Count++] = pRow[1]; + if ( pRow[2] ) + pRes->pLeaves[Count++] = pRow[2]; + } + pRow[0] = 0; + } + } + assert( Count == nNodes ); + pRes->nLeaves = nNodes; +/* + // make sure that the cut is correct + { + for ( i = 1; i < (int)pRes->nLeaves; i++ ) + if ( pRes->pLeaves[i-1] >= pRes->pLeaves[i] ) + { + int v = 0; + } + } +*/ + return pRes; + } + + uSign0 = uSign1 = 0; + for ( Count = 0, i = 0; i <= (int)pCut0->nLeaves; i++ ) + { + if ( i > 0 ) + { + uSign0 |= (1 << Count); + pRes->pLeaves[Count++] = pCut1->pLeaves[i-1]; + } + pRow = M[i]; + if ( pRow[0] ) + { + uSign1 |= (1 << Count); + pRes->pLeaves[Count++] = pRow[0]; + if ( pRow[1] ) + { + uSign1 |= (1 << Count); + pRes->pLeaves[Count++] = pRow[1]; + if ( pRow[2] ) + { + uSign1 |= (1 << Count); + pRes->pLeaves[Count++] = pRow[2]; + } + } + pRow[0] = 0; + } + } + assert( Count == nNodes ); + pRes->nLeaves = nNodes; + pRes->Num1 = uSign1; + pRes->Num0 = uSign0; + return pRes; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/cut/cutNode.c b/src/opt/cut/cutNode.c new file mode 100644 index 00000000..1f93b14b --- /dev/null +++ b/src/opt/cut/cutNode.c @@ -0,0 +1,992 @@ +/**CFile**************************************************************** + + FileName [cutNode.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [K-feasible cut computation package.] + + Synopsis [Procedures to compute cuts for a node.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: cutNode.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "cutInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static int Cut_NodeMapping( Cut_Man_t * p, Cut_Cut_t * pCuts, int Node, int Node0, int Node1 ); +static int Cut_NodeMapping2( Cut_Man_t * p, Cut_Cut_t * pCuts, int Node, int Node0, int Node1 ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Returns 1 if pDom is contained in pCut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Cut_CutCheckDominance( Cut_Cut_t * pDom, Cut_Cut_t * pCut ) +{ + int i, k; + for ( i = 0; i < (int)pDom->nLeaves; i++ ) + { + for ( k = 0; k < (int)pCut->nLeaves; k++ ) + if ( pDom->pLeaves[i] == pCut->pLeaves[k] ) + break; + if ( k == (int)pCut->nLeaves ) // node i in pDom is not contained in pCut + return 0; + } + // every node in pDom is contained in pCut + return 1; +} + +/**Function************************************************************* + + Synopsis [Filters cuts using dominance.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Cut_CutFilter( Cut_Man_t * p, Cut_Cut_t * pList ) +{ + Cut_Cut_t * pListR, ** ppListR = &pListR; + Cut_Cut_t * pCut, * pCut2, * pDom, * pPrev; + // save the first cut + *ppListR = pList, ppListR = &pList->pNext; + // try to filter out other cuts + pPrev = pList; + Cut_ListForEachCutSafe( pList->pNext, pCut, pCut2 ) + { + assert( pCut->nLeaves > 1 ); + // go through all the previous cuts up to pCut + Cut_ListForEachCutStop( pList->pNext, pDom, pCut ) + { + if ( pDom->nLeaves > pCut->nLeaves ) + continue; + if ( (pDom->uSign & pCut->uSign) != pDom->uSign ) + continue; + if ( Cut_CutCheckDominance( pDom, pCut ) ) + break; + } + if ( pDom != pCut ) // pDom is contained in pCut - recycle pCut + { + // make sure cuts are connected after removing + pPrev->pNext = pCut->pNext; + // recycle the cut + Cut_CutRecycle( p, pCut ); + } + else // pDom is NOT contained in pCut - save pCut + { + *ppListR = pCut, ppListR = &pCut->pNext; + pPrev = pCut; + } + } + *ppListR = NULL; +} + +/**Function************************************************************* + + Synopsis [Checks equality of one cut.] + + Description [Returns 1 if the cut is removed.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Cut_CutFilterOneEqual( Cut_Man_t * p, Cut_List_t * pSuperList, Cut_Cut_t * pCut ) +{ + Cut_Cut_t * pTemp; + Cut_ListForEachCut( pSuperList->pHead[pCut->nLeaves], pTemp ) + { + // skip the non-contained cuts + if ( pCut->uSign != pTemp->uSign ) + continue; + // check containment seriously + if ( Cut_CutCheckDominance( pTemp, pCut ) ) + { + p->nCutsFilter++; + Cut_CutRecycle( p, pCut ); + return 1; + } + } + return 0; +} + +/**Function************************************************************* + + Synopsis [Checks containment for one cut.] + + Description [Returns 1 if the cut is removed.] + + SideEffects [May remove other cuts in the set.] + + SeeAlso [] + +***********************************************************************/ +static inline int Cut_CutFilterOne( Cut_Man_t * p, Cut_List_t * pSuperList, Cut_Cut_t * pCut ) +{ + Cut_Cut_t * pTemp, * pTemp2, ** ppTail; + int a; + + // check if this cut is filtered out by smaller cuts + for ( a = 2; a <= (int)pCut->nLeaves; a++ ) + { + Cut_ListForEachCut( pSuperList->pHead[a], pTemp ) + { + // skip the non-contained cuts + if ( (pTemp->uSign & pCut->uSign) != pTemp->uSign ) + continue; + // check containment seriously + if ( Cut_CutCheckDominance( pTemp, pCut ) ) + { + p->nCutsFilter++; + Cut_CutRecycle( p, pCut ); + return 1; + } + } + } + + // filter out other cuts using this one + for ( a = pCut->nLeaves + 1; a <= (int)pCut->nVarsMax; a++ ) + { + ppTail = pSuperList->pHead + a; + Cut_ListForEachCutSafe( pSuperList->pHead[a], pTemp, pTemp2 ) + { + // skip the non-contained cuts + if ( (pTemp->uSign & pCut->uSign) != pCut->uSign ) + { + ppTail = &pTemp->pNext; + continue; + } + // check containment seriously + if ( Cut_CutCheckDominance( pCut, pTemp ) ) + { + p->nCutsFilter++; + p->nNodeCuts--; + // move the head + if ( pSuperList->pHead[a] == pTemp ) + pSuperList->pHead[a] = pTemp->pNext; + // move the tail + if ( pSuperList->ppTail[a] == &pTemp->pNext ) + pSuperList->ppTail[a] = ppTail; + // skip the given cut in the list + *ppTail = pTemp->pNext; + // recycle pTemp + Cut_CutRecycle( p, pTemp ); + } + else + ppTail = &pTemp->pNext; + } + assert( ppTail == pSuperList->ppTail[a] ); + assert( *ppTail == NULL ); + } + + return 0; +} + +/**Function************************************************************* + + Synopsis [Checks if the cut is local and can be removed.] + + Description [Returns 1 if the cut is removed.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Cut_CutFilterGlobal( Cut_Man_t * p, Cut_Cut_t * pCut ) +{ + int a; + if ( pCut->nLeaves == 1 ) + return 0; + for ( a = 0; a < (int)pCut->nLeaves; a++ ) + if ( Vec_IntEntry( p->vNodeAttrs, pCut->pLeaves[a] ) ) // global + return 0; + // there is no global nodes, the cut should be removed + p->nCutsFilter++; + Cut_CutRecycle( p, pCut ); + return 1; +} + + +/**Function************************************************************* + + Synopsis [Checks containment for one cut.] + + Description [Returns 1 if the cut is removed.] + + SideEffects [May remove other cuts in the set.] + + SeeAlso [] + +***********************************************************************/ +static inline int Cut_CutFilterOld( Cut_Man_t * p, Cut_Cut_t * pList, Cut_Cut_t * pCut ) +{ + Cut_Cut_t * pPrev, * pTemp, * pTemp2, ** ppTail; + + // check if this cut is filtered out by smaller cuts + pPrev = NULL; + Cut_ListForEachCut( pList, pTemp ) + { + if ( pTemp->nLeaves > pCut->nLeaves ) + break; + pPrev = pTemp; + // skip the non-contained cuts + if ( (pTemp->uSign & pCut->uSign) != pTemp->uSign ) + continue; + // check containment seriously + if ( Cut_CutCheckDominance( pTemp, pCut ) ) + { + p->nCutsFilter++; + Cut_CutRecycle( p, pCut ); + return 1; + } + } + assert( pPrev->pNext == pTemp ); + + // filter out other cuts using this one + ppTail = &pPrev->pNext; + Cut_ListForEachCutSafe( pTemp, pTemp, pTemp2 ) + { + // skip the non-contained cuts + if ( (pTemp->uSign & pCut->uSign) != pCut->uSign ) + { + ppTail = &pTemp->pNext; + continue; + } + // check containment seriously + if ( Cut_CutCheckDominance( pCut, pTemp ) ) + { + p->nCutsFilter++; + p->nNodeCuts--; + // skip the given cut in the list + *ppTail = pTemp->pNext; + // recycle pTemp + Cut_CutRecycle( p, pTemp ); + } + else + ppTail = &pTemp->pNext; + } + assert( *ppTail == NULL ); + return 0; +} + +/**Function************************************************************* + + Synopsis [Processes two cuts.] + + Description [Returns 1 if the limit has been reached.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Cut_CutProcessTwo( Cut_Man_t * p, Cut_Cut_t * pCut0, Cut_Cut_t * pCut1, Cut_List_t * pSuperList ) +{ + Cut_Cut_t * pCut; + // merge the cuts + if ( pCut0->nLeaves >= pCut1->nLeaves ) + pCut = Cut_CutMergeTwo( p, pCut0, pCut1 ); + else + pCut = Cut_CutMergeTwo( p, pCut1, pCut0 ); + if ( pCut == NULL ) + return 0; + assert( p->pParams->fSeq || pCut->nLeaves > 1 ); + // set the signature + pCut->uSign = pCut0->uSign | pCut1->uSign; + if ( p->pParams->fRecord ) + pCut->Num0 = pCut0->Num0, pCut->Num1 = pCut1->Num0; + // check containment + if ( p->pParams->fFilter ) + { + if ( Cut_CutFilterOne(p, pSuperList, pCut) ) +// if ( Cut_CutFilterOneEqual(p, pSuperList, pCut) ) + return 0; + if ( p->pParams->fSeq ) + { + if ( p->pCompareOld && Cut_CutFilterOld(p, p->pCompareOld, pCut) ) + return 0; + if ( p->pCompareNew && Cut_CutFilterOld(p, p->pCompareNew, pCut) ) + return 0; + } + } + + if ( p->pParams->fGlobal ) + { + assert( p->vNodeAttrs != NULL ); + if ( Cut_CutFilterGlobal( p, pCut ) ) + return 0; + } + + // compute the truth table + if ( p->pParams->fTruth ) + Cut_TruthCompute( p, pCut, pCut0, pCut1, p->fCompl0, p->fCompl1 ); + // add to the list + Cut_ListAdd( pSuperList, pCut ); + // return status (0 if okay; 1 if exceeded the limit) + return ++p->nNodeCuts == p->pParams->nKeepMax; +} + +/**Function************************************************************* + + Synopsis [Computes the cuts by merging cuts at two nodes.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_Cut_t * Cut_NodeComputeCuts( Cut_Man_t * p, int Node, int Node0, int Node1, int fCompl0, int fCompl1, int fTriv, int TreeCode ) +{ + Cut_List_t Super, * pSuper = &Super; + Cut_Cut_t * pList, * pCut; + int clk; + // start the number of cuts at the node + p->nNodes++; + p->nNodeCuts = 0; + // prepare information for recording + if ( p->pParams->fRecord ) + { + Cut_CutNumberList( Cut_NodeReadCutsNew(p, Node0) ); + Cut_CutNumberList( Cut_NodeReadCutsNew(p, Node1) ); + } + // compute the cuts +clk = clock(); + Cut_ListStart( pSuper ); + Cut_NodeDoComputeCuts( p, pSuper, Node, fCompl0, fCompl1, Cut_NodeReadCutsNew(p, Node0), Cut_NodeReadCutsNew(p, Node1), fTriv, TreeCode ); + pList = Cut_ListFinish( pSuper ); +p->timeMerge += clock() - clk; + // verify the result of cut computation +// Cut_CutListVerify( pList ); + // performing the recording + if ( p->pParams->fRecord ) + { + Vec_IntWriteEntry( p->vNodeStarts, Node, Vec_IntSize(p->vCutPairs) ); + Cut_ListForEachCut( pList, pCut ) + Vec_IntPush( p->vCutPairs, ((pCut->Num1 << 16) | pCut->Num0) ); + Vec_IntWriteEntry( p->vNodeCuts, Node, Vec_IntSize(p->vCutPairs) - Vec_IntEntry(p->vNodeStarts, Node) ); + } + // check if the node is over the list + if ( p->nNodeCuts == p->pParams->nKeepMax ) + p->nCutsLimit++; + // set the list at the node + Vec_PtrFillExtra( p->vCutsNew, Node + 1, NULL ); + assert( Cut_NodeReadCutsNew(p, Node) == NULL ); + ///// +// pList->pNext = NULL; + ///// + Cut_NodeWriteCutsNew( p, Node, pList ); + // filter the cuts +//clk = clock(); +// if ( p->pParams->fFilter ) +// Cut_CutFilter( p, pList0 ); +//p->timeFilter += clock() - clk; + // perform mapping of this node with these cuts +clk = clock(); + if ( p->pParams->fMap && !p->pParams->fSeq ) + { +// int Delay1, Delay2; +// Delay1 = Cut_NodeMapping( p, pList, Node, Node0, Node1 ); +// Delay2 = Cut_NodeMapping2( p, pList, Node, Node0, Node1 ); +// assert( Delay1 >= Delay2 ); + Cut_NodeMapping( p, pList, Node, Node0, Node1 ); + } +p->timeMap += clock() - clk; + return pList; +} + +/**Function************************************************************* + + Synopsis [Returns optimum delay mapping.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Cut_NodeMapping2( Cut_Man_t * p, Cut_Cut_t * pCuts, int Node, int Node0, int Node1 ) +{ + Cut_Cut_t * pCut; + int DelayMin, DelayCur, i; + if ( pCuts == NULL ) + p->nDelayMin = -1; + if ( p->nDelayMin == -1 ) + return -1; + DelayMin = 1000000; + Cut_ListForEachCut( pCuts, pCut ) + { + if ( pCut->nLeaves == 1 ) + continue; + DelayCur = 0; + for ( i = 0; i < (int)pCut->nLeaves; i++ ) + if ( DelayCur < Vec_IntEntry(p->vDelays, pCut->pLeaves[i]) ) + DelayCur = Vec_IntEntry(p->vDelays, pCut->pLeaves[i]); + if ( DelayMin > DelayCur ) + DelayMin = DelayCur; + } + if ( DelayMin == 1000000 ) + { + p->nDelayMin = -1; + return -1; + } + DelayMin++; + Vec_IntWriteEntry( p->vDelays, Node, DelayMin ); + if ( p->nDelayMin < DelayMin ) + p->nDelayMin = DelayMin; + return DelayMin; +} + +/**Function************************************************************* + + Synopsis [Returns optimum delay mapping using the largest cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Cut_NodeMapping( Cut_Man_t * p, Cut_Cut_t * pCuts, int Node, int Node0, int Node1 ) +{ + Cut_Cut_t * pCut0, * pCut1, * pCut; + int Delay0, Delay1, Delay; + // get the fanin cuts + Delay0 = Vec_IntEntry( p->vDelays2, Node0 ); + Delay1 = Vec_IntEntry( p->vDelays2, Node1 ); + pCut0 = (Delay0 == 0) ? Vec_PtrEntry( p->vCutsNew, Node0 ) : Vec_PtrEntry( p->vCutsMax, Node0 ); + pCut1 = (Delay1 == 0) ? Vec_PtrEntry( p->vCutsNew, Node1 ) : Vec_PtrEntry( p->vCutsMax, Node1 ); + if ( Delay0 == Delay1 ) + Delay = (Delay0 == 0) ? Delay0 + 1: Delay0; + else if ( Delay0 > Delay1 ) + { + Delay = Delay0; + pCut1 = Vec_PtrEntry( p->vCutsNew, Node1 ); + assert( pCut1->nLeaves == 1 ); + } + else // if ( Delay0 < Delay1 ) + { + Delay = Delay1; + pCut0 = Vec_PtrEntry( p->vCutsNew, Node0 ); + assert( pCut0->nLeaves == 1 ); + } + // merge the cuts + if ( pCut0->nLeaves < pCut1->nLeaves ) + pCut = Cut_CutMergeTwo( p, pCut1, pCut0 ); + else + pCut = Cut_CutMergeTwo( p, pCut0, pCut1 ); + if ( pCut == NULL ) + { + Delay++; + pCut = Cut_CutAlloc( p ); + pCut->nLeaves = 2; + pCut->pLeaves[0] = Node0 < Node1 ? Node0 : Node1; + pCut->pLeaves[1] = Node0 < Node1 ? Node1 : Node0; + } + assert( Delay > 0 ); + Vec_IntWriteEntry( p->vDelays2, Node, Delay ); + Vec_PtrWriteEntry( p->vCutsMax, Node, pCut ); + if ( p->nDelayMin < Delay ) + p->nDelayMin = Delay; + return Delay; +} + +/**Function************************************************************* + + Synopsis [Computes area after mapping.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Cut_ManMappingArea_rec( Cut_Man_t * p, int Node ) +{ + Cut_Cut_t * pCut; + int i, Counter; + if ( p->vCutsMax == NULL ) + return 0; + pCut = Vec_PtrEntry( p->vCutsMax, Node ); + if ( pCut == NULL || pCut->nLeaves == 1 ) + return 0; + Counter = 0; + for ( i = 0; i < (int)pCut->nLeaves; i++ ) + Counter += Cut_ManMappingArea_rec( p, pCut->pLeaves[i] ); + Vec_PtrWriteEntry( p->vCutsMax, Node, NULL ); + return 1 + Counter; +} + + +/**Function************************************************************* + + Synopsis [Computes the cuts by merging cuts at two nodes.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_NodeDoComputeCuts( Cut_Man_t * p, Cut_List_t * pSuper, int Node, int fCompl0, int fCompl1, Cut_Cut_t * pList0, Cut_Cut_t * pList1, int fTriv, int TreeCode ) +{ + Cut_Cut_t * pStop0, * pStop1, * pTemp0, * pTemp1, * pStore0, * pStore1; + int i, nCutsOld, Limit; + // start with the elementary cut + if ( fTriv ) + { +// printf( "Creating trivial cut %d.\n", Node ); + pTemp0 = Cut_CutCreateTriv( p, Node ); + Cut_ListAdd( pSuper, pTemp0 ); + p->nNodeCuts++; + } + // get the cut lists of children + if ( pList0 == NULL || pList1 == NULL || (p->pParams->fLocal && TreeCode) ) + return; + + // remember the old number of cuts + nCutsOld = p->nCutsCur; + Limit = p->pParams->nVarsMax; + // get the simultation bit of the node + p->fSimul = (fCompl0 ^ pList0->fSimul) & (fCompl1 ^ pList1->fSimul); + // set temporary variables + p->fCompl0 = fCompl0; + p->fCompl1 = fCompl1; + // if tree cuts are computed, make sure only the unit cuts propagate over the DAG nodes + if ( TreeCode & 1 ) + { + assert( pList0->nLeaves == 1 ); + pStore0 = pList0->pNext; + pList0->pNext = NULL; + } + if ( TreeCode & 2 ) + { + assert( pList1->nLeaves == 1 ); + pStore1 = pList1->pNext; + pList1->pNext = NULL; + } + // find the point in the list where the max-var cuts begin + Cut_ListForEachCut( pList0, pStop0 ) + if ( pStop0->nLeaves == (unsigned)Limit ) + break; + Cut_ListForEachCut( pList1, pStop1 ) + if ( pStop1->nLeaves == (unsigned)Limit ) + break; + + // small by small + Cut_ListForEachCutStop( pList0, pTemp0, pStop0 ) + Cut_ListForEachCutStop( pList1, pTemp1, pStop1 ) + { + if ( Cut_CutProcessTwo( p, pTemp0, pTemp1, pSuper ) ) + goto Quits; + } + // small by large + Cut_ListForEachCutStop( pList0, pTemp0, pStop0 ) + Cut_ListForEachCut( pStop1, pTemp1 ) + { + if ( (pTemp0->uSign & pTemp1->uSign) != pTemp0->uSign ) + continue; + if ( Cut_CutProcessTwo( p, pTemp0, pTemp1, pSuper ) ) + goto Quits; + } + // small by large + Cut_ListForEachCutStop( pList1, pTemp1, pStop1 ) + Cut_ListForEachCut( pStop0, pTemp0 ) + { + if ( (pTemp0->uSign & pTemp1->uSign) != pTemp1->uSign ) + continue; + if ( Cut_CutProcessTwo( p, pTemp0, pTemp1, pSuper ) ) + goto Quits; + } + // large by large + Cut_ListForEachCut( pStop0, pTemp0 ) + Cut_ListForEachCut( pStop1, pTemp1 ) + { + assert( pTemp0->nLeaves == (unsigned)Limit && pTemp1->nLeaves == (unsigned)Limit ); + if ( pTemp0->uSign != pTemp1->uSign ) + continue; + for ( i = 0; i < Limit; i++ ) + if ( pTemp0->pLeaves[i] != pTemp1->pLeaves[i] ) + break; + if ( i < Limit ) + continue; + if ( Cut_CutProcessTwo( p, pTemp0, pTemp1, pSuper ) ) + goto Quits; + } + if ( p->nNodeCuts == 0 ) + p->nNodesNoCuts++; +Quits: + if ( TreeCode & 1 ) + pList0->pNext = pStore0; + if ( TreeCode & 2 ) + pList1->pNext = pStore1; +} + +/**Function************************************************************* + + Synopsis [Computes the cuts by unioning cuts at a choice node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_Cut_t * Cut_NodeUnionCuts( Cut_Man_t * p, Vec_Int_t * vNodes ) +{ + Cut_List_t Super, * pSuper = &Super; + Cut_Cut_t * pList, * pListStart, * pCut, * pCut2, * pTop; + int i, k, Node, Root, Limit = p->pParams->nVarsMax; + int clk = clock(); + + // start the new list + Cut_ListStart( pSuper ); + + // remember the root node to save the resulting cuts + Root = Vec_IntEntry( vNodes, 0 ); + p->nNodeCuts = 1; + + // collect small cuts first + Vec_PtrClear( p->vTemp ); + Vec_IntForEachEntry( vNodes, Node, i ) + { + // get the cuts of this node + pList = Cut_NodeReadCutsNew( p, Node ); + Cut_NodeWriteCutsNew( p, Node, NULL ); + assert( pList ); + // remember the starting point + pListStart = pList->pNext; + pList->pNext = NULL; + // save or recycle the elementary cut + if ( i == 0 ) + Cut_ListAdd( pSuper, pList ), pTop = pList; + else + Cut_CutRecycle( p, pList ); + // save all the cuts that are smaller than the limit + Cut_ListForEachCutSafe( pListStart, pCut, pCut2 ) + { + if ( pCut->nLeaves == (unsigned)Limit ) + { + Vec_PtrPush( p->vTemp, pCut ); + break; + } + // check containment + if ( p->pParams->fFilter && Cut_CutFilterOne( p, pSuper, pCut ) ) + continue; + // set the complemented bit by comparing the first cut with the current cut + pCut->fCompl = pTop->fSimul ^ pCut->fSimul; + pListStart = pCut->pNext; + pCut->pNext = NULL; + // add to the list + Cut_ListAdd( pSuper, pCut ); + if ( ++p->nNodeCuts == p->pParams->nKeepMax ) + { + // recycle the rest of the cuts of this node + Cut_ListForEachCutSafe( pListStart, pCut, pCut2 ) + Cut_CutRecycle( p, pCut ); + // recycle all cuts of other nodes + Vec_IntForEachEntryStart( vNodes, Node, k, i+1 ) + Cut_NodeFreeCuts( p, Node ); + // recycle the saved cuts of other nodes + Vec_PtrForEachEntry( p->vTemp, pList, k ) + Cut_ListForEachCutSafe( pList, pCut, pCut2 ) + Cut_CutRecycle( p, pCut ); + goto finish; + } + } + } + // collect larger cuts next + Vec_PtrForEachEntry( p->vTemp, pList, i ) + { + Cut_ListForEachCutSafe( pList, pCut, pCut2 ) + { + // check containment + if ( p->pParams->fFilter && Cut_CutFilterOne( p, pSuper, pCut ) ) + continue; + // set the complemented bit + pCut->fCompl = pTop->fSimul ^ pCut->fSimul; + pListStart = pCut->pNext; + pCut->pNext = NULL; + // add to the list + Cut_ListAdd( pSuper, pCut ); + if ( ++p->nNodeCuts == p->pParams->nKeepMax ) + { + // recycle the rest of the cuts + Cut_ListForEachCutSafe( pListStart, pCut, pCut2 ) + Cut_CutRecycle( p, pCut ); + // recycle the saved cuts of other nodes + Vec_PtrForEachEntryStart( p->vTemp, pList, k, i+1 ) + Cut_ListForEachCutSafe( pList, pCut, pCut2 ) + Cut_CutRecycle( p, pCut ); + goto finish; + } + } + } +finish : + // set the cuts at the node + assert( Cut_NodeReadCutsNew(p, Root) == NULL ); + pList = Cut_ListFinish( pSuper ); + Cut_NodeWriteCutsNew( p, Root, pList ); +p->timeUnion += clock() - clk; + // filter the cuts +//clk = clock(); +// if ( p->pParams->fFilter ) +// Cut_CutFilter( p, pList ); +//p->timeFilter += clock() - clk; + p->nNodes -= vNodes->nSize - 1; + return pList; +} + +/**Function************************************************************* + + Synopsis [Computes the cuts by unioning cuts at a choice node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_Cut_t * Cut_NodeUnionCutsSeq( Cut_Man_t * p, Vec_Int_t * vNodes, int CutSetNum, int fFirst ) +{ + Cut_List_t Super, * pSuper = &Super; + Cut_Cut_t * pList, * pListStart, * pCut, * pCut2, * pTop; + int i, k, Node, Root, Limit = p->pParams->nVarsMax; + int clk = clock(); + + // start the new list + Cut_ListStart( pSuper ); + + // remember the root node to save the resulting cuts + Root = Vec_IntEntry( vNodes, 0 ); + p->nNodeCuts = 1; + + // store the original lists for comparison + p->pCompareOld = Cut_NodeReadCutsOld( p, Root ); + p->pCompareNew = (CutSetNum >= 0)? Cut_NodeReadCutsNew( p, Root ) : NULL; + + // get the topmost cut + pTop = NULL; + if ( (pTop = Cut_NodeReadCutsOld( p, Root )) == NULL ) + pTop = Cut_NodeReadCutsNew( p, Root ); + assert( pTop != NULL ); + + // collect small cuts first + Vec_PtrClear( p->vTemp ); + Vec_IntForEachEntry( vNodes, Node, i ) + { + // get the cuts of this node + if ( i == 0 && CutSetNum >= 0 ) + { + pList = Cut_NodeReadCutsTemp( p, CutSetNum ); + Cut_NodeWriteCutsTemp( p, CutSetNum, NULL ); + } + else + { + pList = Cut_NodeReadCutsNew( p, Node ); + Cut_NodeWriteCutsNew( p, Node, NULL ); + } + if ( pList == NULL ) + continue; + + // process the cuts + if ( fFirst ) + { + // remember the starting point + pListStart = pList->pNext; + pList->pNext = NULL; + // save or recycle the elementary cut + if ( i == 0 ) + Cut_ListAdd( pSuper, pList ); + else + Cut_CutRecycle( p, pList ); + } + else + pListStart = pList; + + // save all the cuts that are smaller than the limit + Cut_ListForEachCutSafe( pListStart, pCut, pCut2 ) + { + if ( pCut->nLeaves == (unsigned)Limit ) + { + Vec_PtrPush( p->vTemp, pCut ); + break; + } + // check containment +// if ( p->pParams->fFilter && Cut_CutFilterOne( p, pSuper, pCut ) ) +// continue; + if ( p->pParams->fFilter ) + { + if ( Cut_CutFilterOne(p, pSuper, pCut) ) + continue; + if ( p->pParams->fSeq ) + { + if ( p->pCompareOld && Cut_CutFilterOld(p, p->pCompareOld, pCut) ) + continue; + if ( p->pCompareNew && Cut_CutFilterOld(p, p->pCompareNew, pCut) ) + continue; + } + } + + // set the complemented bit by comparing the first cut with the current cut + pCut->fCompl = pTop->fSimul ^ pCut->fSimul; + pListStart = pCut->pNext; + pCut->pNext = NULL; + // add to the list + Cut_ListAdd( pSuper, pCut ); + if ( ++p->nNodeCuts == p->pParams->nKeepMax ) + { + // recycle the rest of the cuts of this node + Cut_ListForEachCutSafe( pListStart, pCut, pCut2 ) + Cut_CutRecycle( p, pCut ); + // recycle all cuts of other nodes + Vec_IntForEachEntryStart( vNodes, Node, k, i+1 ) + Cut_NodeFreeCuts( p, Node ); + // recycle the saved cuts of other nodes + Vec_PtrForEachEntry( p->vTemp, pList, k ) + Cut_ListForEachCutSafe( pList, pCut, pCut2 ) + Cut_CutRecycle( p, pCut ); + goto finish; + } + } + } + // collect larger cuts next + Vec_PtrForEachEntry( p->vTemp, pList, i ) + { + Cut_ListForEachCutSafe( pList, pCut, pCut2 ) + { + // check containment +// if ( p->pParams->fFilter && Cut_CutFilterOne( p, pSuper, pCut ) ) +// continue; + if ( p->pParams->fFilter ) + { + if ( Cut_CutFilterOne(p, pSuper, pCut) ) + continue; + if ( p->pParams->fSeq ) + { + if ( p->pCompareOld && Cut_CutFilterOld(p, p->pCompareOld, pCut) ) + continue; + if ( p->pCompareNew && Cut_CutFilterOld(p, p->pCompareNew, pCut) ) + continue; + } + } + + // set the complemented bit + pCut->fCompl = pTop->fSimul ^ pCut->fSimul; + pListStart = pCut->pNext; + pCut->pNext = NULL; + // add to the list + Cut_ListAdd( pSuper, pCut ); + if ( ++p->nNodeCuts == p->pParams->nKeepMax ) + { + // recycle the rest of the cuts + Cut_ListForEachCutSafe( pListStart, pCut, pCut2 ) + Cut_CutRecycle( p, pCut ); + // recycle the saved cuts of other nodes + Vec_PtrForEachEntryStart( p->vTemp, pList, k, i+1 ) + Cut_ListForEachCutSafe( pList, pCut, pCut2 ) + Cut_CutRecycle( p, pCut ); + goto finish; + } + } + } +finish : + // set the cuts at the node + pList = Cut_ListFinish( pSuper ); + + // set the lists at the node +// assert( Cut_NodeReadCutsNew(p, Root) == NULL ); +// Cut_NodeWriteCutsNew( p, Root, pList ); + if ( CutSetNum >= 0 ) + { + assert( Cut_NodeReadCutsTemp(p, CutSetNum) == NULL ); + Cut_NodeWriteCutsTemp( p, CutSetNum, pList ); + } + else + { + assert( Cut_NodeReadCutsNew(p, Root) == NULL ); + Cut_NodeWriteCutsNew( p, Root, pList ); + } + +p->timeUnion += clock() - clk; + // filter the cuts +//clk = clock(); +// if ( p->pParams->fFilter ) +// Cut_CutFilter( p, pList ); +//p->timeFilter += clock() - clk; +// if ( fFirst ) +// p->nNodes -= vNodes->nSize - 1; + return pList; +} + + +/**Function************************************************************* + + Synopsis [Verifies that the list contains only non-dominated cuts.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Cut_CutListVerify( Cut_Cut_t * pList ) +{ + Cut_Cut_t * pCut, * pDom; + Cut_ListForEachCut( pList, pCut ) + { + Cut_ListForEachCutStop( pList, pDom, pCut ) + { + if ( Cut_CutCheckDominance( pDom, pCut ) ) + { + int x = 0; + printf( "******************* These are contained cuts:\n" ); + Cut_CutPrint( pDom, 1 ); + Cut_CutPrint( pDom, 1 ); + + return 0; + } + } + } + return 1; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/cut/cutOracle.c b/src/opt/cut/cutOracle.c new file mode 100644 index 00000000..3eb4462b --- /dev/null +++ b/src/opt/cut/cutOracle.c @@ -0,0 +1,428 @@ +/**CFile**************************************************************** + + FileName [cutOracle.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [K-feasible cut computation package.] + + Synopsis [Procedures to compute cuts for a node using the oracle.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: cutOracle.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "cutInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +struct Cut_OracleStruct_t_ +{ + // cut comptupatation parameters + Cut_Params_t * pParams; + Vec_Int_t * vFanCounts; + int fSimul; + // storage for cuts + Vec_Ptr_t * vCutsNew; + Vec_Ptr_t * vCuts0; + Vec_Ptr_t * vCuts1; + // oracle info + Vec_Int_t * vNodeCuts; + Vec_Int_t * vNodeStarts; + Vec_Int_t * vCutPairs; + // memory management + Extra_MmFixed_t * pMmCuts; + int EntrySize; + int nTruthWords; + // stats + int timeTotal; + int nCuts; + int nCutsTriv; +}; + +static Cut_Cut_t * Cut_CutStart( Cut_Oracle_t * p ); +static Cut_Cut_t * Cut_CutTriv( Cut_Oracle_t * p, int Node ); +static Cut_Cut_t * Cut_CutMerge( Cut_Oracle_t * p, Cut_Cut_t * pCut0, Cut_Cut_t * pCut1 ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Starts the cut oracle.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_Oracle_t * Cut_OracleStart( Cut_Man_t * pMan ) +{ + Cut_Oracle_t * p; + int clk = clock(); + + assert( pMan->pParams->nVarsMax >= 3 && pMan->pParams->nVarsMax <= CUT_SIZE_MAX ); + assert( pMan->pParams->fRecord ); + + p = ALLOC( Cut_Oracle_t, 1 ); + memset( p, 0, sizeof(Cut_Oracle_t) ); + + // set and correct parameters + p->pParams = pMan->pParams; + + // transfer the recording info + p->vNodeCuts = pMan->vNodeCuts; pMan->vNodeCuts = NULL; + p->vNodeStarts = pMan->vNodeStarts; pMan->vNodeStarts = NULL; + p->vCutPairs = pMan->vCutPairs; pMan->vCutPairs = NULL; + + // prepare storage for cuts + p->vCutsNew = Vec_PtrAlloc( p->pParams->nIdsMax ); + Vec_PtrFill( p->vCutsNew, p->pParams->nIdsMax, NULL ); + p->vCuts0 = Vec_PtrAlloc( 100 ); + p->vCuts1 = Vec_PtrAlloc( 100 ); + + // entry size + p->EntrySize = sizeof(Cut_Cut_t) + p->pParams->nVarsMax * sizeof(int); + if ( p->pParams->fTruth ) + { + if ( p->pParams->nVarsMax > 8 ) + { + p->pParams->fTruth = 0; + printf( "Skipping computation of truth table for more than 8 inputs.\n" ); + } + else + { + p->nTruthWords = Cut_TruthWords( p->pParams->nVarsMax ); + p->EntrySize += p->nTruthWords * sizeof(unsigned); + } + } + // memory for cuts + p->pMmCuts = Extra_MmFixedStart( p->EntrySize ); + return p; +} +/**Function************************************************************* + + Synopsis [Stop the cut oracle.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_OracleStop( Cut_Oracle_t * p ) +{ + Cut_Cut_t * pCut; + int i; + +// if ( p->pParams->fVerbose ) + { + printf( "Cut computation statistics with oracle:\n" ); + printf( "Current cuts = %8d. (Trivial = %d.)\n", p->nCuts-p->nCutsTriv, p->nCutsTriv ); + PRT( "Total time ", p->timeTotal ); + } + + Vec_PtrForEachEntry( p->vCutsNew, pCut, i ) + if ( pCut != NULL ) + { + int k = 0; + } + if ( p->vCuts0 ) Vec_PtrFree( p->vCuts0 ); + if ( p->vCuts1 ) Vec_PtrFree( p->vCuts1 ); + if ( p->vCutsNew ) Vec_PtrFree( p->vCutsNew ); + if ( p->vFanCounts ) Vec_IntFree( p->vFanCounts ); + + if ( p->vNodeCuts ) Vec_IntFree( p->vNodeCuts ); + if ( p->vNodeStarts ) Vec_IntFree( p->vNodeStarts ); + if ( p->vCutPairs ) Vec_IntFree( p->vCutPairs ); + + Extra_MmFixedStop( p->pMmCuts ); + free( p ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_OracleSetFanoutCounts( Cut_Oracle_t * p, Vec_Int_t * vFanCounts ) +{ + p->vFanCounts = vFanCounts; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Cut_OracleReadDrop( Cut_Oracle_t * p ) +{ + return p->pParams->fDrop; +} + +/**Function************************************************************* + + Synopsis [Sets the trivial cut for the node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_OracleNodeSetTriv( Cut_Oracle_t * p, int Node ) +{ + assert( Vec_PtrEntry( p->vCutsNew, Node ) == NULL ); + Vec_PtrWriteEntry( p->vCutsNew, Node, Cut_CutTriv(p, Node) ); +} + + + +/**Function************************************************************* + + Synopsis [Allocates the cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_Cut_t * Cut_CutStart( Cut_Oracle_t * p ) +{ + Cut_Cut_t * pCut; + // cut allocation + pCut = (Cut_Cut_t *)Extra_MmFixedEntryFetch( p->pMmCuts ); + memset( pCut, 0, sizeof(Cut_Cut_t) ); + pCut->nVarsMax = p->pParams->nVarsMax; + pCut->fSimul = p->fSimul; + p->nCuts++; + return pCut; +} + +/**Function************************************************************* + + Synopsis [Creates the trivial cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_Cut_t * Cut_CutTriv( Cut_Oracle_t * p, int Node ) +{ + Cut_Cut_t * pCut; + pCut = Cut_CutStart( p ); + pCut->nLeaves = 1; + pCut->pLeaves[0] = Node; + if ( p->pParams->fTruth ) + { + unsigned * pTruth = Cut_CutReadTruth(pCut); + int i; + for ( i = 0; i < p->nTruthWords; i++ ) + pTruth[i] = 0xAAAAAAAA; + } + p->nCutsTriv++; + return pCut; +} + +/**Function************************************************************* + + Synopsis [Merges two cuts.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_Cut_t * Cut_CutMerge( Cut_Oracle_t * p, Cut_Cut_t * pCut0, Cut_Cut_t * pCut1 ) +{ + Cut_Cut_t * pCut; + int Limit, i, k, c; + // create the leaves of the new cut + pCut = Cut_CutStart( p ); + Limit = p->pParams->nVarsMax; + for ( i = k = c = 0; c < Limit; c++ ) + { + if ( k == (int)pCut1->nLeaves ) + { + if ( i == (int)pCut0->nLeaves ) + { + pCut->nLeaves = c; + return pCut; + } + pCut->pLeaves[c] = pCut0->pLeaves[i++]; + continue; + } + if ( i == (int)pCut0->nLeaves ) + { + if ( k == (int)pCut1->nLeaves ) + { + pCut->nLeaves = c; + return pCut; + } + pCut->pLeaves[c] = pCut1->pLeaves[k++]; + continue; + } + if ( pCut0->pLeaves[i] < pCut1->pLeaves[k] ) + { + pCut->pLeaves[c] = pCut0->pLeaves[i++]; + continue; + } + if ( pCut0->pLeaves[i] > pCut1->pLeaves[k] ) + { + pCut->pLeaves[c] = pCut1->pLeaves[k++]; + continue; + } + pCut->pLeaves[c] = pCut0->pLeaves[i++]; + k++; + } + assert( i == (int)pCut0->nLeaves && k == (int)pCut1->nLeaves ); + pCut->nLeaves = c; + return pCut; +} + +/**Function************************************************************* + + Synopsis [Reconstruct the cuts of the node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_Cut_t * Cut_OracleComputeCuts( Cut_Oracle_t * p, int Node, int Node0, int Node1, int fCompl0, int fCompl1 ) +{ + Cut_Cut_t * pList = NULL, ** ppTail = &pList; + Cut_Cut_t * pCut, * pCut0, * pCut1, * pList0, * pList1; + int iCutStart, nCuts, i, Entry; + int clk = clock(); + + // get the cuts of the children + pList0 = Vec_PtrEntry( p->vCutsNew, Node0 ); + pList1 = Vec_PtrEntry( p->vCutsNew, Node1 ); + assert( pList0 && pList1 ); + + // get the complemented attribute of the cut + p->fSimul = (fCompl0 ^ pList0->fSimul) & (fCompl1 ^ pList1->fSimul); + + // collect the cuts + Vec_PtrClear( p->vCuts0 ); + Cut_ListForEachCut( pList0, pCut ) + Vec_PtrPush( p->vCuts0, pCut ); + Vec_PtrClear( p->vCuts1 ); + Cut_ListForEachCut( pList1, pCut ) + Vec_PtrPush( p->vCuts1, pCut ); + + // get the first and last cuts of this node + nCuts = Vec_IntEntry(p->vNodeCuts, Node); + iCutStart = Vec_IntEntry(p->vNodeStarts, Node); + + // create trivial cut + assert( Vec_IntEntry(p->vCutPairs, iCutStart) == 0 ); + pCut = Cut_CutTriv( p, Node ); + *ppTail = pCut; + ppTail = &pCut->pNext; + // create other cuts + for ( i = 1; i < nCuts; i++ ) + { + Entry = Vec_IntEntry( p->vCutPairs, iCutStart + i ); + pCut0 = Vec_PtrEntry( p->vCuts0, Entry & 0xFFFF ); + pCut1 = Vec_PtrEntry( p->vCuts1, Entry >> 16 ); + pCut = Cut_CutMerge( p, pCut0, pCut1 ); + *ppTail = pCut; + ppTail = &pCut->pNext; + // compute the truth table + if ( p->pParams->fTruth ) + Cut_TruthComputeOld( pCut, pCut0, pCut1, fCompl0, fCompl1 ); + } + *ppTail = NULL; + + // write the new cut + assert( Vec_PtrEntry( p->vCutsNew, Node ) == NULL ); + Vec_PtrWriteEntry( p->vCutsNew, Node, pList ); +p->timeTotal += clock() - clk; + return pList; +} + +/**Function************************************************************* + + Synopsis [Deallocates the cuts at the node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_OracleFreeCuts( Cut_Oracle_t * p, int Node ) +{ + Cut_Cut_t * pList, * pCut, * pCut2; + pList = Vec_PtrEntry( p->vCutsNew, Node ); + if ( pList == NULL ) + return; + Cut_ListForEachCutSafe( pList, pCut, pCut2 ) + Extra_MmFixedEntryRecycle( p->pMmCuts, (char *)pCut ); + Vec_PtrWriteEntry( p->vCutsNew, Node, pList ); +} + +/**Function************************************************************* + + Synopsis [Consider dropping cuts if they are useless by now.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_OracleTryDroppingCuts( Cut_Oracle_t * p, int Node ) +{ + int nFanouts; + assert( p->vFanCounts ); + nFanouts = Vec_IntEntry( p->vFanCounts, Node ); + assert( nFanouts > 0 ); + if ( --nFanouts == 0 ) + Cut_OracleFreeCuts( p, Node ); + Vec_IntWriteEntry( p->vFanCounts, Node, nFanouts ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/cut/cutPre22.c b/src/opt/cut/cutPre22.c new file mode 100644 index 00000000..5cb87a9c --- /dev/null +++ b/src/opt/cut/cutPre22.c @@ -0,0 +1,988 @@ +/**CFile**************************************************************** + + FileName [cutPre22.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Network and node package.] + + Synopsis [Precomputes truth tables for the 2x2 macro cell.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: cutPre22.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "cutInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +#define CUT_CELL_MVAR 9 + +typedef struct Cut_Cell_t_ Cut_Cell_t; +typedef struct Cut_CMan_t_ Cut_CMan_t; + +struct Cut_Cell_t_ +{ + Cut_Cell_t * pNext; // pointer to the next cell in the table + Cut_Cell_t * pNextVar; // pointer to the next cell of this support size + Cut_Cell_t * pParent; // pointer to the cell used to derive this one + int nUsed; // the number of times the cell is used + char Box[4]; // functions in the boxes + unsigned nVars : 4; // the number of variables + unsigned CrossBar0 : 4; // the variable set equal + unsigned CrossBar1 : 4; // the variable set equal + unsigned CrossBarPhase : 2; // the phase of the cross bar (0, 1, or 2) + unsigned CanonPhase : 18; // the canonical phase + char CanonPerm[CUT_CELL_MVAR+3]; // semicanonical permutation + short Store[2*CUT_CELL_MVAR]; // minterm counts in the cofactors + unsigned uTruth[1<<(CUT_CELL_MVAR-5)]; // the current truth table +}; + +struct Cut_CMan_t_ +{ + // storage for canonical cells + Extra_MmFixed_t * pMem; + st_table * tTable; + Cut_Cell_t * pSameVar[CUT_CELL_MVAR+1]; + // elementary truth tables + unsigned uInputs[CUT_CELL_MVAR][1<<(CUT_CELL_MVAR-5)]; + // temporary truth tables + unsigned uTemp1[22][1<<(CUT_CELL_MVAR-5)]; + unsigned uTemp2[22][1<<(CUT_CELL_MVAR-5)]; + unsigned uTemp3[22][1<<(CUT_CELL_MVAR-5)]; + unsigned uFinal[1<<(CUT_CELL_MVAR-5)]; + unsigned puAux[1<<(CUT_CELL_MVAR-5)]; + // statistical variables + int nTotal; + int nGood; + int nVarCounts[CUT_CELL_MVAR+1]; + int nSymGroups[CUT_CELL_MVAR+1]; + int nSymGroupsE[CUT_CELL_MVAR+1]; + int timeCanon; + int timeSupp; + int timeTable; + int nCellFound; + int nCellNotFound; +}; + +// NP-classes of functions of 3 variables (22) +static char * s_NP3[22] = { + " 0\n", // 00 const 0 // 0 vars + " 1\n", // 01 const 1 // 0 vars + "1 1\n", // 02 a // 1 vars + "11 1\n", // 03 ab // 2 vars + "11 0\n", // 04 (ab)' // 2 vars + "10 1\n01 1\n", // 05 a<+>b // 2 vars + "111 1\n", // 06 0s abc // 3 vars + "111 0\n", // 07 (abc)' // + "11- 1\n1-1 1\n", // 08 1p a(b+c) // + "11- 0\n1-1 0\n", // 09 (a(b+c))' // + "111 1\n100 1\n010 1\n001 1\n", // 10 2s a<+>b<+>c // + "10- 0\n1-0 0\n011 0\n", // 11 3p a<+>bc // + "101 1\n110 1\n", // 12 4p a(b<+>c) // + "101 0\n110 0\n", // 13 (a(b<+>c))' // + "11- 1\n1-1 1\n-11 1\n", // 14 5s ab+bc+ac // + "111 1\n000 1\n", // 15 6s abc+a'b'c' // + "111 0\n000 0\n", // 16 (abc+a'b'c')' // + "11- 1\n-11 1\n0-1 1\n", // 17 7 ab+bc+a'c // + "011 1\n101 1\n110 1\n", // 18 8s a'bc+ab'c+abc' // + "011 0\n101 0\n110 0\n", // 19 (a'bc+ab'c+abc')' // + "100 1\n-11 1\n", // 20 9p ab'c'+bc // + "100 0\n-11 0\n" // 21 (ab'c'+bc)' // +}; + +// NP-classes of functions of 3 variables (22) +static char * s_NP3Names[22] = { + " const 0 ", + " const 1 ", + " a ", + " ab ", + " (ab)' ", + " a<+>b ", + "0s abc ", + " (abc)' ", + "1p a(b+c) ", + " (a(b+c))' ", + "2s a<+>b<+>c ", + "3p a<+>bc ", + "4p a(b<+>c) ", + " (a(b<+>c))' ", + "5s ab+bc+ac ", + "6s abc+a'b'c' ", + " (abc+a'b'c')' ", + "7 ab+bc+a'c ", + "8s a'bc+ab'c+abc' ", + " (a'bc+ab'c+abc')' ", + "9p ab'c'+bc ", + " (ab'c'+bc)' " +}; + +// the number of variables in each function +static int s_NP3VarNums[22] = { 0, 0, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }; + +// NPN classes of functions of exactly 3 inputs (10) +static int s_NPNe3[10] = { 6, 8, 10, 11, 12, 14, 15, 17, 18, 20 }; + +// NPN classes of functions of exactly 3 inputs that are symmetric (5) +static int s_NPNe3s[10] = { 6, 10, 14, 15, 18 }; + +// NPN classes of functions of exactly 3 inputs (4) +static int s_NPNe3p[10] = { 8, 11, 12, 20 }; + +static Cut_CMan_t * Cut_CManStart(); +static void Cut_CManStop( Cut_CMan_t * p ); +static void Cut_CellTruthElem( unsigned * InA, unsigned * InB, unsigned * InC, unsigned * pOut, int nVars, int Type ); +static void Cut_CellCanonicize( Cut_CMan_t * p, Cut_Cell_t * pCell ); +static int Cut_CellTableLookup( Cut_CMan_t * p, Cut_Cell_t * pCell ); +static void Cut_CellSuppMin( Cut_Cell_t * pCell ); +static void Cut_CellCrossBar( Cut_Cell_t * pCell ); + + +static Cut_CMan_t * s_pCMan = NULL; + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Start the precomputation manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_CellLoad() +{ + FILE * pFile; + char * pFileName = "cells22_daomap_iwls.txt"; + char pString[1000]; + Cut_CMan_t * p; + Cut_Cell_t * pCell; + int Length; //, i; + pFile = fopen( pFileName, "r" ); + if ( pFile == NULL ) + { + printf( "Cannot open file \"%s\".\n", pFileName ); + return; + } + // start the manager + p = Cut_CManStart(); + // load truth tables + while ( fgets(pString, 1000, pFile) ) + { + Length = strlen(pString); + pString[Length--] = 0; + if ( Length == 0 ) + continue; + // derive the cell + pCell = (Cut_Cell_t *)Extra_MmFixedEntryFetch( p->pMem ); + memset( pCell, 0, sizeof(Cut_Cell_t) ); + pCell->nVars = Extra_Base2Log(Length*4); + pCell->nUsed = 1; +// Extra_TruthCopy( pCell->uTruth, pTruth, nVars ); + Extra_ReadHexadecimal( pCell->uTruth, pString, pCell->nVars ); + Cut_CellSuppMin( pCell ); +/* + // set the elementary permutation + for ( i = 0; i < (int)pCell->nVars; i++ ) + pCell->CanonPerm[i] = i; + // canonicize + pCell->CanonPhase = Extra_TruthSemiCanonicize( pCell->uTruth, p->puAux, pCell->nVars, pCell->CanonPerm, pCell->Store ); +*/ + // add to the table + p->nTotal++; + +// Extra_PrintHexadecimal( stdout, pCell->uTruth, pCell->nVars ); printf( "\n" ); +// if ( p->nTotal == 500 ) +// break; + + if ( !Cut_CellTableLookup( p, pCell ) ) // new cell + p->nGood++; + } + printf( "Read %d cells from file \"%s\". Added %d cells to the table.\n", p->nTotal, pFileName, p->nGood ); + fclose( pFile ); +// return p; +} + +/**Function************************************************************* + + Synopsis [Precomputes truth tables for the 2x2 macro cell.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_CellPrecompute() +{ + Cut_CMan_t * p; + Cut_Cell_t * pCell, * pTemp; + int i1, i2, i3, i, j, k, c, clk = clock(), clk2 = clock(); + + p = Cut_CManStart(); + + // precompute truth tables + for ( i = 0; i < 22; i++ ) + Cut_CellTruthElem( p->uInputs[0], p->uInputs[1], p->uInputs[2], p->uTemp1[i], 9, i ); + for ( i = 0; i < 22; i++ ) + Cut_CellTruthElem( p->uInputs[3], p->uInputs[4], p->uInputs[5], p->uTemp2[i], 9, i ); + for ( i = 0; i < 22; i++ ) + Cut_CellTruthElem( p->uInputs[6], p->uInputs[7], p->uInputs[8], p->uTemp3[i], 9, i ); +/* + if ( k == 8 && ((i1 == 6 && i2 == 14 && i3 == 20) || (i1 == 20 && i2 == 6 && i3 == 14)) ) + { + Extra_PrintBinary( stdout, &pCell->CanonPhase, pCell->nVars+1 ); printf( " : " ); + for ( i = 0; i < pCell->nVars; i++ ) + printf( "%d=%d/%d ", pCell->CanonPerm[i], pCell->Store[2*i], pCell->Store[2*i+1] ); + Extra_PrintHexadecimal( stdout, pCell->uTruth, pCell->nVars ); + printf( "\n" ); + } +*/ +/* + // go through symmetric roots + for ( k = 0; k < 5; k++ ) + for ( i1 = 0; i1 < 22; i1++ ) + for ( i2 = i1; i2 < 22; i2++ ) + for ( i3 = i2; i3 < 22; i3++ ) + { + // derive the cell + pCell = (Cut_Cell_t *)Extra_MmFixedEntryFetch( p->pMem ); + memset( pCell, 0, sizeof(Cut_Cell_t) ); + pCell->nVars = 9; + pCell->Box[0] = s_NPNe3s[k]; + pCell->Box[1] = i1; + pCell->Box[2] = i2; + pCell->Box[3] = i3; + // fill in the truth table + Cut_CellTruthElem( p->uTemp1[i1], p->uTemp2[i2], p->uTemp3[i3], pCell->uTruth, 9, s_NPNe3s[k] ); + // canonicize + Cut_CellCanonicize( pCell ); + + // add to the table + p->nTotal++; + if ( Cut_CellTableLookup( p, pCell ) ) // already exists + Extra_MmFixedEntryRecycle( p->pMem, (char *)pCell ); + else + p->nGood++; + } + + // go through partially symmetric roots + for ( k = 0; k < 4; k++ ) + for ( i1 = 0; i1 < 22; i1++ ) + for ( i2 = 0; i2 < 22; i2++ ) + for ( i3 = i2; i3 < 22; i3++ ) + { + // derive the cell + pCell = (Cut_Cell_t *)Extra_MmFixedEntryFetch( p->pMem ); + memset( pCell, 0, sizeof(Cut_Cell_t) ); + pCell->nVars = 9; + pCell->Box[0] = s_NPNe3p[k]; + pCell->Box[1] = i1; + pCell->Box[2] = i2; + pCell->Box[3] = i3; + // fill in the truth table + Cut_CellTruthElem( p->uTemp1[i1], p->uTemp2[i2], p->uTemp3[i3], pCell->uTruth, 9, s_NPNe3p[k] ); + // canonicize + Cut_CellCanonicize( pCell ); + + // add to the table + p->nTotal++; + if ( Cut_CellTableLookup( p, pCell ) ) // already exists + Extra_MmFixedEntryRecycle( p->pMem, (char *)pCell ); + else + p->nGood++; + } + + // go through non-symmetric functions + for ( i1 = 0; i1 < 22; i1++ ) + for ( i2 = 0; i2 < 22; i2++ ) + for ( i3 = 0; i3 < 22; i3++ ) + { + // derive the cell + pCell = (Cut_Cell_t *)Extra_MmFixedEntryFetch( p->pMem ); + memset( pCell, 0, sizeof(Cut_Cell_t) ); + pCell->nVars = 9; + pCell->Box[0] = 17; + pCell->Box[1] = i1; + pCell->Box[2] = i2; + pCell->Box[3] = i3; + // fill in the truth table + Cut_CellTruthElem( p->uTemp1[i1], p->uTemp2[i2], p->uTemp3[i3], pCell->uTruth, 9, 17 ); + // canonicize + Cut_CellCanonicize( pCell ); + + // add to the table + p->nTotal++; + if ( Cut_CellTableLookup( p, pCell ) ) // already exists + Extra_MmFixedEntryRecycle( p->pMem, (char *)pCell ); + else + p->nGood++; + } +*/ + + // go through non-symmetric functions + for ( k = 0; k < 10; k++ ) + for ( i1 = 0; i1 < 22; i1++ ) + for ( i2 = 0; i2 < 22; i2++ ) + for ( i3 = 0; i3 < 22; i3++ ) + { + // derive the cell + pCell = (Cut_Cell_t *)Extra_MmFixedEntryFetch( p->pMem ); + memset( pCell, 0, sizeof(Cut_Cell_t) ); + pCell->nVars = 9; + pCell->Box[0] = s_NPNe3[k]; + pCell->Box[1] = i1; + pCell->Box[2] = i2; + pCell->Box[3] = i3; + // set the elementary permutation + for ( i = 0; i < (int)pCell->nVars; i++ ) + pCell->CanonPerm[i] = i; + // fill in the truth table + Cut_CellTruthElem( p->uTemp1[i1], p->uTemp2[i2], p->uTemp3[i3], pCell->uTruth, 9, s_NPNe3[k] ); + // minimize the support + Cut_CellSuppMin( pCell ); + + // canonicize + pCell->CanonPhase = Extra_TruthSemiCanonicize( pCell->uTruth, p->puAux, pCell->nVars, pCell->CanonPerm, pCell->Store ); + + // add to the table + p->nTotal++; + if ( Cut_CellTableLookup( p, pCell ) ) // already exists + Extra_MmFixedEntryRecycle( p->pMem, (char *)pCell ); + else + { + p->nGood++; + p->nVarCounts[pCell->nVars]++; + + if ( pCell->nVars ) + for ( i = 0; i < (int)pCell->nVars-1; i++ ) + { + if ( pCell->Store[2*i] != pCell->Store[2*(i+1)] ) // i and i+1 cannot be symmetric + continue; + // i and i+1 can be symmetric + // find the end of this group + for ( j = i+1; j < (int)pCell->nVars; j++ ) + if ( pCell->Store[2*i] != pCell->Store[2*j] ) + break; + + if ( pCell->Store[2*i] == pCell->Store[2*i+1] ) + p->nSymGroupsE[j-i]++; + else + p->nSymGroups[j-i]++; + i = j - 1; + } +/* + if ( pCell->nVars == 3 ) + { + Extra_PrintBinary( stdout, pCell->uTruth, 32 ); printf( "\n" ); + for ( i = 0; i < (int)pCell->nVars; i++ ) + printf( "%d=%d/%d ", pCell->CanonPerm[i], pCell->Store[2*i], pCell->Store[2*i+1] ); + printf( "\n" ); + } +*/ + } + } + + printf( "BASIC: Total = %d. Good = %d. Entry = %d. ", p->nTotal, p->nGood, sizeof(Cut_Cell_t) ); + PRT( "Time", clock() - clk ); + printf( "Cells: " ); + for ( i = 0; i <= 9; i++ ) + printf( "%d=%d ", i, p->nVarCounts[i] ); + printf( "\nDiffs: " ); + for ( i = 0; i <= 9; i++ ) + printf( "%d=%d ", i, p->nSymGroups[i] ); + printf( "\nEquals: " ); + for ( i = 0; i <= 9; i++ ) + printf( "%d=%d ", i, p->nSymGroupsE[i] ); + printf( "\n" ); + + // continue adding new cells using support + for ( k = CUT_CELL_MVAR; k > 3; k-- ) + { + for ( pTemp = p->pSameVar[k]; pTemp; pTemp = pTemp->pNextVar ) + for ( i1 = 0; i1 < k; i1++ ) + for ( i2 = i1+1; i2 < k; i2++ ) + for ( c = 0; c < 3; c++ ) + { + // derive the cell + pCell = (Cut_Cell_t *)Extra_MmFixedEntryFetch( p->pMem ); + memset( pCell, 0, sizeof(Cut_Cell_t) ); + pCell->nVars = pTemp->nVars; + pCell->pParent = pTemp; + // set the elementary permutation + for ( i = 0; i < (int)pCell->nVars; i++ ) + pCell->CanonPerm[i] = i; + // fill in the truth table + Extra_TruthCopy( pCell->uTruth, pTemp->uTruth, pTemp->nVars ); + // create the cross-bar + pCell->CrossBar0 = i1; + pCell->CrossBar1 = i2; + pCell->CrossBarPhase = c; + Cut_CellCrossBar( pCell ); + // minimize the support +//clk2 = clock(); + Cut_CellSuppMin( pCell ); +//p->timeSupp += clock() - clk2; + // canonicize +//clk2 = clock(); + pCell->CanonPhase = Extra_TruthSemiCanonicize( pCell->uTruth, p->puAux, pCell->nVars, pCell->CanonPerm, pCell->Store ); +//p->timeCanon += clock() - clk2; + + // add to the table +//clk2 = clock(); + p->nTotal++; + if ( Cut_CellTableLookup( p, pCell ) ) // already exists + Extra_MmFixedEntryRecycle( p->pMem, (char *)pCell ); + else + { + p->nGood++; + p->nVarCounts[pCell->nVars]++; + + for ( i = 0; i < (int)pCell->nVars-1; i++ ) + { + if ( pCell->Store[2*i] != pCell->Store[2*(i+1)] ) // i and i+1 cannot be symmetric + continue; + // i and i+1 can be symmetric + // find the end of this group + for ( j = i+1; j < (int)pCell->nVars; j++ ) + if ( pCell->Store[2*i] != pCell->Store[2*j] ) + break; + + if ( pCell->Store[2*i] == pCell->Store[2*i+1] ) + p->nSymGroupsE[j-i]++; + else + p->nSymGroups[j-i]++; + i = j - 1; + } +/* + if ( pCell->nVars == 3 ) + { + Extra_PrintBinary( stdout, pCell->uTruth, 32 ); printf( "\n" ); + for ( i = 0; i < (int)pCell->nVars; i++ ) + printf( "%d=%d/%d ", pCell->CanonPerm[i], pCell->Store[2*i], pCell->Store[2*i+1] ); + printf( "\n" ); + } +*/ + } +//p->timeTable += clock() - clk2; + } + + printf( "VAR %d: Total = %d. Good = %d. Entry = %d. ", k, p->nTotal, p->nGood, sizeof(Cut_Cell_t) ); + PRT( "Time", clock() - clk ); + printf( "Cells: " ); + for ( i = 0; i <= 9; i++ ) + printf( "%d=%d ", i, p->nVarCounts[i] ); + printf( "\nDiffs: " ); + for ( i = 0; i <= 9; i++ ) + printf( "%d=%d ", i, p->nSymGroups[i] ); + printf( "\nEquals: " ); + for ( i = 0; i <= 9; i++ ) + printf( "%d=%d ", i, p->nSymGroupsE[i] ); + printf( "\n" ); + } +// printf( "\n" ); + PRT( "Supp ", p->timeSupp ); + PRT( "Canon", p->timeCanon ); + PRT( "Table", p->timeTable ); +// Cut_CManStop( p ); +} + +/**Function************************************************************* + + Synopsis [Check the table.] + + Description [Returns 1 if such a truth table already exists.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Cut_CellTableLookup( Cut_CMan_t * p, Cut_Cell_t * pCell ) +{ + Cut_Cell_t ** pSlot, * pTemp; + unsigned Hash; + Hash = Extra_TruthHash( pCell->uTruth, Extra_TruthWordNum( pCell->nVars ) ); + if ( !st_find_or_add( p->tTable, (char *)Hash, (char ***)&pSlot ) ) + *pSlot = NULL; + for ( pTemp = *pSlot; pTemp; pTemp = pTemp->pNext ) + { + if ( pTemp->nVars != pCell->nVars ) + continue; + if ( Extra_TruthIsEqual(pTemp->uTruth, pCell->uTruth, pCell->nVars) ) + return 1; + } + // the entry is new + pCell->pNext = *pSlot; + *pSlot = pCell; + // add it to the variable support list + pCell->pNextVar = p->pSameVar[pCell->nVars]; + p->pSameVar[pCell->nVars] = pCell; + return 0; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_CellSuppMin( Cut_Cell_t * pCell ) +{ + static unsigned uTemp[1<<(CUT_CELL_MVAR-5)]; + unsigned * pIn, * pOut, * pTemp; + int i, k, Counter, Temp; + + // go backward through the support variables and remove redundant + for ( k = pCell->nVars - 1; k >= 0; k-- ) + if ( !Extra_TruthVarInSupport(pCell->uTruth, pCell->nVars, k) ) + { + // shift all the variables above this one + Counter = 0; + pIn = pCell->uTruth; pOut = uTemp; + for ( i = k; i < (int)pCell->nVars - 1; i++ ) + { + Extra_TruthSwapAdjacentVars( pOut, pIn, pCell->nVars, i ); + pTemp = pIn; pIn = pOut; pOut = pTemp; + // swap the support vars + Temp = pCell->CanonPerm[i]; + pCell->CanonPerm[i] = pCell->CanonPerm[i+1]; + pCell->CanonPerm[i+1] = Temp; + Counter++; + } + // return the function back into its place + if ( Counter & 1 ) + Extra_TruthCopy( pOut, pIn, pCell->nVars ); + // remove one variable + pCell->nVars--; +// Extra_PrintBinary( stdout, pCell->uTruth, (1<nVars) ); printf( "\n" ); + } +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_CellCrossBar( Cut_Cell_t * pCell ) +{ + static unsigned uTemp0[1<<(CUT_CELL_MVAR-5)]; + static unsigned uTemp1[1<<(CUT_CELL_MVAR-5)]; + Extra_TruthCopy( uTemp0, pCell->uTruth, pCell->nVars ); + Extra_TruthCopy( uTemp1, pCell->uTruth, pCell->nVars ); + if ( pCell->CanonPhase == 0 ) + { + Extra_TruthCofactor0( uTemp0, pCell->nVars, pCell->CrossBar0 ); + Extra_TruthCofactor0( uTemp0, pCell->nVars, pCell->CrossBar1 ); + Extra_TruthCofactor1( uTemp1, pCell->nVars, pCell->CrossBar0 ); + Extra_TruthCofactor1( uTemp1, pCell->nVars, pCell->CrossBar1 ); + } + else if ( pCell->CanonPhase == 1 ) + { + Extra_TruthCofactor1( uTemp0, pCell->nVars, pCell->CrossBar0 ); + Extra_TruthCofactor0( uTemp0, pCell->nVars, pCell->CrossBar1 ); + Extra_TruthCofactor0( uTemp1, pCell->nVars, pCell->CrossBar0 ); + Extra_TruthCofactor1( uTemp1, pCell->nVars, pCell->CrossBar1 ); + } + else if ( pCell->CanonPhase == 2 ) + { + Extra_TruthCofactor0( uTemp0, pCell->nVars, pCell->CrossBar0 ); + Extra_TruthCofactor1( uTemp0, pCell->nVars, pCell->CrossBar1 ); + Extra_TruthCofactor1( uTemp1, pCell->nVars, pCell->CrossBar0 ); + Extra_TruthCofactor0( uTemp1, pCell->nVars, pCell->CrossBar1 ); + } + else assert( 0 ); + Extra_TruthMux( pCell->uTruth, uTemp0, uTemp1, pCell->nVars, pCell->CrossBar0 ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_CellTruthElem( unsigned * InA, unsigned * InB, unsigned * InC, unsigned * pOut, int nVars, int Type ) +{ + int nWords = Extra_TruthWordNum( nVars ); + int i; + + assert( Type < 22 ); + switch ( Type ) + { + // " 0\n", // 00 const 0 + case 0: + for ( i = 0; i < nWords; i++ ) + pOut[i] = 0; + return; + // " 1\n", // 01 const 1 + case 1: + for ( i = 0; i < nWords; i++ ) + pOut[i] = 0xFFFFFFFF; + return; + // "1 1\n", // 02 a + case 2: + for ( i = 0; i < nWords; i++ ) + pOut[i] = InA[i]; + return; + // "11 1\n", // 03 ab + case 3: + for ( i = 0; i < nWords; i++ ) + pOut[i] = InA[i] & InB[i]; + return; + // "11 0\n", // 04 (ab)' + case 4: + for ( i = 0; i < nWords; i++ ) + pOut[i] = ~(InA[i] & InB[i]); + return; + // "10 1\n01 1\n", // 05 a<+>b + case 5: + for ( i = 0; i < nWords; i++ ) + pOut[i] = InA[i] ^ InB[i]; + return; + // "111 1\n", // 06 + abc + case 6: + for ( i = 0; i < nWords; i++ ) + pOut[i] = InA[i] & InB[i] & InC[i]; + return; + // "111 0\n", // 07 (abc)' + case 7: + for ( i = 0; i < nWords; i++ ) + pOut[i] = ~(InA[i] & InB[i] & InC[i]); + return; + // "11- 1\n1-1 1\n", // 08 + a(b+c) + case 8: + for ( i = 0; i < nWords; i++ ) + pOut[i] = InA[i] & (InB[i] | InC[i]); + return; + // "11- 0\n1-1 0\n", // 09 (a(b+c))' + case 9: + for ( i = 0; i < nWords; i++ ) + pOut[i] = ~(InA[i] & (InB[i] | InC[i])); + return; + // "111 1\n100 1\n010 1\n001 1\n", // 10 + a<+>b<+>c + case 10: + for ( i = 0; i < nWords; i++ ) + pOut[i] = InA[i] ^ InB[i] ^ InC[i]; + return; + // "10- 0\n1-0 0\n011 0\n", // 11 + a<+>bc + case 11: + for ( i = 0; i < nWords; i++ ) + pOut[i] = InA[i] ^ (InB[i] & InC[i]); + return; + // "101 1\n110 1\n", // 12 + a(b<+>c) + case 12: + for ( i = 0; i < nWords; i++ ) + pOut[i] = InA[i] & (InB[i] ^ InC[i]); + return; + // "101 0\n110 0\n", // 13 (a(b<+>c))' + case 13: + for ( i = 0; i < nWords; i++ ) + pOut[i] = ~(InA[i] & (InB[i] ^ InC[i])); + return; + // "11- 1\n1-1 1\n-11 1\n", // 14 + ab+bc+ac + case 14: + for ( i = 0; i < nWords; i++ ) + pOut[i] = (InA[i] & InB[i]) | (InB[i] & InC[i]) | (InA[i] & InC[i]); + return; + // "111 1\n000 1\n", // 15 + abc+a'b'c' + case 15: + for ( i = 0; i < nWords; i++ ) + pOut[i] = (InA[i] & InB[i] & InC[i]) | (~InA[i] & ~InB[i] & ~InC[i]); + return; + // "111 0\n000 0\n", // 16 (abc+a'b'c')' + case 16: + for ( i = 0; i < nWords; i++ ) + pOut[i] = ~((InA[i] & InB[i] & InC[i]) | (~InA[i] & ~InB[i] & ~InC[i])); + return; + // "11- 1\n-11 1\n0-1 1\n", // 17 + ab+bc+a'c + case 17: + for ( i = 0; i < nWords; i++ ) + pOut[i] = (InA[i] & InB[i]) | (InB[i] & InC[i]) | (~InA[i] & InC[i]); + return; + // "011 1\n101 1\n110 1\n", // 18 + a'bc+ab'c+abc' + case 18: + for ( i = 0; i < nWords; i++ ) + pOut[i] = (~InA[i] & InB[i] & InC[i]) | (InA[i] & ~InB[i] & InC[i]) | (InA[i] & InB[i] & ~InC[i]); + return; + // "011 0\n101 0\n110 0\n", // 19 (a'bc+ab'c+abc')' + case 19: + for ( i = 0; i < nWords; i++ ) + pOut[i] = ~((~InA[i] & InB[i] & InC[i]) | (InA[i] & ~InB[i] & InC[i]) | (InA[i] & InB[i] & ~InC[i])); + return; + // "100 1\n-11 1\n", // 20 + ab'c'+bc + case 20: + for ( i = 0; i < nWords; i++ ) + pOut[i] = (InA[i] & ~InB[i] & ~InC[i]) | (InB[i] & InC[i]); + return; + // "100 0\n-11 0\n" // 21 (ab'c'+bc)' + case 21: + for ( i = 0; i < nWords; i++ ) + pOut[i] = ~((InA[i] & ~InB[i] & ~InC[i]) | (InB[i] & InC[i])); + return; + } +} + + +/**Function************************************************************* + + Synopsis [Start the precomputation manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_CMan_t * Cut_CManStart() +{ + Cut_CMan_t * p; + int i, k; + // start the manager + assert( sizeof(unsigned) == 4 ); + p = ALLOC( Cut_CMan_t, 1 ); + memset( p, 0, sizeof(Cut_CMan_t) ); + // start the table and the memory manager + p->tTable = st_init_table(st_ptrcmp,st_ptrhash); + p->pMem = Extra_MmFixedStart( sizeof(Cut_Cell_t) ); + // set elementary truth tables + for ( k = 0; k < CUT_CELL_MVAR; k++ ) + for ( i = 0; i < (1<uInputs[k][i>>5] |= (1 << (i&31)); + s_pCMan = p; + return p; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_CManStop( Cut_CMan_t * p ) +{ + st_free_table( p->tTable ); + Extra_MmFixedStop( p->pMem ); + free( p ); +} +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Cut_CellIsRunning() +{ + return s_pCMan != NULL; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_CellDumpToFile() +{ + FILE * pFile; + Cut_CMan_t * p = s_pCMan; + Cut_Cell_t * pTemp; + char * pFileName = "celllib22.txt"; + int NumUsed[10][5] = {{0}}; + int BoxUsed[22][5] = {{0}}; + int i, k, Counter; + int clk = clock(); + + if ( p == NULL ) + { + printf( "Cut_CellDumpToFile: Cell manager is not defined.\n" ); + return; + } + + // count the number of cells used + for ( k = CUT_CELL_MVAR; k >= 0; k-- ) + { + for ( pTemp = p->pSameVar[k]; pTemp; pTemp = pTemp->pNextVar ) + { + if ( pTemp->nUsed == 0 ) + NumUsed[k][0]++; + else if ( pTemp->nUsed < 10 ) + NumUsed[k][1]++; + else if ( pTemp->nUsed < 100 ) + NumUsed[k][2]++; + else if ( pTemp->nUsed < 1000 ) + NumUsed[k][3]++; + else + NumUsed[k][4]++; + + for ( i = 0; i < 4; i++ ) + if ( pTemp->nUsed == 0 ) + BoxUsed[ pTemp->Box[i] ][0]++; + else if ( pTemp->nUsed < 10 ) + BoxUsed[ pTemp->Box[i] ][1]++; + else if ( pTemp->nUsed < 100 ) + BoxUsed[ pTemp->Box[i] ][2]++; + else if ( pTemp->nUsed < 1000 ) + BoxUsed[ pTemp->Box[i] ][3]++; + else + BoxUsed[ pTemp->Box[i] ][4]++; + } + } + + printf( "Functions found = %10d. Functions not found = %10d.\n", p->nCellFound, p->nCellNotFound ); + for ( k = 0; k <= CUT_CELL_MVAR; k++ ) + { + printf( "%3d : ", k ); + for ( i = 0; i < 5; i++ ) + printf( "%8d ", NumUsed[k][i] ); + printf( "\n" ); + } + printf( "Box usage:\n" ); + for ( k = 0; k < 22; k++ ) + { + printf( "%3d : ", k ); + for ( i = 0; i < 5; i++ ) + printf( "%8d ", BoxUsed[k][i] ); + printf( " %s", s_NP3Names[k] ); + printf( "\n" ); + } + + pFile = fopen( pFileName, "w" ); + if ( pFile == NULL ) + { + printf( "Cut_CellDumpToFile: Cannout open output file.\n" ); + return; + } + + Counter = 0; + for ( k = 0; k <= CUT_CELL_MVAR; k++ ) + { + for ( pTemp = p->pSameVar[k]; pTemp; pTemp = pTemp->pNextVar ) + if ( pTemp->nUsed > 0 ) + { + Extra_PrintHexadecimal( pFile, pTemp->uTruth, (k <= 5? 5 : k) ); + fprintf( pFile, "\n" ); + Counter++; + } + fprintf( pFile, "\n" ); + } + fclose( pFile ); + + printf( "Library composed of %d functions is written into file \"%s\". ", Counter, pFileName ); + + PRT( "Time", clock() - clk ); +} + + +/**Function************************************************************* + + Synopsis [Looks up if the given function exists in the hash table.] + + Description [If the function exists, returns 1, meaning that it can be + implemented using two levels of 3-input LUTs. If the function does not + exist, return 0.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Cut_CellTruthLookup( unsigned * pTruth, int nVars ) +{ + Cut_CMan_t * p = s_pCMan; + Cut_Cell_t * pTemp; + Cut_Cell_t Cell, * pCell = &Cell; + unsigned Hash; + int i; + + // cell manager is not defined + if ( p == NULL ) + { + printf( "Cut_CellTruthLookup: Cell manager is not defined.\n" ); + return 0; + } + + // canonicize + memset( pCell, 0, sizeof(Cut_Cell_t) ); + pCell->nVars = nVars; + Extra_TruthCopy( pCell->uTruth, pTruth, nVars ); + Cut_CellSuppMin( pCell ); + // set the elementary permutation + for ( i = 0; i < (int)pCell->nVars; i++ ) + pCell->CanonPerm[i] = i; + // canonicize + pCell->CanonPhase = Extra_TruthSemiCanonicize( pCell->uTruth, p->puAux, pCell->nVars, pCell->CanonPerm, pCell->Store ); + + + // check if the cell exists + Hash = Extra_TruthHash( pCell->uTruth, Extra_TruthWordNum(pCell->nVars) ); + if ( st_lookup( p->tTable, (char *)Hash, (char **)&pTemp ) ) + { + for ( ; pTemp; pTemp = pTemp->pNext ) + { + if ( pTemp->nVars != pCell->nVars ) + continue; + if ( Extra_TruthIsEqual(pTemp->uTruth, pCell->uTruth, pCell->nVars) ) + { + pTemp->nUsed++; + p->nCellFound++; + return 1; + } + } + } + p->nCellNotFound++; + return 0; +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/cut/cutSeq.c b/src/opt/cut/cutSeq.c new file mode 100644 index 00000000..d36f94f7 --- /dev/null +++ b/src/opt/cut/cutSeq.c @@ -0,0 +1,227 @@ +/**CFile**************************************************************** + + FileName [cutSeq.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [K-feasible cut computation package.] + + Synopsis [Sequential cut computation.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: cutSeq.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "cutInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Shifts all cut leaves of the node by the given number of latches.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Cut_NodeShiftCutLeaves( Cut_Cut_t * pList, int nLat ) +{ + Cut_Cut_t * pTemp; + int i; + // shift the cuts by as many latches + Cut_ListForEachCut( pList, pTemp ) + { + pTemp->uSign = 0; + for ( i = 0; i < (int)pTemp->nLeaves; i++ ) + { + pTemp->pLeaves[i] += nLat; + pTemp->uSign |= Cut_NodeSign( pTemp->pLeaves[i] ); + } + } +} + +/**Function************************************************************* + + Synopsis [Computes sequential cuts for the node from its fanins.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_NodeComputeCutsSeq( Cut_Man_t * p, int Node, int Node0, int Node1, int fCompl0, int fCompl1, int nLat0, int nLat1, int fTriv, int CutSetNum ) +{ + Cut_List_t Super, * pSuper = &Super; + Cut_Cut_t * pListNew; + int clk; + + // get the number of cuts at the node + p->nNodeCuts = Cut_CutCountList( Cut_NodeReadCutsOld(p, Node) ); + if ( p->nNodeCuts >= p->pParams->nKeepMax ) + return; + + // count only the first visit + if ( p->nNodeCuts == 0 ) + p->nNodes++; + + // store the fanin lists + p->pStore0[0] = Cut_NodeReadCutsOld( p, Node0 ); + p->pStore0[1] = Cut_NodeReadCutsNew( p, Node0 ); + p->pStore1[0] = Cut_NodeReadCutsOld( p, Node1 ); + p->pStore1[1] = Cut_NodeReadCutsNew( p, Node1 ); + + // duplicate the cut lists if fanin nodes are non-standard + if ( Node == Node0 || Node == Node1 || Node0 == Node1 ) + { + p->pStore0[0] = Cut_CutDupList( p, p->pStore0[0] ); + p->pStore0[1] = Cut_CutDupList( p, p->pStore0[1] ); + p->pStore1[0] = Cut_CutDupList( p, p->pStore1[0] ); + p->pStore1[1] = Cut_CutDupList( p, p->pStore1[1] ); + } + + // shift the cuts by as many latches and recompute signatures + if ( nLat0 ) Cut_NodeShiftCutLeaves( p->pStore0[0], nLat0 ); + if ( nLat0 ) Cut_NodeShiftCutLeaves( p->pStore0[1], nLat0 ); + if ( nLat1 ) Cut_NodeShiftCutLeaves( p->pStore1[0], nLat1 ); + if ( nLat1 ) Cut_NodeShiftCutLeaves( p->pStore1[1], nLat1 ); + + // store the original lists for comparison + p->pCompareOld = Cut_NodeReadCutsOld( p, Node ); + p->pCompareNew = Cut_NodeReadCutsNew( p, Node ); + + // merge the old and the new +clk = clock(); + Cut_ListStart( pSuper ); + Cut_NodeDoComputeCuts( p, pSuper, Node, fCompl0, fCompl1, p->pStore0[0], p->pStore1[1], 0, 0 ); + Cut_NodeDoComputeCuts( p, pSuper, Node, fCompl0, fCompl1, p->pStore0[1], p->pStore1[0], 0, 0 ); + Cut_NodeDoComputeCuts( p, pSuper, Node, fCompl0, fCompl1, p->pStore0[1], p->pStore1[1], fTriv, 0 ); + pListNew = Cut_ListFinish( pSuper ); +p->timeMerge += clock() - clk; + + // shift the cuts by as many latches and recompute signatures + if ( Node == Node0 || Node == Node1 || Node0 == Node1 ) + { + Cut_CutRecycleList( p, p->pStore0[0] ); + Cut_CutRecycleList( p, p->pStore0[1] ); + Cut_CutRecycleList( p, p->pStore1[0] ); + Cut_CutRecycleList( p, p->pStore1[1] ); + } + else + { + if ( nLat0 ) Cut_NodeShiftCutLeaves( p->pStore0[0], -nLat0 ); + if ( nLat0 ) Cut_NodeShiftCutLeaves( p->pStore0[1], -nLat0 ); + if ( nLat1 ) Cut_NodeShiftCutLeaves( p->pStore1[0], -nLat1 ); + if ( nLat1 ) Cut_NodeShiftCutLeaves( p->pStore1[1], -nLat1 ); + } + + // set the lists at the node + if ( CutSetNum >= 0 ) + { + assert( Cut_NodeReadCutsTemp(p, CutSetNum) == NULL ); + Cut_NodeWriteCutsTemp( p, CutSetNum, pListNew ); + } + else + { + assert( Cut_NodeReadCutsNew(p, Node) == NULL ); + Cut_NodeWriteCutsNew( p, Node, pListNew ); + } + + // mark the node if we exceeded the number of cuts + if ( p->nNodeCuts >= p->pParams->nKeepMax ) + p->nCutsLimit++; +} + +/**Function************************************************************* + + Synopsis [Merges the new cuts with the old cuts.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_NodeNewMergeWithOld( Cut_Man_t * p, int Node ) +{ + Cut_Cut_t * pListOld, * pListNew, * pList; + // get the new cuts + pListNew = Cut_NodeReadCutsNew( p, Node ); + if ( pListNew == NULL ) + return; + Cut_NodeWriteCutsNew( p, Node, NULL ); + // get the old cuts + pListOld = Cut_NodeReadCutsOld( p, Node ); + if ( pListOld == NULL ) + { + Cut_NodeWriteCutsOld( p, Node, pListNew ); + return; + } + // merge the lists + pList = Cut_CutMergeLists( pListOld, pListNew ); + Cut_NodeWriteCutsOld( p, Node, pList ); +} + + +/**Function************************************************************* + + Synopsis [Transfers the temporary cuts to be the new cuts.] + + Description [Returns 1 if something was transferred.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Cut_NodeTempTransferToNew( Cut_Man_t * p, int Node, int CutSetNum ) +{ + Cut_Cut_t * pList; + pList = Cut_NodeReadCutsTemp( p, CutSetNum ); + Cut_NodeWriteCutsTemp( p, CutSetNum, NULL ); + Cut_NodeWriteCutsNew( p, Node, pList ); + return pList != NULL; +} + +/**Function************************************************************* + + Synopsis [Transfers the old cuts to be the new cuts.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_NodeOldTransferToNew( Cut_Man_t * p, int Node ) +{ + Cut_Cut_t * pList; + pList = Cut_NodeReadCutsOld( p, Node ); + Cut_NodeWriteCutsOld( p, Node, NULL ); + Cut_NodeWriteCutsNew( p, Node, pList ); +// Cut_CutListVerify( pList ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/cut/cutTruth.c b/src/opt/cut/cutTruth.c new file mode 100644 index 00000000..c3514ad7 --- /dev/null +++ b/src/opt/cut/cutTruth.c @@ -0,0 +1,226 @@ +/**CFile**************************************************************** + + FileName [cutTruth.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [K-feasible cut computation package.] + + Synopsis [Incremental truth table computation.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: cutTruth.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "cutInt.h" + +/* + Truth tables computed in this package are represented as bit-strings + stored in the cut data structure. Cuts of any number of inputs have + the truth table with 2^k bits, where k is the max number of cut inputs. +*/ + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +extern int nTotal = 0; +extern int nGood = 0; +extern int nEqual = 0; + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Computes the stretching phase of the cut w.r.t. the merged cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline unsigned Cut_TruthPhase( Cut_Cut_t * pCut, Cut_Cut_t * pCut1 ) +{ + unsigned uPhase = 0; + int i, k; + for ( i = k = 0; i < (int)pCut->nLeaves; i++ ) + { + if ( k == (int)pCut1->nLeaves ) + break; + if ( pCut->pLeaves[i] < pCut1->pLeaves[k] ) + continue; + assert( pCut->pLeaves[i] == pCut1->pLeaves[k] ); + uPhase |= (1 << i); + k++; + } + return uPhase; +} + +/**Function************************************************************* + + Synopsis [Performs truth table computation.] + + Description [This procedure cannot be used while recording oracle + because it will overwrite Num0 and Num1.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_TruthNCanonicize( Cut_Cut_t * pCut ) +{ + unsigned uTruth; + unsigned * uCanon2; + char * pPhases2; + assert( pCut->nVarsMax < 6 ); + + // get the direct truth table + uTruth = *Cut_CutReadTruth(pCut); + + // compute the direct truth table + Extra_TruthCanonFastN( pCut->nVarsMax, pCut->nLeaves, &uTruth, &uCanon2, &pPhases2 ); +// uCanon[0] = uCanon2[0]; +// uCanon[1] = (p->nVarsMax == 6)? uCanon2[1] : uCanon2[0]; +// uPhases[0] = pPhases2[0]; + pCut->uCanon0 = uCanon2[0]; + pCut->Num0 = pPhases2[0]; + + // get the complemented truth table + uTruth = ~*Cut_CutReadTruth(pCut); + + // compute the direct truth table + Extra_TruthCanonFastN( pCut->nVarsMax, pCut->nLeaves, &uTruth, &uCanon2, &pPhases2 ); +// uCanon[0] = uCanon2[0]; +// uCanon[1] = (p->nVarsMax == 6)? uCanon2[1] : uCanon2[0]; +// uPhases[0] = pPhases2[0]; + pCut->uCanon1 = uCanon2[0]; + pCut->Num1 = pPhases2[0]; +} + +/**Function************************************************************* + + Synopsis [Performs truth table computation.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_TruthComputeOld( Cut_Cut_t * pCut, Cut_Cut_t * pCut0, Cut_Cut_t * pCut1, int fCompl0, int fCompl1 ) +{ + static unsigned uTruth0[8], uTruth1[8]; + int nTruthWords = Cut_TruthWords( pCut->nVarsMax ); + unsigned * pTruthRes; + int i, uPhase; + + // permute the first table + uPhase = Cut_TruthPhase( pCut, pCut0 ); + Extra_TruthExpand( pCut->nVarsMax, nTruthWords, Cut_CutReadTruth(pCut0), uPhase, uTruth0 ); + if ( fCompl0 ) + { + for ( i = 0; i < nTruthWords; i++ ) + uTruth0[i] = ~uTruth0[i]; + } + + // permute the second table + uPhase = Cut_TruthPhase( pCut, pCut1 ); + Extra_TruthExpand( pCut->nVarsMax, nTruthWords, Cut_CutReadTruth(pCut1), uPhase, uTruth1 ); + if ( fCompl1 ) + { + for ( i = 0; i < nTruthWords; i++ ) + uTruth1[i] = ~uTruth1[i]; + } + + // write the resulting table + pTruthRes = Cut_CutReadTruth(pCut); + + if ( pCut->fCompl ) + { + for ( i = 0; i < nTruthWords; i++ ) + pTruthRes[i] = ~(uTruth0[i] & uTruth1[i]); + } + else + { + for ( i = 0; i < nTruthWords; i++ ) + pTruthRes[i] = uTruth0[i] & uTruth1[i]; + } +} + +/**Function************************************************************* + + Synopsis [Performs truth table computation.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cut_TruthCompute( Cut_Man_t * p, Cut_Cut_t * pCut, Cut_Cut_t * pCut0, Cut_Cut_t * pCut1, int fCompl0, int fCompl1 ) +{ + // permute the first table + if ( fCompl0 ) + Extra_TruthNot( p->puTemp[0], Cut_CutReadTruth(pCut0), pCut->nVarsMax ); + else + Extra_TruthCopy( p->puTemp[0], Cut_CutReadTruth(pCut0), pCut->nVarsMax ); + Extra_TruthStretch( p->puTemp[2], p->puTemp[0], pCut0->nLeaves, pCut->nVarsMax, Cut_TruthPhase(pCut, pCut0) ); + // permute the second table + if ( fCompl1 ) + Extra_TruthNot( p->puTemp[1], Cut_CutReadTruth(pCut1), pCut->nVarsMax ); + else + Extra_TruthCopy( p->puTemp[1], Cut_CutReadTruth(pCut1), pCut->nVarsMax ); + Extra_TruthStretch( p->puTemp[3], p->puTemp[1], pCut1->nLeaves, pCut->nVarsMax, Cut_TruthPhase(pCut, pCut1) ); + // produce the resulting table + if ( pCut->fCompl ) + Extra_TruthNand( Cut_CutReadTruth(pCut), p->puTemp[2], p->puTemp[3], pCut->nVarsMax ); + else + Extra_TruthAnd( Cut_CutReadTruth(pCut), p->puTemp[2], p->puTemp[3], pCut->nVarsMax ); + +// Ivy_TruthTestOne( *Cut_CutReadTruth(pCut) ); + + // quit if no fancy computation is needed + if ( !p->pParams->fFancy ) + return; + + if ( pCut->nLeaves != 7 ) + return; + + // count the total number of truth tables computed + nTotal++; + + // MAPPING INTO ALTERA 6-2 LOGIC BLOCKS + // call this procedure to find the minimum number of common variables in the cofactors + // if this number is less or equal than 3, the cut can be implemented using the 6-2 logic block + if ( Extra_TruthMinCofSuppOverlap( Cut_CutReadTruth(pCut), pCut->nVarsMax, NULL ) <= 4 ) + nGood++; + + // MAPPING INTO ACTEL 2x2 CELLS + // call this procedure to see if a semi-canonical form can be found in the lookup table + // (if it exists, then a two-level 3-input LUT implementation of the cut exists) + // Before this procedure is called, cell manager should be defined by calling + // Cut_CellLoad (make sure file "cells22_daomap_iwls.txt" is available in the working dir) +// if ( Cut_CellIsRunning() && pCut->nVarsMax <= 9 ) +// nGood += Cut_CellTruthLookup( Cut_CutReadTruth(pCut), pCut->nVarsMax ); +} + + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/cut/module.make b/src/opt/cut/module.make new file mode 100644 index 00000000..132e730b --- /dev/null +++ b/src/opt/cut/module.make @@ -0,0 +1,9 @@ +SRC += src/opt/cut/cutApi.c \ + src/opt/cut/cutCut.c \ + src/opt/cut/cutMan.c \ + src/opt/cut/cutMerge.c \ + src/opt/cut/cutNode.c \ + src/opt/cut/cutOracle.c \ + src/opt/cut/cutPre22.c \ + src/opt/cut/cutSeq.c \ + src/opt/cut/cutTruth.c diff --git a/src/opt/dec/dec.h b/src/opt/dec/dec.h new file mode 100644 index 00000000..41d22649 --- /dev/null +++ b/src/opt/dec/dec.h @@ -0,0 +1,719 @@ +/**CFile**************************************************************** + + FileName [dec.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [A simple decomposition tree/node data structure and its APIs.] + + Synopsis [External declarations.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: dec.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef __DEC_H__ +#define __DEC_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// BASIC TYPES /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Dec_Edge_t_ Dec_Edge_t; +struct Dec_Edge_t_ +{ + unsigned fCompl : 1; // the complemented bit + unsigned Node : 30; // the decomposition node pointed by the edge +}; + +typedef struct Dec_Node_t_ Dec_Node_t; +struct Dec_Node_t_ +{ + Dec_Edge_t eEdge0; // the left child of the node + Dec_Edge_t eEdge1; // the right child of the node + // other info + void * pFunc; // the function of the node (BDD or AIG) + unsigned Level : 14; // the level of this node in the global AIG + // printing info + unsigned fNodeOr : 1; // marks the original OR node + unsigned fCompl0 : 1; // marks the original complemented edge + unsigned fCompl1 : 1; // marks the original complemented edge + // latch info + unsigned nLat0 : 5; // the number of latches on the first edge + unsigned nLat1 : 5; // the number of latches on the second edge + unsigned nLat2 : 5; // the number of latches on the output edge +}; + +typedef struct Dec_Graph_t_ Dec_Graph_t; +struct Dec_Graph_t_ +{ + int fConst; // marks the constant 1 graph + int nLeaves; // the number of leaves + int nSize; // the number of nodes (including the leaves) + int nCap; // the number of allocated nodes + Dec_Node_t * pNodes; // the array of leaves and internal nodes + Dec_Edge_t eRoot; // the pointer to the topmost node +}; + +typedef struct Dec_Man_t_ Dec_Man_t; +struct Dec_Man_t_ +{ + void * pMvcMem; // memory manager for MVC cover (used for factoring) + Vec_Int_t * vCubes; // storage for cubes + Vec_Int_t * vLits; // storage for literals + // precomputation information about 4-variable functions + unsigned short * puCanons; // canonical forms + char * pPhases; // canonical phases + char * pPerms; // canonical permutations + unsigned char * pMap; // mapping of functions into class numbers +}; + + +//////////////////////////////////////////////////////////////////////// +/// ITERATORS /// +//////////////////////////////////////////////////////////////////////// + +// interator throught the leaves +#define Dec_GraphForEachLeaf( pGraph, pLeaf, i ) \ + for ( i = 0; (i < (pGraph)->nLeaves) && (((pLeaf) = Dec_GraphNode(pGraph, i)), 1); i++ ) +// interator throught the internal nodes +#define Dec_GraphForEachNode( pGraph, pAnd, i ) \ + for ( i = (pGraph)->nLeaves; (i < (pGraph)->nSize) && (((pAnd) = Dec_GraphNode(pGraph, i)), 1); i++ ) + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +/*=== decAbc.c ========================================================*/ +extern Abc_Obj_t * Dec_GraphToNetwork( Abc_Ntk_t * pNtk, Dec_Graph_t * pGraph ); +extern Abc_Obj_t * Dec_GraphToNetworkNoStrash( Abc_Ntk_t * pNtk, Dec_Graph_t * pGraph ); +extern int Dec_GraphToNetworkCount( Abc_Obj_t * pRoot, Dec_Graph_t * pGraph, int NodeMax, int LevelMax ); +extern void Dec_GraphUpdateNetwork( Abc_Obj_t * pRoot, Dec_Graph_t * pGraph, bool fUpdateLevel, int nGain ); +/*=== decFactor.c ========================================================*/ +extern Dec_Graph_t * Dec_Factor( char * pSop ); +/*=== decMan.c ========================================================*/ +extern Dec_Man_t * Dec_ManStart(); +extern void Dec_ManStop( Dec_Man_t * p ); +/*=== decPrint.c ========================================================*/ +extern void Dec_GraphPrint( FILE * pFile, Dec_Graph_t * pGraph, char * pNamesIn[], char * pNameOut ); +/*=== decUtil.c ========================================================*/ +extern DdNode * Dec_GraphDeriveBdd( DdManager * dd, Dec_Graph_t * pGraph ); +extern unsigned Dec_GraphDeriveTruth( Dec_Graph_t * pGraph ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Creates an edge pointing to the node in the given polarity.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Dec_Edge_t Dec_EdgeCreate( int Node, int fCompl ) +{ + Dec_Edge_t eEdge = { fCompl, Node }; + return eEdge; +} + +/**Function************************************************************* + + Synopsis [Converts the edge into unsigned integer.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline unsigned Dec_EdgeToInt( Dec_Edge_t eEdge ) +{ + return (eEdge.Node << 1) | eEdge.fCompl; +} + +/**Function************************************************************* + + Synopsis [Converts unsigned integer into the edge.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Dec_Edge_t Dec_IntToEdge( unsigned Edge ) +{ + return Dec_EdgeCreate( Edge >> 1, Edge & 1 ); +} + +/**Function************************************************************* + + Synopsis [Converts the edge into unsigned integer.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline unsigned Dec_EdgeToInt_( Dec_Edge_t eEdge ) +{ + return *(unsigned *)&eEdge; +} + +/**Function************************************************************* + + Synopsis [Converts unsigned integer into the edge.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Dec_Edge_t Dec_IntToEdge_( unsigned Edge ) +{ + return *(Dec_Edge_t *)&Edge; +} + +/**Function************************************************************* + + Synopsis [Creates a graph with the given number of leaves.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Dec_Graph_t * Dec_GraphCreate( int nLeaves ) +{ + Dec_Graph_t * pGraph; + pGraph = ALLOC( Dec_Graph_t, 1 ); + memset( pGraph, 0, sizeof(Dec_Graph_t) ); + pGraph->nLeaves = nLeaves; + pGraph->nSize = nLeaves; + pGraph->nCap = 2 * nLeaves + 50; + pGraph->pNodes = ALLOC( Dec_Node_t, pGraph->nCap ); + memset( pGraph->pNodes, 0, sizeof(Dec_Node_t) * pGraph->nSize ); + return pGraph; +} + +/**Function************************************************************* + + Synopsis [Creates constant 0 graph.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Dec_Graph_t * Dec_GraphCreateConst0() +{ + Dec_Graph_t * pGraph; + pGraph = ALLOC( Dec_Graph_t, 1 ); + memset( pGraph, 0, sizeof(Dec_Graph_t) ); + pGraph->fConst = 1; + pGraph->eRoot.fCompl = 1; + return pGraph; +} + +/**Function************************************************************* + + Synopsis [Creates constant 1 graph.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Dec_Graph_t * Dec_GraphCreateConst1() +{ + Dec_Graph_t * pGraph; + pGraph = ALLOC( Dec_Graph_t, 1 ); + memset( pGraph, 0, sizeof(Dec_Graph_t) ); + pGraph->fConst = 1; + return pGraph; +} + +/**Function************************************************************* + + Synopsis [Creates the literal graph.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Dec_Graph_t * Dec_GraphCreateLeaf( int iLeaf, int nLeaves, int fCompl ) +{ + Dec_Graph_t * pGraph; + assert( 0 <= iLeaf && iLeaf < nLeaves ); + pGraph = Dec_GraphCreate( nLeaves ); + pGraph->eRoot.Node = iLeaf; + pGraph->eRoot.fCompl = fCompl; + return pGraph; +} + +/**Function************************************************************* + + Synopsis [Creates a graph with the given number of leaves.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Dec_GraphFree( Dec_Graph_t * pGraph ) +{ + FREE( pGraph->pNodes ); + free( pGraph ); +} + +/**Function************************************************************* + + Synopsis [Returns 1 if the graph is a constant.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline bool Dec_GraphIsConst( Dec_Graph_t * pGraph ) +{ + return pGraph->fConst; +} + +/**Function************************************************************* + + Synopsis [Returns 1 if the graph is constant 0.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline bool Dec_GraphIsConst0( Dec_Graph_t * pGraph ) +{ + return pGraph->fConst && pGraph->eRoot.fCompl; +} + +/**Function************************************************************* + + Synopsis [Returns 1 if the graph is constant 1.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline bool Dec_GraphIsConst1( Dec_Graph_t * pGraph ) +{ + return pGraph->fConst && !pGraph->eRoot.fCompl; +} + +/**Function************************************************************* + + Synopsis [Returns 1 if the graph is complemented.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline bool Dec_GraphIsComplement( Dec_Graph_t * pGraph ) +{ + return pGraph->eRoot.fCompl; +} + +/**Function************************************************************* + + Synopsis [Checks if the graph is complemented.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Dec_GraphComplement( Dec_Graph_t * pGraph ) +{ + pGraph->eRoot.fCompl ^= 1; +} + + +/**Function************************************************************* + + Synopsis [Returns the number of leaves.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Dec_GraphLeaveNum( Dec_Graph_t * pGraph ) +{ + return pGraph->nLeaves; +} + +/**Function************************************************************* + + Synopsis [Returns the number of internal nodes.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Dec_GraphNodeNum( Dec_Graph_t * pGraph ) +{ + return pGraph->nSize - pGraph->nLeaves; +} + +/**Function************************************************************* + + Synopsis [Returns the pointer to the node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Dec_Node_t * Dec_GraphNode( Dec_Graph_t * pGraph, int i ) +{ + return pGraph->pNodes + i; +} + +/**Function************************************************************* + + Synopsis [Returns the pointer to the node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Dec_Node_t * Dec_GraphNodeLast( Dec_Graph_t * pGraph ) +{ + return pGraph->pNodes + pGraph->nSize - 1; +} + +/**Function************************************************************* + + Synopsis [Returns the number of the given node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Dec_GraphNodeInt( Dec_Graph_t * pGraph, Dec_Node_t * pNode ) +{ + return pNode - pGraph->pNodes; +} + +/**Function************************************************************* + + Synopsis [Check if the graph represents elementary variable.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline bool Dec_GraphIsVar( Dec_Graph_t * pGraph ) +{ + return pGraph->eRoot.Node < (unsigned)pGraph->nLeaves; +} + +/**Function************************************************************* + + Synopsis [Check if the graph represents elementary variable.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline bool Dec_GraphNodeIsVar( Dec_Graph_t * pGraph, Dec_Node_t * pNode ) +{ + return Dec_GraphNodeInt(pGraph,pNode) < pGraph->nLeaves; +} + +/**Function************************************************************* + + Synopsis [Returns the elementary variable elementary variable.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Dec_Node_t * Dec_GraphVar( Dec_Graph_t * pGraph ) +{ + assert( Dec_GraphIsVar( pGraph ) ); + return Dec_GraphNode( pGraph, pGraph->eRoot.Node ); +} + +/**Function************************************************************* + + Synopsis [Returns the number of the elementary variable.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Dec_GraphVarInt( Dec_Graph_t * pGraph ) +{ + assert( Dec_GraphIsVar( pGraph ) ); + return Dec_GraphNodeInt( pGraph, Dec_GraphVar(pGraph) ); +} + +/**Function************************************************************* + + Synopsis [Sets the root of the graph.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Dec_GraphSetRoot( Dec_Graph_t * pGraph, Dec_Edge_t eRoot ) +{ + pGraph->eRoot = eRoot; +} + +/**Function************************************************************* + + Synopsis [Appends a new node to the graph.] + + Description [This procedure is meant for internal use.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Dec_Node_t * Dec_GraphAppendNode( Dec_Graph_t * pGraph ) +{ + Dec_Node_t * pNode; + if ( pGraph->nSize == pGraph->nCap ) + { + pGraph->pNodes = REALLOC( Dec_Node_t, pGraph->pNodes, 2 * pGraph->nCap ); + pGraph->nCap = 2 * pGraph->nCap; + } + pNode = pGraph->pNodes + pGraph->nSize++; + memset( pNode, 0, sizeof(Dec_Node_t) ); + return pNode; +} + +/**Function************************************************************* + + Synopsis [Creates an AND node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Dec_Edge_t Dec_GraphAddNodeAnd( Dec_Graph_t * pGraph, Dec_Edge_t eEdge0, Dec_Edge_t eEdge1 ) +{ + Dec_Node_t * pNode; + // get the new node + pNode = Dec_GraphAppendNode( pGraph ); + // set the inputs and other info + pNode->eEdge0 = eEdge0; + pNode->eEdge1 = eEdge1; + pNode->fCompl0 = eEdge0.fCompl; + pNode->fCompl1 = eEdge1.fCompl; + return Dec_EdgeCreate( pGraph->nSize - 1, 0 ); +} + +/**Function************************************************************* + + Synopsis [Creates an OR node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Dec_Edge_t Dec_GraphAddNodeOr( Dec_Graph_t * pGraph, Dec_Edge_t eEdge0, Dec_Edge_t eEdge1 ) +{ + Dec_Node_t * pNode; + // get the new node + pNode = Dec_GraphAppendNode( pGraph ); + // set the inputs and other info + pNode->eEdge0 = eEdge0; + pNode->eEdge1 = eEdge1; + pNode->fCompl0 = eEdge0.fCompl; + pNode->fCompl1 = eEdge1.fCompl; + // make adjustments for the OR gate + pNode->fNodeOr = 1; + pNode->eEdge0.fCompl = !pNode->eEdge0.fCompl; + pNode->eEdge1.fCompl = !pNode->eEdge1.fCompl; + return Dec_EdgeCreate( pGraph->nSize - 1, 1 ); +} + +/**Function************************************************************* + + Synopsis [Creates an XOR node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Dec_Edge_t Dec_GraphAddNodeXor( Dec_Graph_t * pGraph, Dec_Edge_t eEdge0, Dec_Edge_t eEdge1, int Type ) +{ + Dec_Edge_t eNode0, eNode1, eNode; + if ( Type == 0 ) + { + // derive the first AND + eEdge0.fCompl ^= 1; + eNode0 = Dec_GraphAddNodeAnd( pGraph, eEdge0, eEdge1 ); + eEdge0.fCompl ^= 1; + // derive the second AND + eEdge1.fCompl ^= 1; + eNode1 = Dec_GraphAddNodeAnd( pGraph, eEdge0, eEdge1 ); + // derive the final OR + eNode = Dec_GraphAddNodeOr( pGraph, eNode0, eNode1 ); + } + else + { + // derive the first AND + eNode0 = Dec_GraphAddNodeAnd( pGraph, eEdge0, eEdge1 ); + // derive the second AND + eEdge0.fCompl ^= 1; + eEdge1.fCompl ^= 1; + eNode1 = Dec_GraphAddNodeAnd( pGraph, eEdge0, eEdge1 ); + // derive the final OR + eNode = Dec_GraphAddNodeOr( pGraph, eNode0, eNode1 ); + eNode.fCompl ^= 1; + } + return eNode; +} + +/**Function************************************************************* + + Synopsis [Creates an XOR node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Dec_Edge_t Dec_GraphAddNodeMux( Dec_Graph_t * pGraph, Dec_Edge_t eEdgeC, Dec_Edge_t eEdgeT, Dec_Edge_t eEdgeE, int Type ) +{ + Dec_Edge_t eNode0, eNode1, eNode; + if ( Type == 0 ) + { + // derive the first AND + eNode0 = Dec_GraphAddNodeAnd( pGraph, eEdgeC, eEdgeT ); + // derive the second AND + eEdgeC.fCompl ^= 1; + eNode1 = Dec_GraphAddNodeAnd( pGraph, eEdgeC, eEdgeE ); + // derive the final OR + eNode = Dec_GraphAddNodeOr( pGraph, eNode0, eNode1 ); + } + else + { + // complement the arguments + eEdgeT.fCompl ^= 1; + eEdgeE.fCompl ^= 1; + // derive the first AND + eNode0 = Dec_GraphAddNodeAnd( pGraph, eEdgeC, eEdgeT ); + // derive the second AND + eEdgeC.fCompl ^= 1; + eNode1 = Dec_GraphAddNodeAnd( pGraph, eEdgeC, eEdgeE ); + // derive the final OR + eNode = Dec_GraphAddNodeOr( pGraph, eNode0, eNode1 ); + eNode.fCompl ^= 1; + } + return eNode; +} + +#ifdef __cplusplus +} +#endif + +#endif + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + diff --git a/src/opt/dec/decAbc.c b/src/opt/dec/decAbc.c new file mode 100644 index 00000000..bd960c14 --- /dev/null +++ b/src/opt/dec/decAbc.c @@ -0,0 +1,305 @@ +/**CFile**************************************************************** + + FileName [decAbc.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Interface between the decomposition package and ABC network.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: decAbc.c,v 1.1 2003/05/22 19:20:05 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "dec.h" +#include "ivy.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Transforms the decomposition graph into the AIG.] + + Description [AIG nodes for the fanins should be assigned to pNode->pFunc + of the leaves of the graph before calling this procedure.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Abc_Obj_t * Dec_GraphToNetwork( Abc_Ntk_t * pNtk, Dec_Graph_t * pGraph ) +{ + Abc_Obj_t * pAnd0, * pAnd1; + Dec_Node_t * pNode; + int i; + // check for constant function + if ( Dec_GraphIsConst(pGraph) ) + return Abc_ObjNotCond( Abc_AigConst1(pNtk), Dec_GraphIsComplement(pGraph) ); + // check for a literal + if ( Dec_GraphIsVar(pGraph) ) + return Abc_ObjNotCond( Dec_GraphVar(pGraph)->pFunc, Dec_GraphIsComplement(pGraph) ); + // build the AIG nodes corresponding to the AND gates of the graph + Dec_GraphForEachNode( pGraph, pNode, i ) + { + pAnd0 = Abc_ObjNotCond( Dec_GraphNode(pGraph, pNode->eEdge0.Node)->pFunc, pNode->eEdge0.fCompl ); + pAnd1 = Abc_ObjNotCond( Dec_GraphNode(pGraph, pNode->eEdge1.Node)->pFunc, pNode->eEdge1.fCompl ); + pNode->pFunc = Abc_AigAnd( pNtk->pManFunc, pAnd0, pAnd1 ); + } + // complement the result if necessary + return Abc_ObjNotCond( pNode->pFunc, Dec_GraphIsComplement(pGraph) ); +} + +/**Function************************************************************* + + Synopsis [Transforms the decomposition graph into the AIG.] + + Description [AIG nodes for the fanins should be assigned to pNode->pFunc + of the leaves of the graph before calling this procedure.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Abc_Obj_t * Dec_GraphToNetworkNoStrash( Abc_Ntk_t * pNtk, Dec_Graph_t * pGraph ) +{ + Abc_Obj_t * pAnd, * pAnd0, * pAnd1; + Dec_Node_t * pNode; + int i; + // check for constant function + if ( Dec_GraphIsConst(pGraph) ) + return Abc_ObjNotCond( Abc_AigConst1(pNtk), Dec_GraphIsComplement(pGraph) ); + // check for a literal + if ( Dec_GraphIsVar(pGraph) ) + return Abc_ObjNotCond( Dec_GraphVar(pGraph)->pFunc, Dec_GraphIsComplement(pGraph) ); + // build the AIG nodes corresponding to the AND gates of the graph + Dec_GraphForEachNode( pGraph, pNode, i ) + { + pAnd0 = Abc_ObjNotCond( Dec_GraphNode(pGraph, pNode->eEdge0.Node)->pFunc, pNode->eEdge0.fCompl ); + pAnd1 = Abc_ObjNotCond( Dec_GraphNode(pGraph, pNode->eEdge1.Node)->pFunc, pNode->eEdge1.fCompl ); +// pNode->pFunc = Abc_AigAnd( pNtk->pManFunc, pAnd0, pAnd1 ); + pAnd = Abc_NtkCreateNode( pNtk ); + Abc_ObjAddFanin( pAnd, pAnd0 ); + Abc_ObjAddFanin( pAnd, pAnd1 ); + pNode->pFunc = pAnd; + } + // complement the result if necessary + return Abc_ObjNotCond( pNode->pFunc, Dec_GraphIsComplement(pGraph) ); +} + +/**Function************************************************************* + + Synopsis [Counts the number of new nodes added when using this graph.] + + Description [AIG nodes for the fanins should be assigned to pNode->pFunc + of the leaves of the graph before calling this procedure. + Returns -1 if the number of nodes and levels exceeded the given limit or + the number of levels exceeded the maximum allowed level.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Dec_GraphToNetworkCount( Abc_Obj_t * pRoot, Dec_Graph_t * pGraph, int NodeMax, int LevelMax ) +{ + Abc_Aig_t * pMan = pRoot->pNtk->pManFunc; + Dec_Node_t * pNode, * pNode0, * pNode1; + Abc_Obj_t * pAnd, * pAnd0, * pAnd1; + int i, Counter, LevelNew, LevelOld; + // check for constant function or a literal + if ( Dec_GraphIsConst(pGraph) || Dec_GraphIsVar(pGraph) ) + return 0; + // set the levels of the leaves + Dec_GraphForEachLeaf( pGraph, pNode, i ) + pNode->Level = Abc_ObjRegular(pNode->pFunc)->Level; + // compute the AIG size after adding the internal nodes + Counter = 0; + Dec_GraphForEachNode( pGraph, pNode, i ) + { + // get the children of this node + pNode0 = Dec_GraphNode( pGraph, pNode->eEdge0.Node ); + pNode1 = Dec_GraphNode( pGraph, pNode->eEdge1.Node ); + // get the AIG nodes corresponding to the children + pAnd0 = pNode0->pFunc; + pAnd1 = pNode1->pFunc; + if ( pAnd0 && pAnd1 ) + { + // if they are both present, find the resulting node + pAnd0 = Abc_ObjNotCond( pAnd0, pNode->eEdge0.fCompl ); + pAnd1 = Abc_ObjNotCond( pAnd1, pNode->eEdge1.fCompl ); + pAnd = Abc_AigAndLookup( pMan, pAnd0, pAnd1 ); + // return -1 if the node is the same as the original root + if ( Abc_ObjRegular(pAnd) == pRoot ) + return -1; + } + else + pAnd = NULL; + // count the number of added nodes + if ( pAnd == NULL || Abc_NodeIsTravIdCurrent(Abc_ObjRegular(pAnd)) ) + { + if ( ++Counter > NodeMax ) + return -1; + } + // count the number of new levels + LevelNew = 1 + ABC_MAX( pNode0->Level, pNode1->Level ); + if ( pAnd ) + { + if ( Abc_ObjRegular(pAnd) == Abc_AigConst1(pRoot->pNtk) ) + LevelNew = 0; + else if ( Abc_ObjRegular(pAnd) == Abc_ObjRegular(pAnd0) ) + LevelNew = (int)Abc_ObjRegular(pAnd0)->Level; + else if ( Abc_ObjRegular(pAnd) == Abc_ObjRegular(pAnd1) ) + LevelNew = (int)Abc_ObjRegular(pAnd1)->Level; + LevelOld = (int)Abc_ObjRegular(pAnd)->Level; +// assert( LevelNew == LevelOld ); + } + if ( LevelNew > LevelMax ) + return -1; + pNode->pFunc = pAnd; + pNode->Level = LevelNew; + } + return Counter; +} + + +/**Function************************************************************* + + Synopsis [Replaces MFFC of the node by the new factored form.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Dec_GraphUpdateNetwork( Abc_Obj_t * pRoot, Dec_Graph_t * pGraph, bool fUpdateLevel, int nGain ) +{ + Abc_Obj_t * pRootNew; + Abc_Ntk_t * pNtk = pRoot->pNtk; + int nNodesNew, nNodesOld; + nNodesOld = Abc_NtkNodeNum(pNtk); + // create the new structure of nodes + pRootNew = Dec_GraphToNetwork( pNtk, pGraph ); + // remove the old nodes + Abc_AigReplace( pNtk->pManFunc, pRoot, pRootNew, fUpdateLevel ); + // compare the gains + nNodesNew = Abc_NtkNodeNum(pNtk); + assert( nGain <= nNodesOld - nNodesNew ); +} + + +/**Function************************************************************* + + Synopsis [Transforms the decomposition graph into the AIG.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Hop_Obj_t * Dec_GraphToNetworkAig( Hop_Man_t * pMan, Dec_Graph_t * pGraph ) +{ + Dec_Node_t * pNode; + Hop_Obj_t * pAnd0, * pAnd1; + int i; + // check for constant function + if ( Dec_GraphIsConst(pGraph) ) + return Hop_NotCond( Hop_ManConst1(pMan), Dec_GraphIsComplement(pGraph) ); + // check for a literal + if ( Dec_GraphIsVar(pGraph) ) + return Hop_NotCond( Dec_GraphVar(pGraph)->pFunc, Dec_GraphIsComplement(pGraph) ); + // build the AIG nodes corresponding to the AND gates of the graph + Dec_GraphForEachNode( pGraph, pNode, i ) + { + pAnd0 = Hop_NotCond( Dec_GraphNode(pGraph, pNode->eEdge0.Node)->pFunc, pNode->eEdge0.fCompl ); + pAnd1 = Hop_NotCond( Dec_GraphNode(pGraph, pNode->eEdge1.Node)->pFunc, pNode->eEdge1.fCompl ); + pNode->pFunc = Hop_And( pMan, pAnd0, pAnd1 ); + } + // complement the result if necessary + return Hop_NotCond( pNode->pFunc, Dec_GraphIsComplement(pGraph) ); +} + +/**Function************************************************************* + + Synopsis [Strashes one logic node using its SOP.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Hop_Obj_t * Dec_GraphFactorSop( Hop_Man_t * pMan, char * pSop ) +{ + Hop_Obj_t * pFunc; + Dec_Graph_t * pFForm; + Dec_Node_t * pNode; + int i; + // perform factoring + pFForm = Dec_Factor( pSop ); + // collect the fanins + Dec_GraphForEachLeaf( pFForm, pNode, i ) + pNode->pFunc = Hop_IthVar( pMan, i ); + // perform strashing + pFunc = Dec_GraphToNetworkAig( pMan, pFForm ); + Dec_GraphFree( pFForm ); + return pFunc; +} + +/**Function************************************************************* + + Synopsis [Transforms the decomposition graph into the AIG.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Ivy_Obj_t * Dec_GraphToNetworkIvy( Ivy_Man_t * pMan, Dec_Graph_t * pGraph ) +{ + Dec_Node_t * pNode; + Ivy_Obj_t * pAnd0, * pAnd1; + int i; + // check for constant function + if ( Dec_GraphIsConst(pGraph) ) + return Ivy_NotCond( Ivy_ManConst1(pMan), Dec_GraphIsComplement(pGraph) ); + // check for a literal + if ( Dec_GraphIsVar(pGraph) ) + return Ivy_NotCond( Dec_GraphVar(pGraph)->pFunc, Dec_GraphIsComplement(pGraph) ); + // build the AIG nodes corresponding to the AND gates of the graph + Dec_GraphForEachNode( pGraph, pNode, i ) + { + pAnd0 = Ivy_NotCond( Dec_GraphNode(pGraph, pNode->eEdge0.Node)->pFunc, pNode->eEdge0.fCompl ); + pAnd1 = Ivy_NotCond( Dec_GraphNode(pGraph, pNode->eEdge1.Node)->pFunc, pNode->eEdge1.fCompl ); + pNode->pFunc = Ivy_And( pMan, pAnd0, pAnd1 ); + } + // complement the result if necessary + return Ivy_NotCond( pNode->pFunc, Dec_GraphIsComplement(pGraph) ); +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/dec/decFactor.c b/src/opt/dec/decFactor.c new file mode 100644 index 00000000..dca422ea --- /dev/null +++ b/src/opt/dec/decFactor.c @@ -0,0 +1,392 @@ +/**CFile**************************************************************** + + FileName [ftFactor.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Procedures for algebraic factoring.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: ftFactor.c,v 1.3 2003/09/01 04:56:43 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "main.h" +#include "mvc.h" +#include "dec.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static Dec_Edge_t Dec_Factor_rec( Dec_Graph_t * pFForm, Mvc_Cover_t * pCover ); +static Dec_Edge_t Dec_FactorLF_rec( Dec_Graph_t * pFForm, Mvc_Cover_t * pCover, Mvc_Cover_t * pSimple ); +static Dec_Edge_t Dec_FactorTrivial( Dec_Graph_t * pFForm, Mvc_Cover_t * pCover ); +static Dec_Edge_t Dec_FactorTrivialCube( Dec_Graph_t * pFForm, Mvc_Cover_t * pCover, Mvc_Cube_t * pCube, Vec_Int_t * vEdgeLits ); +static Dec_Edge_t Dec_FactorTrivialTree_rec( Dec_Graph_t * pFForm, Dec_Edge_t * peNodes, int nNodes, int fNodeOr ); +static int Dec_FactorVerify( char * pSop, Dec_Graph_t * pFForm ); +static Mvc_Cover_t * Dec_ConvertSopToMvc( char * pSop ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Factors the cover.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Dec_Graph_t * Dec_Factor( char * pSop ) +{ + Mvc_Cover_t * pCover; + Dec_Graph_t * pFForm; + Dec_Edge_t eRoot; + + // derive the cover from the SOP representation + pCover = Dec_ConvertSopToMvc( pSop ); + + // make sure the cover is CCS free (should be done before CST) + Mvc_CoverContain( pCover ); + // check for trivial functions + if ( Mvc_CoverIsEmpty(pCover) ) + { + Mvc_CoverFree( pCover ); + return Dec_GraphCreateConst0(); + } + if ( Mvc_CoverIsTautology(pCover) ) + { + Mvc_CoverFree( pCover ); + return Dec_GraphCreateConst1(); + } + + // perform CST + Mvc_CoverInverse( pCover ); // CST + // start the factored form + pFForm = Dec_GraphCreate( Abc_SopGetVarNum(pSop) ); + // factor the cover + eRoot = Dec_Factor_rec( pFForm, pCover ); + // finalize the factored form + Dec_GraphSetRoot( pFForm, eRoot ); + // complement the factored form if SOP is complemented + if ( Abc_SopIsComplement(pSop) ) + Dec_GraphComplement( pFForm ); + // verify the factored form +// if ( !Dec_FactorVerify( pSop, pFForm ) ) +// printf( "Verification has failed.\n" ); +// Mvc_CoverInverse( pCover ); // undo CST + Mvc_CoverFree( pCover ); + return pFForm; +} + +/**Function************************************************************* + + Synopsis [Internal recursive factoring procedure.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Dec_Edge_t Dec_Factor_rec( Dec_Graph_t * pFForm, Mvc_Cover_t * pCover ) +{ + Mvc_Cover_t * pDiv, * pQuo, * pRem, * pCom; + Dec_Edge_t eNodeDiv, eNodeQuo, eNodeRem; + Dec_Edge_t eNodeAnd, eNode; + + // make sure the cover contains some cubes + assert( Mvc_CoverReadCubeNum(pCover) ); + + // get the divisor + pDiv = Mvc_CoverDivisor( pCover ); + if ( pDiv == NULL ) + return Dec_FactorTrivial( pFForm, pCover ); + + // divide the cover by the divisor + Mvc_CoverDivideInternal( pCover, pDiv, &pQuo, &pRem ); + assert( Mvc_CoverReadCubeNum(pQuo) ); + + Mvc_CoverFree( pDiv ); + Mvc_CoverFree( pRem ); + + // check the trivial case + if ( Mvc_CoverReadCubeNum(pQuo) == 1 ) + { + eNode = Dec_FactorLF_rec( pFForm, pCover, pQuo ); + Mvc_CoverFree( pQuo ); + return eNode; + } + + // make the quotient cube free + Mvc_CoverMakeCubeFree( pQuo ); + + // divide the cover by the quotient + Mvc_CoverDivideInternal( pCover, pQuo, &pDiv, &pRem ); + + // check the trivial case + if ( Mvc_CoverIsCubeFree( pDiv ) ) + { + eNodeDiv = Dec_Factor_rec( pFForm, pDiv ); + eNodeQuo = Dec_Factor_rec( pFForm, pQuo ); + Mvc_CoverFree( pDiv ); + Mvc_CoverFree( pQuo ); + eNodeAnd = Dec_GraphAddNodeAnd( pFForm, eNodeDiv, eNodeQuo ); + if ( Mvc_CoverReadCubeNum(pRem) == 0 ) + { + Mvc_CoverFree( pRem ); + return eNodeAnd; + } + else + { + eNodeRem = Dec_Factor_rec( pFForm, pRem ); + Mvc_CoverFree( pRem ); + return Dec_GraphAddNodeOr( pFForm, eNodeAnd, eNodeRem ); + } + } + + // get the common cube + pCom = Mvc_CoverCommonCubeCover( pDiv ); + Mvc_CoverFree( pDiv ); + Mvc_CoverFree( pQuo ); + Mvc_CoverFree( pRem ); + + // solve the simple problem + eNode = Dec_FactorLF_rec( pFForm, pCover, pCom ); + Mvc_CoverFree( pCom ); + return eNode; +} + + +/**Function************************************************************* + + Synopsis [Internal recursive factoring procedure for the leaf case.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Dec_Edge_t Dec_FactorLF_rec( Dec_Graph_t * pFForm, Mvc_Cover_t * pCover, Mvc_Cover_t * pSimple ) +{ + Dec_Man_t * pManDec = Abc_FrameReadManDec(); + Vec_Int_t * vEdgeLits = pManDec->vLits; + Mvc_Cover_t * pDiv, * pQuo, * pRem; + Dec_Edge_t eNodeDiv, eNodeQuo, eNodeRem; + Dec_Edge_t eNodeAnd; + + // get the most often occurring literal + pDiv = Mvc_CoverBestLiteralCover( pCover, pSimple ); + // divide the cover by the literal + Mvc_CoverDivideByLiteral( pCover, pDiv, &pQuo, &pRem ); + // get the node pointer for the literal + eNodeDiv = Dec_FactorTrivialCube( pFForm, pDiv, Mvc_CoverReadCubeHead(pDiv), vEdgeLits ); + Mvc_CoverFree( pDiv ); + // factor the quotient and remainder + eNodeQuo = Dec_Factor_rec( pFForm, pQuo ); + Mvc_CoverFree( pQuo ); + eNodeAnd = Dec_GraphAddNodeAnd( pFForm, eNodeDiv, eNodeQuo ); + if ( Mvc_CoverReadCubeNum(pRem) == 0 ) + { + Mvc_CoverFree( pRem ); + return eNodeAnd; + } + else + { + eNodeRem = Dec_Factor_rec( pFForm, pRem ); + Mvc_CoverFree( pRem ); + return Dec_GraphAddNodeOr( pFForm, eNodeAnd, eNodeRem ); + } +} + + + +/**Function************************************************************* + + Synopsis [Factoring the cover, which has no algebraic divisors.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Dec_Edge_t Dec_FactorTrivial( Dec_Graph_t * pFForm, Mvc_Cover_t * pCover ) +{ + Dec_Man_t * pManDec = Abc_FrameReadManDec(); + Vec_Int_t * vEdgeCubes = pManDec->vCubes; + Vec_Int_t * vEdgeLits = pManDec->vLits; + Mvc_Manager_t * pMem = pManDec->pMvcMem; + Dec_Edge_t eNode; + Mvc_Cube_t * pCube; + // create the factored form for each cube + Vec_IntClear( vEdgeCubes ); + Mvc_CoverForEachCube( pCover, pCube ) + { + eNode = Dec_FactorTrivialCube( pFForm, pCover, pCube, vEdgeLits ); + Vec_IntPush( vEdgeCubes, Dec_EdgeToInt_(eNode) ); + } + // balance the factored forms + return Dec_FactorTrivialTree_rec( pFForm, (Dec_Edge_t *)vEdgeCubes->pArray, vEdgeCubes->nSize, 1 ); +} + +/**Function************************************************************* + + Synopsis [Factoring the cube.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Dec_Edge_t Dec_FactorTrivialCube( Dec_Graph_t * pFForm, Mvc_Cover_t * pCover, Mvc_Cube_t * pCube, Vec_Int_t * vEdgeLits ) +{ + Dec_Edge_t eNode; + int iBit, Value; + // create the factored form for each literal + Vec_IntClear( vEdgeLits ); + Mvc_CubeForEachBit( pCover, pCube, iBit, Value ) + if ( Value ) + { + eNode = Dec_EdgeCreate( iBit/2, iBit%2 ); // CST + Vec_IntPush( vEdgeLits, Dec_EdgeToInt_(eNode) ); + } + // balance the factored forms + return Dec_FactorTrivialTree_rec( pFForm, (Dec_Edge_t *)vEdgeLits->pArray, vEdgeLits->nSize, 0 ); +} + +/**Function************************************************************* + + Synopsis [Create the well-balanced tree of nodes.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Dec_Edge_t Dec_FactorTrivialTree_rec( Dec_Graph_t * pFForm, Dec_Edge_t * peNodes, int nNodes, int fNodeOr ) +{ + Dec_Edge_t eNode1, eNode2; + int nNodes1, nNodes2; + + if ( nNodes == 1 ) + return peNodes[0]; + + // split the nodes into two parts + nNodes1 = nNodes/2; + nNodes2 = nNodes - nNodes1; +// nNodes2 = nNodes/2; +// nNodes1 = nNodes - nNodes2; + + // recursively construct the tree for the parts + eNode1 = Dec_FactorTrivialTree_rec( pFForm, peNodes, nNodes1, fNodeOr ); + eNode2 = Dec_FactorTrivialTree_rec( pFForm, peNodes + nNodes1, nNodes2, fNodeOr ); + + if ( fNodeOr ) + return Dec_GraphAddNodeOr( pFForm, eNode1, eNode2 ); + else + return Dec_GraphAddNodeAnd( pFForm, eNode1, eNode2 ); +} + + + +/**Function************************************************************* + + Synopsis [Converts SOP into MVC.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Mvc_Cover_t * Dec_ConvertSopToMvc( char * pSop ) +{ + Dec_Man_t * pManDec = Abc_FrameReadManDec(); + Mvc_Manager_t * pMem = pManDec->pMvcMem; + Mvc_Cover_t * pMvc; + Mvc_Cube_t * pMvcCube; + char * pCube; + int nVars, Value, v; + + // start the cover + nVars = Abc_SopGetVarNum(pSop); + pMvc = Mvc_CoverAlloc( pMem, nVars * 2 ); + // check the logic function of the node + Abc_SopForEachCube( pSop, nVars, pCube ) + { + // create and add the cube + pMvcCube = Mvc_CubeAlloc( pMvc ); + Mvc_CoverAddCubeTail( pMvc, pMvcCube ); + // fill in the literals + Mvc_CubeBitFill( pMvcCube ); + Abc_CubeForEachVar( pCube, Value, v ) + { + if ( Value == '0' ) + Mvc_CubeBitRemove( pMvcCube, v * 2 + 1 ); + else if ( Value == '1' ) + Mvc_CubeBitRemove( pMvcCube, v * 2 ); + } + } + return pMvc; +} + +/**Function************************************************************* + + Synopsis [Verifies that the factoring is correct.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Dec_FactorVerify( char * pSop, Dec_Graph_t * pFForm ) +{ + DdManager * dd = Abc_FrameReadManDd(); + DdNode * bFunc1, * bFunc2; + int RetValue; + bFunc1 = Abc_ConvertSopToBdd( dd, pSop ); Cudd_Ref( bFunc1 ); + bFunc2 = Dec_GraphDeriveBdd( dd, pFForm ); Cudd_Ref( bFunc2 ); +//Extra_bddPrint( dd, bFunc1 ); printf("\n"); +//Extra_bddPrint( dd, bFunc2 ); printf("\n"); + RetValue = (bFunc1 == bFunc2); + if ( bFunc1 != bFunc2 ) + { + int s; + Extra_bddPrint( dd, bFunc1 ); printf("\n"); + Extra_bddPrint( dd, bFunc2 ); printf("\n"); + s = 0; + } + Cudd_RecursiveDeref( dd, bFunc1 ); + Cudd_RecursiveDeref( dd, bFunc2 ); + return RetValue; +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/dec/decMan.c b/src/opt/dec/decMan.c new file mode 100644 index 00000000..65857461 --- /dev/null +++ b/src/opt/dec/decMan.c @@ -0,0 +1,83 @@ +/**CFile**************************************************************** + + FileName [decMan.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Decomposition manager.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: decMan.c,v 1.1 2003/05/22 19:20:05 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "mvc.h" +#include "dec.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Start the MVC manager used in the factoring package.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Dec_Man_t * Dec_ManStart() +{ + Dec_Man_t * p; + int clk = clock(); + p = ALLOC( Dec_Man_t, 1 ); + p->pMvcMem = Mvc_ManagerStart(); + p->vCubes = Vec_IntAlloc( 8 ); + p->vLits = Vec_IntAlloc( 8 ); + // canonical forms, phases, perms + Extra_Truth4VarNPN( &p->puCanons, &p->pPhases, &p->pPerms, &p->pMap ); +//PRT( "NPN classes precomputation time", clock() - clk ); + return p; +} + +/**Function************************************************************* + + Synopsis [Stops the MVC maanager used in the factoring package.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Dec_ManStop( Dec_Man_t * p ) +{ + Mvc_ManagerFree( p->pMvcMem ); + Vec_IntFree( p->vCubes ); + Vec_IntFree( p->vLits ); + free( p->puCanons ); + free( p->pPhases ); + free( p->pPerms ); + free( p->pMap ); + free( p ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/dec/decPrint.c b/src/opt/dec/decPrint.c new file mode 100644 index 00000000..2d8f09b3 --- /dev/null +++ b/src/opt/dec/decPrint.c @@ -0,0 +1,284 @@ +/**CFile**************************************************************** + + FileName [decPrint.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Procedures to print the decomposition graphs (factored forms).] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: decPrint.c,v 1.1 2003/05/22 19:20:05 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "dec.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static void Dec_GraphPrint_rec( FILE * pFile, Dec_Graph_t * pGraph, Dec_Node_t * pNode, int fCompl, char * pNamesIn[], int * pPos, int LitSizeMax ); +static int Dec_GraphPrintGetLeafName( FILE * pFile, int iLeaf, int fCompl, char * pNamesIn[] ); +static void Dec_GraphPrintUpdatePos( FILE * pFile, int * pPos, int LitSizeMax ); +static int Dec_GraphPrintOutputName( FILE * pFile, char * pNameOut, int fCompl ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Prints the decomposition graph.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Dec_GraphPrint( FILE * pFile, Dec_Graph_t * pGraph, char * pNamesIn[], char * pNameOut ) +{ + Vec_Ptr_t * vNamesIn = NULL; + int LitSizeMax, LitSizeCur, Pos, i; + + // create the names if not given by the user + if ( pNamesIn == NULL ) + { + vNamesIn = Abc_NodeGetFakeNames( Dec_GraphLeaveNum(pGraph) ); + pNamesIn = (char **)vNamesIn->pArray; + } + if ( pNameOut == NULL ) + pNameOut = "F"; + + // get the size of the longest literal + LitSizeMax = 0; + for ( i = 0; i < Dec_GraphLeaveNum(pGraph); i++ ) + { + LitSizeCur = strlen(pNamesIn[i]); + if ( LitSizeMax < LitSizeCur ) + LitSizeMax = LitSizeCur; + } + if ( LitSizeMax > 50 ) + LitSizeMax = 20; + + // write the decomposition graph (factored form) + if ( Dec_GraphIsConst(pGraph) ) // constant + { + Pos = Dec_GraphPrintOutputName( pFile, pNameOut, 0 ); + fprintf( pFile, "Constant %d", !Dec_GraphIsComplement(pGraph) ); + } + else if ( Dec_GraphIsVar(pGraph) ) // literal + { + Pos = Dec_GraphPrintOutputName( pFile, pNameOut, 0 ); + Dec_GraphPrintGetLeafName( pFile, Dec_GraphVarInt(pGraph), Dec_GraphIsComplement(pGraph), pNamesIn ); + } + else + { + Pos = Dec_GraphPrintOutputName( pFile, pNameOut, Dec_GraphIsComplement(pGraph) ); + Dec_GraphPrint_rec( pFile, pGraph, Dec_GraphNodeLast(pGraph), 0, pNamesIn, &Pos, LitSizeMax ); + } + fprintf( pFile, "\n" ); + + if ( vNamesIn ) + Abc_NodeFreeNames( vNamesIn ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Dec_GraphPrint2_rec( FILE * pFile, Dec_Graph_t * pGraph, Dec_Node_t * pNode, int fCompl, char * pNamesIn[], int * pPos, int LitSizeMax ) +{ + Dec_Node_t * pNode0, * pNode1; + pNode0 = Dec_GraphNode(pGraph, pNode->eEdge0.Node); + pNode1 = Dec_GraphNode(pGraph, pNode->eEdge1.Node); + if ( Dec_GraphNodeIsVar(pGraph, pNode) ) // FT_NODE_LEAF ) + { + (*pPos) += Dec_GraphPrintGetLeafName( pFile, Dec_GraphNodeInt(pGraph,pNode), fCompl, pNamesIn ); + return; + } + if ( !pNode->fNodeOr ) // FT_NODE_AND ) + { + if ( !pNode0->fNodeOr ) // != FT_NODE_OR ) + Dec_GraphPrint_rec( pFile, pGraph, pNode0, pNode->fCompl0, pNamesIn, pPos, LitSizeMax ); + else + { + fprintf( pFile, "(" ); + (*pPos)++; + Dec_GraphPrint_rec( pFile, pGraph, pNode0, pNode->fCompl0, pNamesIn, pPos, LitSizeMax ); + fprintf( pFile, ")" ); + (*pPos)++; + } + fprintf( pFile, " " ); + (*pPos)++; + + Dec_GraphPrintUpdatePos( pFile, pPos, LitSizeMax ); + + if ( !pNode1->fNodeOr ) // != FT_NODE_OR ) + Dec_GraphPrint_rec( pFile, pGraph, pNode1, pNode->fCompl1, pNamesIn, pPos, LitSizeMax ); + else + { + fprintf( pFile, "(" ); + (*pPos)++; + Dec_GraphPrint_rec( pFile, pGraph, pNode1, pNode->fCompl1, pNamesIn, pPos, LitSizeMax ); + fprintf( pFile, ")" ); + (*pPos)++; + } + return; + } + if ( pNode->fNodeOr ) // FT_NODE_OR ) + { + Dec_GraphPrint_rec( pFile, pGraph, pNode0, pNode->fCompl0, pNamesIn, pPos, LitSizeMax ); + fprintf( pFile, " + " ); + (*pPos) += 3; + + Dec_GraphPrintUpdatePos( pFile, pPos, LitSizeMax ); + + Dec_GraphPrint_rec( pFile, pGraph, pNode1, pNode->fCompl1, pNamesIn, pPos, LitSizeMax ); + return; + } + assert( 0 ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Dec_GraphPrint_rec( FILE * pFile, Dec_Graph_t * pGraph, Dec_Node_t * pNode, int fCompl, char * pNamesIn[], int * pPos, int LitSizeMax ) +{ + Dec_Node_t * pNode0, * pNode1; + Dec_Node_t * pNode00, * pNode01, * pNode10, * pNode11; + pNode0 = Dec_GraphNode(pGraph, pNode->eEdge0.Node); + pNode1 = Dec_GraphNode(pGraph, pNode->eEdge1.Node); + if ( Dec_GraphNodeIsVar(pGraph, pNode) ) // FT_NODE_LEAF ) + { + (*pPos) += Dec_GraphPrintGetLeafName( pFile, Dec_GraphNodeInt(pGraph,pNode), fCompl, pNamesIn ); + return; + } + if ( !Dec_GraphNodeIsVar(pGraph, pNode0) && !Dec_GraphNodeIsVar(pGraph, pNode1) ) + { + pNode00 = Dec_GraphNode(pGraph, pNode0->eEdge0.Node); + pNode01 = Dec_GraphNode(pGraph, pNode0->eEdge1.Node); + pNode10 = Dec_GraphNode(pGraph, pNode1->eEdge0.Node); + pNode11 = Dec_GraphNode(pGraph, pNode1->eEdge1.Node); + if ( (pNode00 == pNode10 || pNode00 == pNode11) && (pNode01 == pNode10 || pNode01 == pNode11) ) + { + fprintf( pFile, "(" ); + (*pPos)++; + Dec_GraphPrint_rec( pFile, pGraph, pNode00, pNode00->fCompl0, pNamesIn, pPos, LitSizeMax ); + fprintf( pFile, " # " ); + (*pPos) += 3; + Dec_GraphPrint_rec( pFile, pGraph, pNode01, pNode01->fCompl1, pNamesIn, pPos, LitSizeMax ); + fprintf( pFile, ")" ); + (*pPos)++; + return; + } + } + if ( fCompl ) + { + fprintf( pFile, "(" ); + (*pPos)++; + Dec_GraphPrint_rec( pFile, pGraph, pNode0, !pNode->fCompl0, pNamesIn, pPos, LitSizeMax ); + fprintf( pFile, " + " ); + (*pPos) += 3; + Dec_GraphPrint_rec( pFile, pGraph, pNode1, !pNode->fCompl1, pNamesIn, pPos, LitSizeMax ); + fprintf( pFile, ")" ); + (*pPos)++; + } + else + { + fprintf( pFile, "(" ); + (*pPos)++; + Dec_GraphPrint_rec( pFile, pGraph, pNode0, pNode->fCompl0, pNamesIn, pPos, LitSizeMax ); + Dec_GraphPrint_rec( pFile, pGraph, pNode1, pNode->fCompl1, pNamesIn, pPos, LitSizeMax ); + fprintf( pFile, ")" ); + (*pPos)++; + } +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Dec_GraphPrintGetLeafName( FILE * pFile, int iLeaf, int fCompl, char * pNamesIn[] ) +{ + static char Buffer[100]; + sprintf( Buffer, "%s%s", pNamesIn[iLeaf], fCompl? "\'" : "" ); + fprintf( pFile, "%s", Buffer ); + return strlen( Buffer ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Dec_GraphPrintUpdatePos( FILE * pFile, int * pPos, int LitSizeMax ) +{ + int i; + if ( *pPos + LitSizeMax < 77 ) + return; + fprintf( pFile, "\n" ); + for ( i = 0; i < 10; i++ ) + fprintf( pFile, " " ); + *pPos = 10; +} + +/**Function************************************************************* + + Synopsis [Starts the printout for a decomposition graph.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Dec_GraphPrintOutputName( FILE * pFile, char * pNameOut, int fCompl ) +{ + if ( pNameOut == NULL ) + return 0; + fprintf( pFile, "%6s%s = ", pNameOut, fCompl? "\'" : " " ); + return 10; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/dec/decUtil.c b/src/opt/dec/decUtil.c new file mode 100644 index 00000000..463bc7e2 --- /dev/null +++ b/src/opt/dec/decUtil.c @@ -0,0 +1,134 @@ +/**CFile**************************************************************** + + FileName [decUtil.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Decomposition unitilies.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: decUtil.c,v 1.1 2003/05/22 19:20:05 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "dec.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Converts graph to BDD.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Dec_GraphDeriveBdd( DdManager * dd, Dec_Graph_t * pGraph ) +{ + DdNode * bFunc, * bFunc0, * bFunc1; + Dec_Node_t * pNode; + int i; + + // sanity checks + assert( Dec_GraphLeaveNum(pGraph) >= 0 ); + assert( Dec_GraphLeaveNum(pGraph) <= pGraph->nSize ); + + // check for constant function + if ( Dec_GraphIsConst(pGraph) ) + return Cudd_NotCond( b1, Dec_GraphIsComplement(pGraph) ); + // check for a literal + if ( Dec_GraphIsVar(pGraph) ) + return Cudd_NotCond( Cudd_bddIthVar(dd, Dec_GraphVarInt(pGraph)), Dec_GraphIsComplement(pGraph) ); + + // assign the elementary variables + Dec_GraphForEachLeaf( pGraph, pNode, i ) + pNode->pFunc = Cudd_bddIthVar( dd, i ); + + // compute the function for each internal node + Dec_GraphForEachNode( pGraph, pNode, i ) + { + bFunc0 = Cudd_NotCond( Dec_GraphNode(pGraph, pNode->eEdge0.Node)->pFunc, pNode->eEdge0.fCompl ); + bFunc1 = Cudd_NotCond( Dec_GraphNode(pGraph, pNode->eEdge1.Node)->pFunc, pNode->eEdge1.fCompl ); + pNode->pFunc = Cudd_bddAnd( dd, bFunc0, bFunc1 ); Cudd_Ref( pNode->pFunc ); + } + + // deref the intermediate results + bFunc = pNode->pFunc; Cudd_Ref( bFunc ); + Dec_GraphForEachNode( pGraph, pNode, i ) + Cudd_RecursiveDeref( dd, pNode->pFunc ); + Cudd_Deref( bFunc ); + + // complement the result if necessary + return Cudd_NotCond( bFunc, Dec_GraphIsComplement(pGraph) ); +} + +/**Function************************************************************* + + Synopsis [Derives the truth table.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned Dec_GraphDeriveTruth( Dec_Graph_t * pGraph ) +{ + unsigned uTruths[5] = { 0xAAAAAAAA, 0xCCCCCCCC, 0xF0F0F0F0, 0xFF00FF00, 0xFFFF0000 }; + unsigned uTruth, uTruth0, uTruth1; + Dec_Node_t * pNode; + int i; + + // sanity checks + assert( Dec_GraphLeaveNum(pGraph) >= 0 ); + assert( Dec_GraphLeaveNum(pGraph) <= pGraph->nSize ); + assert( Dec_GraphLeaveNum(pGraph) <= 5 ); + + // check for constant function + if ( Dec_GraphIsConst(pGraph) ) + return Dec_GraphIsComplement(pGraph)? 0 : ~((unsigned)0); + // check for a literal + if ( Dec_GraphIsVar(pGraph) ) + return Dec_GraphIsComplement(pGraph)? ~uTruths[Dec_GraphVarInt(pGraph)] : uTruths[Dec_GraphVarInt(pGraph)]; + + // assign the elementary variables + Dec_GraphForEachLeaf( pGraph, pNode, i ) + pNode->pFunc = (void *)uTruths[i]; + + // compute the function for each internal node + Dec_GraphForEachNode( pGraph, pNode, i ) + { + uTruth0 = (unsigned)Dec_GraphNode(pGraph, pNode->eEdge0.Node)->pFunc; + uTruth1 = (unsigned)Dec_GraphNode(pGraph, pNode->eEdge1.Node)->pFunc; + uTruth0 = pNode->eEdge0.fCompl? ~uTruth0 : uTruth0; + uTruth1 = pNode->eEdge1.fCompl? ~uTruth1 : uTruth1; + uTruth = uTruth0 & uTruth1; + pNode->pFunc = (void *)uTruth; + } + + // complement the result if necessary + return Dec_GraphIsComplement(pGraph)? ~uTruth : uTruth; +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/dec/module.make b/src/opt/dec/module.make new file mode 100644 index 00000000..1e0722d5 --- /dev/null +++ b/src/opt/dec/module.make @@ -0,0 +1,5 @@ +SRC += src/opt/dec/decAbc.c \ + src/opt/dec/decFactor.c \ + src/opt/dec/decMan.c \ + src/opt/dec/decPrint.c \ + src/opt/dec/decUtil.c diff --git a/src/opt/fxu/fxu.c b/src/opt/fxu/fxu.c new file mode 100644 index 00000000..d11fd793 --- /dev/null +++ b/src/opt/fxu/fxu.c @@ -0,0 +1,254 @@ +/**CFile**************************************************************** + + FileName [fxu.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [The entrance into the fast extract module.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: fxu.c,v 1.0 2003/02/01 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "fxuInt.h" +#include "fxu.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +/*===== fxuCreate.c ====================================================*/ +extern Fxu_Matrix * Fxu_CreateMatrix( Fxu_Data_t * pData ); +extern void Fxu_CreateCovers( Fxu_Matrix * p, Fxu_Data_t * pData ); + +static int s_MemoryTotal; +static int s_MemoryPeak; + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Performs fast_extract on a set of covers.] + + Description [All the covers are given in the array p->vSops. + The resulting covers are returned in the array p->vSopsNew. + The entries in these arrays correspond to objects in the network. + The entries corresponding to the PI and objects with trivial covers are NULL. + The number of extracted covers (not exceeding p->nNodesExt) is returned. + Two other things are important for the correct operation of this procedure: + (1) The input covers do not have duplicated fanins and are SCC-free. + (2) The fanins array contains the numbers of the fanin objects.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Fxu_FastExtract( Fxu_Data_t * pData ) +{ + Fxu_Matrix * p; + Fxu_Single * pSingle; + Fxu_Double * pDouble; + int Weight1, Weight2, Weight3; + int Counter = 0; + + s_MemoryTotal = 0; + s_MemoryPeak = 0; + + // create the matrix + p = Fxu_CreateMatrix( pData ); + if ( p == NULL ) + return -1; +// if ( pData->fVerbose ) +// printf( "Memory usage after construction: Total = %d. Peak = %d.\n", s_MemoryTotal, s_MemoryPeak ); +//Fxu_MatrixPrint( NULL, p ); + + if ( pData->fOnlyS ) + { + pData->nNodesNew = 0; + do + { + Weight1 = Fxu_HeapSingleReadMaxWeight( p->pHeapSingle ); + if ( pData->fVerbose ) + printf( "Div %5d : Best single = %5d.\r", Counter++, Weight1 ); + if ( Weight1 > 0 || Weight1 == 0 && pData->fUse0 ) + Fxu_UpdateSingle( p ); + else + break; + } + while ( ++pData->nNodesNew < pData->nNodesExt ); + } + else if ( pData->fOnlyD ) + { + pData->nNodesNew = 0; + do + { + Weight2 = Fxu_HeapDoubleReadMaxWeight( p->pHeapDouble ); + if ( pData->fVerbose ) + printf( "Div %5d : Best double = %5d.\r", Counter++, Weight2 ); + if ( Weight2 > 0 || Weight2 == 0 && pData->fUse0 ) + Fxu_UpdateDouble( p ); + else + break; + } + while ( ++pData->nNodesNew < pData->nNodesExt ); + } + else if ( !pData->fUseCompl ) + { + pData->nNodesNew = 0; + do + { + Weight1 = Fxu_HeapSingleReadMaxWeight( p->pHeapSingle ); + Weight2 = Fxu_HeapDoubleReadMaxWeight( p->pHeapDouble ); + + if ( pData->fVerbose ) + printf( "Div %5d : Best double = %5d. Best single = %5d.\r", Counter++, Weight2, Weight1 ); +//Fxu_Select( p, &pSingle, &pDouble ); + + if ( Weight1 >= Weight2 ) + { + if ( Weight1 > 0 || Weight1 == 0 && pData->fUse0 ) + Fxu_UpdateSingle( p ); + else + break; + } + else + { + if ( Weight2 > 0 || Weight2 == 0 && pData->fUse0 ) + Fxu_UpdateDouble( p ); + else + break; + } + } + while ( ++pData->nNodesNew < pData->nNodesExt ); + } + else + { // use the complement + pData->nNodesNew = 0; + do + { + Weight1 = Fxu_HeapSingleReadMaxWeight( p->pHeapSingle ); + Weight2 = Fxu_HeapDoubleReadMaxWeight( p->pHeapDouble ); + + // select the best single and double + Weight3 = Fxu_Select( p, &pSingle, &pDouble ); + if ( pData->fVerbose ) + printf( "Div %5d : Best double = %5d. Best single = %5d. Best complement = %5d.\r", + Counter++, Weight2, Weight1, Weight3 ); + + if ( Weight3 > 0 || Weight3 == 0 && pData->fUse0 ) + Fxu_Update( p, pSingle, pDouble ); + else + break; + } + while ( ++pData->nNodesNew < pData->nNodesExt ); + } + + if ( pData->fVerbose ) + printf( "Total single = %3d. Total double = %3d. Total compl = %3d. \n", + p->nDivs1, p->nDivs2, p->nDivs3 ); + + // create the new covers + if ( pData->nNodesNew ) + Fxu_CreateCovers( p, pData ); + Fxu_MatrixDelete( p ); +// printf( "Memory usage after deallocation: Total = %d. Peak = %d.\n", s_MemoryTotal, s_MemoryPeak ); + if ( pData->nNodesNew == pData->nNodesExt ) + printf( "Warning: The limit on the number of extracted divisors has been reached.\n" ); + return pData->nNodesNew; +} + + +/**Function************************************************************* + + Synopsis [Unmarks the cubes in the ring.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_MatrixRingCubesUnmark( Fxu_Matrix * p ) +{ + Fxu_Cube * pCube, * pCube2; + // unmark the cubes + Fxu_MatrixForEachCubeInRingSafe( p, pCube, pCube2 ) + pCube->pOrder = NULL; + Fxu_MatrixRingCubesReset( p ); +} + + +/**Function************************************************************* + + Synopsis [Unmarks the vars in the ring.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_MatrixRingVarsUnmark( Fxu_Matrix * p ) +{ + Fxu_Var * pVar, * pVar2; + // unmark the vars + Fxu_MatrixForEachVarInRingSafe( p, pVar, pVar2 ) + pVar->pOrder = NULL; + Fxu_MatrixRingVarsReset( p ); +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +char * Fxu_MemFetch( Fxu_Matrix * p, int nBytes ) +{ + s_MemoryTotal += nBytes; + if ( s_MemoryPeak < s_MemoryTotal ) + s_MemoryPeak = s_MemoryTotal; +// return malloc( nBytes ); + return Extra_MmFixedEntryFetch( p->pMemMan ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_MemRecycle( Fxu_Matrix * p, char * pItem, int nBytes ) +{ + s_MemoryTotal -= nBytes; +// free( pItem ); + Extra_MmFixedEntryRecycle( p->pMemMan, pItem ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/fxu/fxu.h b/src/opt/fxu/fxu.h new file mode 100644 index 00000000..e6d0b69e --- /dev/null +++ b/src/opt/fxu/fxu.h @@ -0,0 +1,93 @@ +/**CFile**************************************************************** + + FileName [fxu.h] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [External declarations of fast extract for unate covers.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: fxu.h,v 1.0 2003/02/01 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef __FXU_H__ +#define __FXU_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +#include "vec.h" + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// STRUCTURE DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +#ifndef __cplusplus +#ifndef bool +#define bool int +#endif +#endif + +typedef struct FxuDataStruct Fxu_Data_t; + +// structure for the FX input/output data +struct FxuDataStruct +{ + // user specified parameters + bool fOnlyS; // set to 1 to have only single-cube divs + bool fOnlyD; // set to 1 to have only double-cube divs + bool fUse0; // set to 1 to have 0-weight also extracted + bool fUseCompl; // set to 1 to have complement taken into account + bool fVerbose; // set to 1 to have verbose output + int nNodesExt; // the number of divisors to extract + int nSingleMax; // the max number of single-cube divisors to consider + int nPairsMax; // the max number of double-cube divisors to consider + // the input information + Vec_Ptr_t * vSops; // the SOPs for each node in the network + Vec_Ptr_t * vFanins; // the fanins of each node in the network + // output information + Vec_Ptr_t * vSopsNew; // the SOPs for each node in the network after extraction + Vec_Ptr_t * vFaninsNew; // the fanins of each node in the network after extraction + // the SOP manager + Extra_MmFlex_t * pManSop; + // statistics + int nNodesOld; // the old number of nodes + int nNodesNew; // the number of divisors actually extracted +}; + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/*===== fxu.c ==========================================================*/ +extern int Fxu_FastExtract( Fxu_Data_t * pData ); + +#ifdef __cplusplus +} +#endif + +#endif + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + diff --git a/src/opt/fxu/fxuCreate.c b/src/opt/fxu/fxuCreate.c new file mode 100644 index 00000000..55026b27 --- /dev/null +++ b/src/opt/fxu/fxuCreate.c @@ -0,0 +1,431 @@ +/**CFile**************************************************************** + + FileName [fxuCreate.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Create matrix from covers and covers from matrix.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: fxuCreate.c,v 1.0 2003/02/01 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "fxuInt.h" +#include "fxu.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static void Fxu_CreateMatrixAddCube( Fxu_Matrix * p, Fxu_Cube * pCube, char * pSopCube, Vec_Int_t * vFanins, int * pOrder ); +static int Fxu_CreateMatrixLitCompare( int * ptrX, int * ptrY ); +static void Fxu_CreateCoversNode( Fxu_Matrix * p, Fxu_Data_t * pData, int iNode, Fxu_Cube * pCubeFirst, Fxu_Cube * pCubeNext ); +static Fxu_Cube * Fxu_CreateCoversFirstCube( Fxu_Matrix * p, Fxu_Data_t * pData, int iNode ); +static int * s_pLits; + +extern int Fxu_PreprocessCubePairs( Fxu_Matrix * p, Vec_Ptr_t * vCovers, int nPairsTotal, int nPairsMax ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Creates the sparse matrix from the array of SOPs.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Fxu_Matrix * Fxu_CreateMatrix( Fxu_Data_t * pData ) +{ + Fxu_Matrix * p; + Fxu_Var * pVar; + Fxu_Cube * pCubeFirst, * pCubeNew; + Fxu_Cube * pCube1, * pCube2; + Vec_Int_t * vFanins; + char * pSopCover; + char * pSopCube; + int * pOrder, nBitsMax; + int i, v, c; + int nCubesTotal; + int nPairsTotal; + int nPairsStore; + int nCubes; + int iCube, iPair; + int nFanins; + + // collect all sorts of statistics + nCubesTotal = 0; + nPairsTotal = 0; + nPairsStore = 0; + nBitsMax = -1; + for ( i = 0; i < pData->nNodesOld; i++ ) + if ( pSopCover = pData->vSops->pArray[i] ) + { + nCubes = Abc_SopGetCubeNum( pSopCover ); + nFanins = Abc_SopGetVarNum( pSopCover ); + assert( nFanins > 1 && nCubes > 0 ); + + nCubesTotal += nCubes; + nPairsTotal += nCubes * (nCubes - 1) / 2; + nPairsStore += nCubes * nCubes; + if ( nBitsMax < nFanins ) + nBitsMax = nFanins; + } + if ( nBitsMax <= 0 ) + { + printf( "The current network does not have SOPs to perform extraction.\n" ); + return NULL; + } + + if ( nPairsStore > 50000000 ) + { + printf( "The problem is too large to be solved by \"fxu\" (%d cubes and %d cube pairs)\n", nCubesTotal, nPairsStore ); + return NULL; + } + + // start the matrix + p = Fxu_MatrixAllocate(); + // create the column labels + p->ppVars = ALLOC( Fxu_Var *, 2 * (pData->nNodesOld + pData->nNodesExt) ); + for ( i = 0; i < 2 * pData->nNodesOld; i++ ) + p->ppVars[i] = Fxu_MatrixAddVar( p ); + + // allocate storage for all cube pairs at once + p->pppPairs = ALLOC( Fxu_Pair **, nCubesTotal + 100 ); + p->ppPairs = ALLOC( Fxu_Pair *, nPairsStore + 100 ); + memset( p->ppPairs, 0, sizeof(Fxu_Pair *) * nPairsStore ); + iCube = 0; + iPair = 0; + for ( i = 0; i < pData->nNodesOld; i++ ) + if ( pSopCover = pData->vSops->pArray[i] ) + { + // get the number of cubes + nCubes = Abc_SopGetCubeNum( pSopCover ); + // get the new var in the matrix + pVar = p->ppVars[2*i+1]; + // assign the pair storage + pVar->nCubes = nCubes; + if ( nCubes > 0 ) + { + pVar->ppPairs = p->pppPairs + iCube; + pVar->ppPairs[0] = p->ppPairs + iPair; + for ( v = 1; v < nCubes; v++ ) + pVar->ppPairs[v] = pVar->ppPairs[v-1] + nCubes; + } + // update + iCube += nCubes; + iPair += nCubes * nCubes; + } + assert( iCube == nCubesTotal ); + assert( iPair == nPairsStore ); + + + // allocate room for the reordered literals + pOrder = ALLOC( int, nBitsMax ); + // create the rows + for ( i = 0; i < pData->nNodesOld; i++ ) + if ( pSopCover = pData->vSops->pArray[i] ) + { + // get the new var in the matrix + pVar = p->ppVars[2*i+1]; + // here we sort the literals of the cover + // in the increasing order of the numbers of the corresponding nodes + // because literals should be added to the matrix in this order + vFanins = pData->vFanins->pArray[i]; + s_pLits = vFanins->pArray; + // start the variable order + nFanins = Abc_SopGetVarNum( pSopCover ); + for ( v = 0; v < nFanins; v++ ) + pOrder[v] = v; + // reorder the fanins + qsort( (void *)pOrder, nFanins, sizeof(int),(int (*)(const void *, const void *))Fxu_CreateMatrixLitCompare); + assert( s_pLits[ pOrder[0] ] < s_pLits[ pOrder[nFanins-1] ] ); + // create the corresponding cubes in the matrix + pCubeFirst = NULL; + c = 0; + Abc_SopForEachCube( pSopCover, nFanins, pSopCube ) + { + // create the cube + pCubeNew = Fxu_MatrixAddCube( p, pVar, c++ ); + Fxu_CreateMatrixAddCube( p, pCubeNew, pSopCube, vFanins, pOrder ); + if ( pCubeFirst == NULL ) + pCubeFirst = pCubeNew; + pCubeNew->pFirst = pCubeFirst; + } + // set the first cube of this var + pVar->pFirst = pCubeFirst; + // create the divisors without preprocessing + if ( nPairsTotal <= pData->nPairsMax ) + { + for ( pCube1 = pCubeFirst; pCube1; pCube1 = pCube1->pNext ) + for ( pCube2 = pCube1? pCube1->pNext: NULL; pCube2; pCube2 = pCube2->pNext ) + Fxu_MatrixAddDivisor( p, pCube1, pCube2 ); + } + } + FREE( pOrder ); + + // consider the case when cube pairs should be preprocessed + // before adding them to the set of divisors +// if ( pData->fVerbose ) +// printf( "The total number of cube pairs is %d.\n", nPairsTotal ); + if ( nPairsTotal > 10000000 ) + { + printf( "The total number of cube pairs of the network is more than 10,000,000.\n" ); + printf( "Command \"fx\" takes a long time to run in such cases. It is suggested\n" ); + printf( "that the user changes the network by reducing the size of logic node and\n" ); + printf( "consequently the number of cube pairs to be processed by this command.\n" ); + printf( "One way to achieve this is to run the commands \"st; multi -m -F \"\n" ); + printf( "as a proprocessing step, while selecting as approapriate.\n" ); + return NULL; + } + if ( nPairsTotal > pData->nPairsMax ) + if ( !Fxu_PreprocessCubePairs( p, pData->vSops, nPairsTotal, pData->nPairsMax ) ) + return NULL; +// if ( pData->fVerbose ) +// printf( "Only %d best cube pairs will be used by the fast extract command.\n", pData->nPairsMax ); + + // add the var pairs to the heap + Fxu_MatrixComputeSingles( p, pData->fUse0, pData->nSingleMax ); + + // print stats + if ( pData->fVerbose ) + { + double Density; + Density = ((double)p->nEntries) / p->lVars.nItems / p->lCubes.nItems; + fprintf( stdout, "Matrix: [vars x cubes] = [%d x %d] ", + p->lVars.nItems, p->lCubes.nItems ); + fprintf( stdout, "Lits = %d Density = %.5f%%\n", + p->nEntries, Density ); + fprintf( stdout, "1-cube divs = %6d. (Total = %6d) ", p->lSingles.nItems, p->nSingleTotal ); + fprintf( stdout, "2-cube divs = %6d. (Total = %6d)", p->nDivsTotal, nPairsTotal ); + fprintf( stdout, "\n" ); + } +// Fxu_MatrixPrint( stdout, p ); + return p; +} + +/**Function************************************************************* + + Synopsis [Adds one cube with literals to the matrix.] + + Description [Create the cube and literals in the matrix corresponding + to the given cube in the SOP cover. Co-singleton transform is performed here.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_CreateMatrixAddCube( Fxu_Matrix * p, Fxu_Cube * pCube, char * pSopCube, Vec_Int_t * vFanins, int * pOrder ) +{ + Fxu_Var * pVar; + int Value, i; + // add literals to the matrix + Abc_CubeForEachVar( pSopCube, Value, i ) + { + Value = pSopCube[pOrder[i]]; + if ( Value == '0' ) + { + pVar = p->ppVars[ 2 * vFanins->pArray[pOrder[i]] + 1 ]; // CST + Fxu_MatrixAddLiteral( p, pCube, pVar ); + } + else if ( Value == '1' ) + { + pVar = p->ppVars[ 2 * vFanins->pArray[pOrder[i]] ]; // CST + Fxu_MatrixAddLiteral( p, pCube, pVar ); + } + } +} + + +/**Function************************************************************* + + Synopsis [Creates the new array of Sop covers from the sparse matrix.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_CreateCovers( Fxu_Matrix * p, Fxu_Data_t * pData ) +{ + Fxu_Cube * pCube, * pCubeFirst, * pCubeNext; + char * pSopCover; + int iNode, n; + + // get the first cube of the first internal node + pCubeFirst = Fxu_CreateCoversFirstCube( p, pData, 0 ); + + // go through the internal nodes + for ( n = 0; n < pData->nNodesOld; n++ ) + if ( pSopCover = pData->vSops->pArray[n] ) + { + // get the number of this node + iNode = n; + // get the next first cube + pCubeNext = Fxu_CreateCoversFirstCube( p, pData, iNode + 1 ); + // check if there any new variables in these cubes + for ( pCube = pCubeFirst; pCube != pCubeNext; pCube = pCube->pNext ) + if ( pCube->lLits.pTail && pCube->lLits.pTail->iVar >= 2 * pData->nNodesOld ) + break; + if ( pCube != pCubeNext ) + Fxu_CreateCoversNode( p, pData, iNode, pCubeFirst, pCubeNext ); + // update the first cube + pCubeFirst = pCubeNext; + } + + // add the covers for the extracted nodes + for ( n = 0; n < pData->nNodesNew; n++ ) + { + // get the number of this node + iNode = pData->nNodesOld + n; + // get the next first cube + pCubeNext = Fxu_CreateCoversFirstCube( p, pData, iNode + 1 ); + // the node should be added + Fxu_CreateCoversNode( p, pData, iNode, pCubeFirst, pCubeNext ); + // update the first cube + pCubeFirst = pCubeNext; + } +} + +/**Function************************************************************* + + Synopsis [Create Sop covers for one node that has changed.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_CreateCoversNode( Fxu_Matrix * p, Fxu_Data_t * pData, int iNode, Fxu_Cube * pCubeFirst, Fxu_Cube * pCubeNext ) +{ + Vec_Int_t * vInputsNew; + char * pSopCover, * pSopCube; + Fxu_Var * pVar; + Fxu_Cube * pCube; + Fxu_Lit * pLit; + int iNum, nCubes, v; + + // collect positive polarity variable in the cubes between pCubeFirst and pCubeNext + Fxu_MatrixRingVarsStart( p ); + for ( pCube = pCubeFirst; pCube != pCubeNext; pCube = pCube->pNext ) + for ( pLit = pCube->lLits.pHead; pLit; pLit = pLit->pHNext ) + { + pVar = p->ppVars[ 2 * (pLit->pVar->iVar/2) + 1 ]; + if ( pVar->pOrder == NULL ) + Fxu_MatrixRingVarsAdd( p, pVar ); + } + Fxu_MatrixRingVarsStop( p ); + + // collect the variable numbers + vInputsNew = Vec_IntAlloc( 4 ); + Fxu_MatrixForEachVarInRing( p, pVar ) + Vec_IntPush( vInputsNew, pVar->iVar / 2 ); + Fxu_MatrixRingVarsUnmark( p ); + + // sort the vars by their number + Vec_IntSort( vInputsNew, 0 ); + + // mark the vars with their numbers in the sorted array + for ( v = 0; v < vInputsNew->nSize; v++ ) + { + p->ppVars[ 2 * vInputsNew->pArray[v] + 0 ]->lLits.nItems = v; // hack - reuse lLits.nItems + p->ppVars[ 2 * vInputsNew->pArray[v] + 1 ]->lLits.nItems = v; // hack - reuse lLits.nItems + } + + // count the number of cubes + nCubes = 0; + for ( pCube = pCubeFirst; pCube != pCubeNext; pCube = pCube->pNext ) + if ( pCube->lLits.nItems ) + nCubes++; + + // allocate room for the new cover + pSopCover = Abc_SopStart( pData->pManSop, nCubes, vInputsNew->nSize ); + // set the correct polarity of the cover + if ( iNode < pData->nNodesOld && Abc_SopGetPhase( pData->vSops->pArray[iNode] ) == 0 ) + Abc_SopComplement( pSopCover ); + + // add the cubes + nCubes = 0; + for ( pCube = pCubeFirst; pCube != pCubeNext; pCube = pCube->pNext ) + { + if ( pCube->lLits.nItems == 0 ) + continue; + // get hold of the SOP cube + pSopCube = pSopCover + nCubes * (vInputsNew->nSize + 3); + // insert literals + for ( pLit = pCube->lLits.pHead; pLit; pLit = pLit->pHNext ) + { + iNum = pLit->pVar->lLits.nItems; // hack - reuse lLits.nItems + assert( iNum < vInputsNew->nSize ); + if ( pLit->pVar->iVar / 2 < pData->nNodesOld ) + pSopCube[iNum] = (pLit->pVar->iVar & 1)? '0' : '1'; // reverse CST + else + pSopCube[iNum] = (pLit->pVar->iVar & 1)? '1' : '0'; // no CST + } + // count the cube + nCubes++; + } + assert( nCubes == Abc_SopGetCubeNum(pSopCover) ); + + // set the new cover and the array of fanins + pData->vSopsNew->pArray[iNode] = pSopCover; + pData->vFaninsNew->pArray[iNode] = vInputsNew; +} + + +/**Function************************************************************* + + Synopsis [Adds the var to storage.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Fxu_Cube * Fxu_CreateCoversFirstCube( Fxu_Matrix * p, Fxu_Data_t * pData, int iVar ) +{ + int v; + for ( v = iVar; v < pData->nNodesOld + pData->nNodesNew; v++ ) + if ( p->ppVars[ 2*v + 1 ]->pFirst ) + return p->ppVars[ 2*v + 1 ]->pFirst; + return NULL; +} + +/**Function************************************************************* + + Synopsis [Compares the vars by their number.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Fxu_CreateMatrixLitCompare( int * ptrX, int * ptrY ) +{ + return s_pLits[*ptrX] - s_pLits[*ptrY]; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// diff --git a/src/opt/fxu/fxuHeapD.c b/src/opt/fxu/fxuHeapD.c new file mode 100644 index 00000000..c81ad818 --- /dev/null +++ b/src/opt/fxu/fxuHeapD.c @@ -0,0 +1,445 @@ +/**CFile**************************************************************** + + FileName [fxuHeapD.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [The priority queue for double cube divisors.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: fxuHeapD.c,v 1.0 2003/02/01 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "fxuInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +#define FXU_HEAP_DOUBLE_WEIGHT(pDiv) ((pDiv)->Weight) +#define FXU_HEAP_DOUBLE_CURRENT(p, pDiv) ((p)->pTree[(pDiv)->HNum]) +#define FXU_HEAP_DOUBLE_PARENT_EXISTS(p, pDiv) ((pDiv)->HNum > 1) +#define FXU_HEAP_DOUBLE_CHILD1_EXISTS(p, pDiv) (((pDiv)->HNum << 1) <= p->nItems) +#define FXU_HEAP_DOUBLE_CHILD2_EXISTS(p, pDiv) ((((pDiv)->HNum << 1)+1) <= p->nItems) +#define FXU_HEAP_DOUBLE_PARENT(p, pDiv) ((p)->pTree[(pDiv)->HNum >> 1]) +#define FXU_HEAP_DOUBLE_CHILD1(p, pDiv) ((p)->pTree[(pDiv)->HNum << 1]) +#define FXU_HEAP_DOUBLE_CHILD2(p, pDiv) ((p)->pTree[((pDiv)->HNum << 1)+1]) +#define FXU_HEAP_DOUBLE_ASSERT(p, pDiv) assert( (pDiv)->HNum >= 1 && (pDiv)->HNum <= p->nItemsAlloc ) + +static void Fxu_HeapDoubleResize( Fxu_HeapDouble * p ); +static void Fxu_HeapDoubleSwap( Fxu_Double ** pDiv1, Fxu_Double ** pDiv2 ); +static void Fxu_HeapDoubleMoveUp( Fxu_HeapDouble * p, Fxu_Double * pDiv ); +static void Fxu_HeapDoubleMoveDn( Fxu_HeapDouble * p, Fxu_Double * pDiv ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Fxu_HeapDouble * Fxu_HeapDoubleStart() +{ + Fxu_HeapDouble * p; + p = ALLOC( Fxu_HeapDouble, 1 ); + memset( p, 0, sizeof(Fxu_HeapDouble) ); + p->nItems = 0; + p->nItemsAlloc = 10000; + p->pTree = ALLOC( Fxu_Double *, p->nItemsAlloc + 1 ); + p->pTree[0] = NULL; + return p; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_HeapDoubleResize( Fxu_HeapDouble * p ) +{ + p->nItemsAlloc *= 2; + p->pTree = REALLOC( Fxu_Double *, p->pTree, p->nItemsAlloc + 1 ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_HeapDoubleStop( Fxu_HeapDouble * p ) +{ + free( p->pTree ); + free( p ); +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_HeapDoublePrint( FILE * pFile, Fxu_HeapDouble * p ) +{ + Fxu_Double * pDiv; + int Counter = 1; + int Degree = 1; + + Fxu_HeapDoubleCheck( p ); + fprintf( pFile, "The contents of the heap:\n" ); + fprintf( pFile, "Level %d: ", Degree ); + Fxu_HeapDoubleForEachItem( p, pDiv ) + { + assert( Counter == p->pTree[Counter]->HNum ); + fprintf( pFile, "%2d=%3d ", Counter, FXU_HEAP_DOUBLE_WEIGHT(p->pTree[Counter]) ); + if ( ++Counter == (1 << Degree) ) + { + fprintf( pFile, "\n" ); + Degree++; + fprintf( pFile, "Level %d: ", Degree ); + } + } + fprintf( pFile, "\n" ); + fprintf( pFile, "End of the heap printout.\n" ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_HeapDoubleCheck( Fxu_HeapDouble * p ) +{ + Fxu_Double * pDiv; + Fxu_HeapDoubleForEachItem( p, pDiv ) + { + assert( pDiv->HNum == p->i ); + Fxu_HeapDoubleCheckOne( p, pDiv ); + } +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_HeapDoubleCheckOne( Fxu_HeapDouble * p, Fxu_Double * pDiv ) +{ + int Weight1, Weight2; + if ( FXU_HEAP_DOUBLE_CHILD1_EXISTS(p,pDiv) ) + { + Weight1 = FXU_HEAP_DOUBLE_WEIGHT(pDiv); + Weight2 = FXU_HEAP_DOUBLE_WEIGHT( FXU_HEAP_DOUBLE_CHILD1(p,pDiv) ); + assert( Weight1 >= Weight2 ); + } + if ( FXU_HEAP_DOUBLE_CHILD2_EXISTS(p,pDiv) ) + { + Weight1 = FXU_HEAP_DOUBLE_WEIGHT(pDiv); + Weight2 = FXU_HEAP_DOUBLE_WEIGHT( FXU_HEAP_DOUBLE_CHILD2(p,pDiv) ); + assert( Weight1 >= Weight2 ); + } +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_HeapDoubleInsert( Fxu_HeapDouble * p, Fxu_Double * pDiv ) +{ + if ( p->nItems == p->nItemsAlloc ) + Fxu_HeapDoubleResize( p ); + // put the last entry to the last place and move up + p->pTree[++p->nItems] = pDiv; + pDiv->HNum = p->nItems; + // move the last entry up if necessary + Fxu_HeapDoubleMoveUp( p, pDiv ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_HeapDoubleUpdate( Fxu_HeapDouble * p, Fxu_Double * pDiv ) +{ +//printf( "Updating divisor %d.\n", pDiv->Num ); + + FXU_HEAP_DOUBLE_ASSERT(p,pDiv); + if ( FXU_HEAP_DOUBLE_PARENT_EXISTS(p,pDiv) && + FXU_HEAP_DOUBLE_WEIGHT(pDiv) > FXU_HEAP_DOUBLE_WEIGHT( FXU_HEAP_DOUBLE_PARENT(p,pDiv) ) ) + Fxu_HeapDoubleMoveUp( p, pDiv ); + else if ( FXU_HEAP_DOUBLE_CHILD1_EXISTS(p,pDiv) && + FXU_HEAP_DOUBLE_WEIGHT(pDiv) < FXU_HEAP_DOUBLE_WEIGHT( FXU_HEAP_DOUBLE_CHILD1(p,pDiv) ) ) + Fxu_HeapDoubleMoveDn( p, pDiv ); + else if ( FXU_HEAP_DOUBLE_CHILD2_EXISTS(p,pDiv) && + FXU_HEAP_DOUBLE_WEIGHT(pDiv) < FXU_HEAP_DOUBLE_WEIGHT( FXU_HEAP_DOUBLE_CHILD2(p,pDiv) ) ) + Fxu_HeapDoubleMoveDn( p, pDiv ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_HeapDoubleDelete( Fxu_HeapDouble * p, Fxu_Double * pDiv ) +{ + FXU_HEAP_DOUBLE_ASSERT(p,pDiv); + // put the last entry to the deleted place + // decrement the number of entries + p->pTree[pDiv->HNum] = p->pTree[p->nItems--]; + p->pTree[pDiv->HNum]->HNum = pDiv->HNum; + // move the top entry down if necessary + Fxu_HeapDoubleUpdate( p, p->pTree[pDiv->HNum] ); + pDiv->HNum = 0; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Fxu_Double * Fxu_HeapDoubleReadMax( Fxu_HeapDouble * p ) +{ + if ( p->nItems == 0 ) + return NULL; + return p->pTree[1]; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Fxu_Double * Fxu_HeapDoubleGetMax( Fxu_HeapDouble * p ) +{ + Fxu_Double * pDiv; + if ( p->nItems == 0 ) + return NULL; + // prepare the return value + pDiv = p->pTree[1]; + pDiv->HNum = 0; + // put the last entry on top + // decrement the number of entries + p->pTree[1] = p->pTree[p->nItems--]; + p->pTree[1]->HNum = 1; + // move the top entry down if necessary + Fxu_HeapDoubleMoveDn( p, p->pTree[1] ); + return pDiv; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Fxu_HeapDoubleReadMaxWeight( Fxu_HeapDouble * p ) +{ + if ( p->nItems == 0 ) + return -1; + else + return FXU_HEAP_DOUBLE_WEIGHT(p->pTree[1]); +} + + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_HeapDoubleSwap( Fxu_Double ** pDiv1, Fxu_Double ** pDiv2 ) +{ + Fxu_Double * pDiv; + int Temp; + pDiv = *pDiv1; + *pDiv1 = *pDiv2; + *pDiv2 = pDiv; + Temp = (*pDiv1)->HNum; + (*pDiv1)->HNum = (*pDiv2)->HNum; + (*pDiv2)->HNum = Temp; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_HeapDoubleMoveUp( Fxu_HeapDouble * p, Fxu_Double * pDiv ) +{ + Fxu_Double ** ppDiv, ** ppPar; + ppDiv = &FXU_HEAP_DOUBLE_CURRENT(p, pDiv); + while ( FXU_HEAP_DOUBLE_PARENT_EXISTS(p,*ppDiv) ) + { + ppPar = &FXU_HEAP_DOUBLE_PARENT(p,*ppDiv); + if ( FXU_HEAP_DOUBLE_WEIGHT(*ppDiv) > FXU_HEAP_DOUBLE_WEIGHT(*ppPar) ) + { + Fxu_HeapDoubleSwap( ppDiv, ppPar ); + ppDiv = ppPar; + } + else + break; + } +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_HeapDoubleMoveDn( Fxu_HeapDouble * p, Fxu_Double * pDiv ) +{ + Fxu_Double ** ppChild1, ** ppChild2, ** ppDiv; + ppDiv = &FXU_HEAP_DOUBLE_CURRENT(p, pDiv); + while ( FXU_HEAP_DOUBLE_CHILD1_EXISTS(p,*ppDiv) ) + { // if Child1 does not exist, Child2 also does not exists + + // get the children + ppChild1 = &FXU_HEAP_DOUBLE_CHILD1(p,*ppDiv); + if ( FXU_HEAP_DOUBLE_CHILD2_EXISTS(p,*ppDiv) ) + { + ppChild2 = &FXU_HEAP_DOUBLE_CHILD2(p,*ppDiv); + + // consider two cases + if ( FXU_HEAP_DOUBLE_WEIGHT(*ppDiv) >= FXU_HEAP_DOUBLE_WEIGHT(*ppChild1) && + FXU_HEAP_DOUBLE_WEIGHT(*ppDiv) >= FXU_HEAP_DOUBLE_WEIGHT(*ppChild2) ) + { // Div is larger than both, skip + break; + } + else + { // Div is smaller than one of them, then swap it with larger + if ( FXU_HEAP_DOUBLE_WEIGHT(*ppChild1) >= FXU_HEAP_DOUBLE_WEIGHT(*ppChild2) ) + { + Fxu_HeapDoubleSwap( ppDiv, ppChild1 ); + // update the pointer + ppDiv = ppChild1; + } + else + { + Fxu_HeapDoubleSwap( ppDiv, ppChild2 ); + // update the pointer + ppDiv = ppChild2; + } + } + } + else // Child2 does not exist + { + // consider two cases + if ( FXU_HEAP_DOUBLE_WEIGHT(*ppDiv) >= FXU_HEAP_DOUBLE_WEIGHT(*ppChild1) ) + { // Div is larger than Child1, skip + break; + } + else + { // Div is smaller than Child1, then swap them + Fxu_HeapDoubleSwap( ppDiv, ppChild1 ); + // update the pointer + ppDiv = ppChild1; + } + } + } +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/fxu/fxuHeapS.c b/src/opt/fxu/fxuHeapS.c new file mode 100644 index 00000000..eaca8363 --- /dev/null +++ b/src/opt/fxu/fxuHeapS.c @@ -0,0 +1,444 @@ +/**CFile**************************************************************** + + FileName [fxuHeapS.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [The priority queue for variables.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: fxuHeapS.c,v 1.0 2003/02/01 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "fxuInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +#define FXU_HEAP_SINGLE_WEIGHT(pSingle) ((pSingle)->Weight) +#define FXU_HEAP_SINGLE_CURRENT(p, pSingle) ((p)->pTree[(pSingle)->HNum]) +#define FXU_HEAP_SINGLE_PARENT_EXISTS(p, pSingle) ((pSingle)->HNum > 1) +#define FXU_HEAP_SINGLE_CHILD1_EXISTS(p, pSingle) (((pSingle)->HNum << 1) <= p->nItems) +#define FXU_HEAP_SINGLE_CHILD2_EXISTS(p, pSingle) ((((pSingle)->HNum << 1)+1) <= p->nItems) +#define FXU_HEAP_SINGLE_PARENT(p, pSingle) ((p)->pTree[(pSingle)->HNum >> 1]) +#define FXU_HEAP_SINGLE_CHILD1(p, pSingle) ((p)->pTree[(pSingle)->HNum << 1]) +#define FXU_HEAP_SINGLE_CHILD2(p, pSingle) ((p)->pTree[((pSingle)->HNum << 1)+1]) +#define FXU_HEAP_SINGLE_ASSERT(p, pSingle) assert( (pSingle)->HNum >= 1 && (pSingle)->HNum <= p->nItemsAlloc ) + +static void Fxu_HeapSingleResize( Fxu_HeapSingle * p ); +static void Fxu_HeapSingleSwap( Fxu_Single ** pSingle1, Fxu_Single ** pSingle2 ); +static void Fxu_HeapSingleMoveUp( Fxu_HeapSingle * p, Fxu_Single * pSingle ); +static void Fxu_HeapSingleMoveDn( Fxu_HeapSingle * p, Fxu_Single * pSingle ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Fxu_HeapSingle * Fxu_HeapSingleStart() +{ + Fxu_HeapSingle * p; + p = ALLOC( Fxu_HeapSingle, 1 ); + memset( p, 0, sizeof(Fxu_HeapSingle) ); + p->nItems = 0; + p->nItemsAlloc = 2000; + p->pTree = ALLOC( Fxu_Single *, p->nItemsAlloc + 10 ); + p->pTree[0] = NULL; + return p; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_HeapSingleResize( Fxu_HeapSingle * p ) +{ + p->nItemsAlloc *= 2; + p->pTree = REALLOC( Fxu_Single *, p->pTree, p->nItemsAlloc + 10 ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_HeapSingleStop( Fxu_HeapSingle * p ) +{ + int i; + i = 0; + free( p->pTree ); + i = 1; + free( p ); +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_HeapSinglePrint( FILE * pFile, Fxu_HeapSingle * p ) +{ + Fxu_Single * pSingle; + int Counter = 1; + int Degree = 1; + + Fxu_HeapSingleCheck( p ); + fprintf( pFile, "The contents of the heap:\n" ); + fprintf( pFile, "Level %d: ", Degree ); + Fxu_HeapSingleForEachItem( p, pSingle ) + { + assert( Counter == p->pTree[Counter]->HNum ); + fprintf( pFile, "%2d=%3d ", Counter, FXU_HEAP_SINGLE_WEIGHT(p->pTree[Counter]) ); + if ( ++Counter == (1 << Degree) ) + { + fprintf( pFile, "\n" ); + Degree++; + fprintf( pFile, "Level %d: ", Degree ); + } + } + fprintf( pFile, "\n" ); + fprintf( pFile, "End of the heap printout.\n" ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_HeapSingleCheck( Fxu_HeapSingle * p ) +{ + Fxu_Single * pSingle; + Fxu_HeapSingleForEachItem( p, pSingle ) + { + assert( pSingle->HNum == p->i ); + Fxu_HeapSingleCheckOne( p, pSingle ); + } +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_HeapSingleCheckOne( Fxu_HeapSingle * p, Fxu_Single * pSingle ) +{ + int Weight1, Weight2; + if ( FXU_HEAP_SINGLE_CHILD1_EXISTS(p,pSingle) ) + { + Weight1 = FXU_HEAP_SINGLE_WEIGHT(pSingle); + Weight2 = FXU_HEAP_SINGLE_WEIGHT( FXU_HEAP_SINGLE_CHILD1(p,pSingle) ); + assert( Weight1 >= Weight2 ); + } + if ( FXU_HEAP_SINGLE_CHILD2_EXISTS(p,pSingle) ) + { + Weight1 = FXU_HEAP_SINGLE_WEIGHT(pSingle); + Weight2 = FXU_HEAP_SINGLE_WEIGHT( FXU_HEAP_SINGLE_CHILD2(p,pSingle) ); + assert( Weight1 >= Weight2 ); + } +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_HeapSingleInsert( Fxu_HeapSingle * p, Fxu_Single * pSingle ) +{ + if ( p->nItems == p->nItemsAlloc ) + Fxu_HeapSingleResize( p ); + // put the last entry to the last place and move up + p->pTree[++p->nItems] = pSingle; + pSingle->HNum = p->nItems; + // move the last entry up if necessary + Fxu_HeapSingleMoveUp( p, pSingle ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_HeapSingleUpdate( Fxu_HeapSingle * p, Fxu_Single * pSingle ) +{ + FXU_HEAP_SINGLE_ASSERT(p,pSingle); + if ( FXU_HEAP_SINGLE_PARENT_EXISTS(p,pSingle) && + FXU_HEAP_SINGLE_WEIGHT(pSingle) > FXU_HEAP_SINGLE_WEIGHT( FXU_HEAP_SINGLE_PARENT(p,pSingle) ) ) + Fxu_HeapSingleMoveUp( p, pSingle ); + else if ( FXU_HEAP_SINGLE_CHILD1_EXISTS(p,pSingle) && + FXU_HEAP_SINGLE_WEIGHT(pSingle) < FXU_HEAP_SINGLE_WEIGHT( FXU_HEAP_SINGLE_CHILD1(p,pSingle) ) ) + Fxu_HeapSingleMoveDn( p, pSingle ); + else if ( FXU_HEAP_SINGLE_CHILD2_EXISTS(p,pSingle) && + FXU_HEAP_SINGLE_WEIGHT(pSingle) < FXU_HEAP_SINGLE_WEIGHT( FXU_HEAP_SINGLE_CHILD2(p,pSingle) ) ) + Fxu_HeapSingleMoveDn( p, pSingle ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_HeapSingleDelete( Fxu_HeapSingle * p, Fxu_Single * pSingle ) +{ + int Place = pSingle->HNum; + FXU_HEAP_SINGLE_ASSERT(p,pSingle); + // put the last entry to the deleted place + // decrement the number of entries + p->pTree[Place] = p->pTree[p->nItems--]; + p->pTree[Place]->HNum = Place; + // move the top entry down if necessary + Fxu_HeapSingleUpdate( p, p->pTree[Place] ); + pSingle->HNum = 0; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Fxu_Single * Fxu_HeapSingleReadMax( Fxu_HeapSingle * p ) +{ + if ( p->nItems == 0 ) + return NULL; + return p->pTree[1]; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Fxu_Single * Fxu_HeapSingleGetMax( Fxu_HeapSingle * p ) +{ + Fxu_Single * pSingle; + if ( p->nItems == 0 ) + return NULL; + // prepare the return value + pSingle = p->pTree[1]; + pSingle->HNum = 0; + // put the last entry on top + // decrement the number of entries + p->pTree[1] = p->pTree[p->nItems--]; + p->pTree[1]->HNum = 1; + // move the top entry down if necessary + Fxu_HeapSingleMoveDn( p, p->pTree[1] ); + return pSingle; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Fxu_HeapSingleReadMaxWeight( Fxu_HeapSingle * p ) +{ + if ( p->nItems == 0 ) + return -1; + return FXU_HEAP_SINGLE_WEIGHT(p->pTree[1]); +} + + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_HeapSingleSwap( Fxu_Single ** pSingle1, Fxu_Single ** pSingle2 ) +{ + Fxu_Single * pSingle; + int Temp; + pSingle = *pSingle1; + *pSingle1 = *pSingle2; + *pSingle2 = pSingle; + Temp = (*pSingle1)->HNum; + (*pSingle1)->HNum = (*pSingle2)->HNum; + (*pSingle2)->HNum = Temp; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_HeapSingleMoveUp( Fxu_HeapSingle * p, Fxu_Single * pSingle ) +{ + Fxu_Single ** ppSingle, ** ppPar; + ppSingle = &FXU_HEAP_SINGLE_CURRENT(p, pSingle); + while ( FXU_HEAP_SINGLE_PARENT_EXISTS(p,*ppSingle) ) + { + ppPar = &FXU_HEAP_SINGLE_PARENT(p,*ppSingle); + if ( FXU_HEAP_SINGLE_WEIGHT(*ppSingle) > FXU_HEAP_SINGLE_WEIGHT(*ppPar) ) + { + Fxu_HeapSingleSwap( ppSingle, ppPar ); + ppSingle = ppPar; + } + else + break; + } +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_HeapSingleMoveDn( Fxu_HeapSingle * p, Fxu_Single * pSingle ) +{ + Fxu_Single ** ppChild1, ** ppChild2, ** ppSingle; + ppSingle = &FXU_HEAP_SINGLE_CURRENT(p, pSingle); + while ( FXU_HEAP_SINGLE_CHILD1_EXISTS(p,*ppSingle) ) + { // if Child1 does not exist, Child2 also does not exists + + // get the children + ppChild1 = &FXU_HEAP_SINGLE_CHILD1(p,*ppSingle); + if ( FXU_HEAP_SINGLE_CHILD2_EXISTS(p,*ppSingle) ) + { + ppChild2 = &FXU_HEAP_SINGLE_CHILD2(p,*ppSingle); + + // consider two cases + if ( FXU_HEAP_SINGLE_WEIGHT(*ppSingle) >= FXU_HEAP_SINGLE_WEIGHT(*ppChild1) && + FXU_HEAP_SINGLE_WEIGHT(*ppSingle) >= FXU_HEAP_SINGLE_WEIGHT(*ppChild2) ) + { // Var is larger than both, skip + break; + } + else + { // Var is smaller than one of them, then swap it with larger + if ( FXU_HEAP_SINGLE_WEIGHT(*ppChild1) >= FXU_HEAP_SINGLE_WEIGHT(*ppChild2) ) + { + Fxu_HeapSingleSwap( ppSingle, ppChild1 ); + // update the pointer + ppSingle = ppChild1; + } + else + { + Fxu_HeapSingleSwap( ppSingle, ppChild2 ); + // update the pointer + ppSingle = ppChild2; + } + } + } + else // Child2 does not exist + { + // consider two cases + if ( FXU_HEAP_SINGLE_WEIGHT(*ppSingle) >= FXU_HEAP_SINGLE_WEIGHT(*ppChild1) ) + { // Var is larger than Child1, skip + break; + } + else + { // Var is smaller than Child1, then swap them + Fxu_HeapSingleSwap( ppSingle, ppChild1 ); + // update the pointer + ppSingle = ppChild1; + } + } + } +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// diff --git a/src/opt/fxu/fxuInt.h b/src/opt/fxu/fxuInt.h new file mode 100644 index 00000000..ea85cb79 --- /dev/null +++ b/src/opt/fxu/fxuInt.h @@ -0,0 +1,539 @@ +/**CFile**************************************************************** + + FileName [fxuInt.h] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Internal declarations of fast extract for unate covers.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: fxuInt.h,v 1.3 2003/04/10 05:42:44 donald Exp $] + +***********************************************************************/ + +#ifndef __FXU_INT_H__ +#define __FXU_INT_H__ + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +#include "extra.h" +#include "vec.h" + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +// uncomment this macro to switch to standard memory management +//#define USE_SYSTEM_MEMORY_MANAGEMENT + +//////////////////////////////////////////////////////////////////////// +/// STRUCTURE DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/* + Here is an informal description of the FX data structure. + (1) The sparse matrix is filled with literals, associated with + cubes (row) and variables (columns). The matrix contains + all the cubes of all the nodes in the network. + (2) A cube is associated with + (a) its literals in the matrix, + (b) the output variable of the node, to which this cube belongs, + (3) A variable is associated with + (a) its literals in the matrix and + (b) the list of cube pairs in the cover, for which it is the output + (4) A cube pair is associated with two cubes and contains the counters + of literals in the base and in the cubes without the base + (5) A double-cube divisor is associated with list of all cube pairs + that produce it and its current weight (which is updated automatically + each time a new pair is added or an old pair is removed). + (6) A single-cube divisor is associated the pair of variables. +*/ + +// sparse matrix +typedef struct FxuMatrix Fxu_Matrix; // the sparse matrix + +// sparse matrix contents: cubes (rows), vars (columns), literals (entries) +typedef struct FxuCube Fxu_Cube; // one cube in the sparse matrix +typedef struct FxuVar Fxu_Var; // one literal in the sparse matrix +typedef struct FxuLit Fxu_Lit; // one entry in the sparse matrix + +// double cube divisors +typedef struct FxuPair Fxu_Pair; // the pair of cubes +typedef struct FxuDouble Fxu_Double; // the double-cube divisor +typedef struct FxuSingle Fxu_Single; // the two-literal single-cube divisor + +// various lists +typedef struct FxuListCube Fxu_ListCube; // the list of cubes +typedef struct FxuListVar Fxu_ListVar; // the list of literals +typedef struct FxuListLit Fxu_ListLit; // the list of entries +typedef struct FxuListPair Fxu_ListPair; // the list of pairs +typedef struct FxuListDouble Fxu_ListDouble; // the list of divisors +typedef struct FxuListSingle Fxu_ListSingle; // the list of single-cube divisors + +// various heaps +typedef struct FxuHeapDouble Fxu_HeapDouble; // the heap of divisors +typedef struct FxuHeapSingle Fxu_HeapSingle; // the heap of variables + + +// various lists + +// the list of cubes in the sparse matrix +struct FxuListCube +{ + Fxu_Cube * pHead; + Fxu_Cube * pTail; + int nItems; +}; + +// the list of literals in the sparse matrix +struct FxuListVar +{ + Fxu_Var * pHead; + Fxu_Var * pTail; + int nItems; +}; + +// the list of entries in the sparse matrix +struct FxuListLit +{ + Fxu_Lit * pHead; + Fxu_Lit * pTail; + int nItems; +}; + +// the list of cube pair in the sparse matrix +struct FxuListPair +{ + Fxu_Pair * pHead; + Fxu_Pair * pTail; + int nItems; +}; + +// the list of divisors in the sparse matrix +struct FxuListDouble +{ + Fxu_Double * pHead; + Fxu_Double * pTail; + int nItems; +}; + +// the list of divisors in the sparse matrix +struct FxuListSingle +{ + Fxu_Single * pHead; + Fxu_Single * pTail; + int nItems; +}; + + +// various heaps + +// the heap of double cube divisors by weight +struct FxuHeapDouble +{ + Fxu_Double ** pTree; + int nItems; + int nItemsAlloc; + int i; +}; + +// the heap of variable by their occurrence in the cubes +struct FxuHeapSingle +{ + Fxu_Single ** pTree; + int nItems; + int nItemsAlloc; + int i; +}; + + + +// sparse matrix +struct FxuMatrix // ~ 30 words +{ + // the cubes + Fxu_ListCube lCubes; // the double linked list of cubes + // the values (binary literals) + Fxu_ListVar lVars; // the double linked list of variables + Fxu_Var ** ppVars; // the array of variables + // the double cube divisors + Fxu_ListDouble * pTable; // the hash table of divisors + int nTableSize; // the hash table size + int nDivs; // the number of divisors in the table + int nDivsTotal; // the number of divisors in the table + Fxu_HeapDouble * pHeapDouble; // the heap of divisors by weight + // the single cube divisors + Fxu_ListSingle lSingles; // the linked list of single cube divisors + Fxu_HeapSingle * pHeapSingle; // the heap of variables by the number of literals in the matrix + int nWeightLimit;// the limit on weight of single cube divisors collected + int nSingleTotal;// the total number of single cube divisors + // storage for cube pairs + Fxu_Pair *** pppPairs; + Fxu_Pair ** ppPairs; + // temporary storage for cubes + Fxu_Cube * pOrderCubes; + Fxu_Cube ** ppTailCubes; + // temporary storage for variables + Fxu_Var * pOrderVars; + Fxu_Var ** ppTailVars; + // temporary storage for pairs + Vec_Ptr_t * vPairs; + // statistics + int nEntries; // the total number of entries in the sparse matrix + int nDivs1; // the single cube divisors taken + int nDivs2; // the double cube divisors taken + int nDivs3; // the double cube divisors with complement + // memory manager + Extra_MmFixed_t * pMemMan; // the memory manager for all small sized entries +}; + +// the cube in the sparse matrix +struct FxuCube // 9 words +{ + int iCube; // the number of this cube in the cover + Fxu_Cube * pFirst; // the pointer to the first cube of this cover + Fxu_Var * pVar; // the variable representing the output of the cover + Fxu_ListLit lLits; // the row in the table + Fxu_Cube * pPrev; // the previous cube + Fxu_Cube * pNext; // the next cube + Fxu_Cube * pOrder; // the specialized linked list of cubes +}; + +// the variable in the sparse matrix +struct FxuVar // 10 words +{ + int iVar; // the number of this variable + int nCubes; // the number of cubes assoc with this var + Fxu_Cube * pFirst; // the first cube assoc with this var + Fxu_Pair *** ppPairs; // the pairs of cubes assoc with this var + Fxu_ListLit lLits; // the column in the table + Fxu_Var * pPrev; // the previous variable + Fxu_Var * pNext; // the next variable + Fxu_Var * pOrder; // the specialized linked list of variables +}; + +// the literal entry in the sparse matrix +struct FxuLit // 8 words +{ + int iVar; // the number of this variable + int iCube; // the number of this cube + Fxu_Cube * pCube; // the cube of this literal + Fxu_Var * pVar; // the variable of this literal + Fxu_Lit * pHPrev; // prev lit in the cube + Fxu_Lit * pHNext; // next lit in the cube + Fxu_Lit * pVPrev; // prev lit of the var + Fxu_Lit * pVNext; // next lit of the var +}; + +// the cube pair +struct FxuPair // 10 words +{ + int nLits1; // the number of literals in the two cubes + int nLits2; // the number of literals in the two cubes + int nBase; // the number of literals in the base + Fxu_Double * pDiv; // the divisor of this pair + Fxu_Cube * pCube1; // the first cube of the pair + Fxu_Cube * pCube2; // the second cube of the pair + int iCube1; // the first cube of the pair + int iCube2; // the second cube of the pair + Fxu_Pair * pDPrev; // the previous pair in the divisor + Fxu_Pair * pDNext; // the next pair in the divisor +}; + +// the double cube divisor +struct FxuDouble // 10 words +{ + int Num; // the unique number of this divisor + int HNum; // the heap number of this divisor + int Weight; // the weight of this divisor + unsigned Key; // the hash key of this divisor + Fxu_ListPair lPairs; // the pairs of cubes, which produce this divisor + Fxu_Double * pPrev; // the previous divisor in the table + Fxu_Double * pNext; // the next divisor in the table + Fxu_Double * pOrder; // the specialized linked list of divisors +}; + +// the single cube divisor +struct FxuSingle // 7 words +{ + int Num; // the unique number of this divisor + int HNum; // the heap number of this divisor + int Weight; // the weight of this divisor + Fxu_Var * pVar1; // the first variable of the single-cube divisor + Fxu_Var * pVar2; // the second variable of the single-cube divisor + Fxu_Single * pPrev; // the previous divisor in the list + Fxu_Single * pNext; // the next divisor in the list +}; + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +// minimum/maximum +#define Fxu_Min( a, b ) ( ((a)<(b))? (a):(b) ) +#define Fxu_Max( a, b ) ( ((a)>(b))? (a):(b) ) + +// selection of the minimum/maximum cube in the pair +#define Fxu_PairMinCube( pPair ) (((pPair)->iCube1 < (pPair)->iCube2)? (pPair)->pCube1: (pPair)->pCube2) +#define Fxu_PairMaxCube( pPair ) (((pPair)->iCube1 > (pPair)->iCube2)? (pPair)->pCube1: (pPair)->pCube2) +#define Fxu_PairMinCubeInt( pPair ) (((pPair)->iCube1 < (pPair)->iCube2)? (pPair)->iCube1: (pPair)->iCube2) +#define Fxu_PairMaxCubeInt( pPair ) (((pPair)->iCube1 > (pPair)->iCube2)? (pPair)->iCube1: (pPair)->iCube2) + +// iterators + +#define Fxu_MatrixForEachCube( Matrix, Cube )\ + for ( Cube = (Matrix)->lCubes.pHead;\ + Cube;\ + Cube = Cube->pNext ) +#define Fxu_MatrixForEachCubeSafe( Matrix, Cube, Cube2 )\ + for ( Cube = (Matrix)->lCubes.pHead, Cube2 = (Cube? Cube->pNext: NULL);\ + Cube;\ + Cube = Cube2, Cube2 = (Cube? Cube->pNext: NULL) ) + +#define Fxu_MatrixForEachVariable( Matrix, Var )\ + for ( Var = (Matrix)->lVars.pHead;\ + Var;\ + Var = Var->pNext ) +#define Fxu_MatrixForEachVariableSafe( Matrix, Var, Var2 )\ + for ( Var = (Matrix)->lVars.pHead, Var2 = (Var? Var->pNext: NULL);\ + Var;\ + Var = Var2, Var2 = (Var? Var->pNext: NULL) ) + +#define Fxu_MatrixForEachSingle( Matrix, Single )\ + for ( Single = (Matrix)->lSingles.pHead;\ + Single;\ + Single = Single->pNext ) +#define Fxu_MatrixForEachSingleSafe( Matrix, Single, Single2 )\ + for ( Single = (Matrix)->lSingles.pHead, Single2 = (Single? Single->pNext: NULL);\ + Single;\ + Single = Single2, Single2 = (Single? Single->pNext: NULL) ) + +#define Fxu_TableForEachDouble( Matrix, Key, Div )\ + for ( Div = (Matrix)->pTable[Key].pHead;\ + Div;\ + Div = Div->pNext ) +#define Fxu_TableForEachDoubleSafe( Matrix, Key, Div, Div2 )\ + for ( Div = (Matrix)->pTable[Key].pHead, Div2 = (Div? Div->pNext: NULL);\ + Div;\ + Div = Div2, Div2 = (Div? Div->pNext: NULL) ) + +#define Fxu_MatrixForEachDouble( Matrix, Div, Index )\ + for ( Index = 0; Index < (Matrix)->nTableSize; Index++ )\ + Fxu_TableForEachDouble( Matrix, Index, Div ) +#define Fxu_MatrixForEachDoubleSafe( Matrix, Div, Div2, Index )\ + for ( Index = 0; Index < (Matrix)->nTableSize; Index++ )\ + Fxu_TableForEachDoubleSafe( Matrix, Index, Div, Div2 ) + + +#define Fxu_CubeForEachLiteral( Cube, Lit )\ + for ( Lit = (Cube)->lLits.pHead;\ + Lit;\ + Lit = Lit->pHNext ) +#define Fxu_CubeForEachLiteralSafe( Cube, Lit, Lit2 )\ + for ( Lit = (Cube)->lLits.pHead, Lit2 = (Lit? Lit->pHNext: NULL);\ + Lit;\ + Lit = Lit2, Lit2 = (Lit? Lit->pHNext: NULL) ) + +#define Fxu_VarForEachLiteral( Var, Lit )\ + for ( Lit = (Var)->lLits.pHead;\ + Lit;\ + Lit = Lit->pVNext ) + +#define Fxu_CubeForEachDivisor( Cube, Div )\ + for ( Div = (Cube)->lDivs.pHead;\ + Div;\ + Div = Div->pCNext ) + +#define Fxu_DoubleForEachPair( Div, Pair )\ + for ( Pair = (Div)->lPairs.pHead;\ + Pair;\ + Pair = Pair->pDNext ) +#define Fxu_DoubleForEachPairSafe( Div, Pair, Pair2 )\ + for ( Pair = (Div)->lPairs.pHead, Pair2 = (Pair? Pair->pDNext: NULL);\ + Pair;\ + Pair = Pair2, Pair2 = (Pair? Pair->pDNext: NULL) ) + + +// iterator through the cube pairs belonging to the given cube +#define Fxu_CubeForEachPair( pCube, pPair, i )\ + for ( i = 0;\ + i < pCube->pVar->nCubes &&\ + (((unsigned)(pPair = pCube->pVar->ppPairs[pCube->iCube][i])) >= 0);\ + i++ )\ + if ( pPair ) + +// iterator through all the items in the heap +#define Fxu_HeapDoubleForEachItem( Heap, Div )\ + for ( Heap->i = 1;\ + Heap->i <= Heap->nItems && (Div = Heap->pTree[Heap->i]);\ + Heap->i++ ) +#define Fxu_HeapSingleForEachItem( Heap, Single )\ + for ( Heap->i = 1;\ + Heap->i <= Heap->nItems && (Single = Heap->pTree[Heap->i]);\ + Heap->i++ ) + +// starting the rings +#define Fxu_MatrixRingCubesStart( Matrix ) (((Matrix)->ppTailCubes = &((Matrix)->pOrderCubes)), ((Matrix)->pOrderCubes = NULL)) +#define Fxu_MatrixRingVarsStart( Matrix ) (((Matrix)->ppTailVars = &((Matrix)->pOrderVars)), ((Matrix)->pOrderVars = NULL)) +// stopping the rings +#define Fxu_MatrixRingCubesStop( Matrix ) +#define Fxu_MatrixRingVarsStop( Matrix ) +// resetting the rings +#define Fxu_MatrixRingCubesReset( Matrix ) (((Matrix)->pOrderCubes = NULL), ((Matrix)->ppTailCubes = NULL)) +#define Fxu_MatrixRingVarsReset( Matrix ) (((Matrix)->pOrderVars = NULL), ((Matrix)->ppTailVars = NULL)) +// adding to the rings +#define Fxu_MatrixRingCubesAdd( Matrix, Cube) ((*((Matrix)->ppTailCubes) = Cube), ((Matrix)->ppTailCubes = &(Cube)->pOrder), ((Cube)->pOrder = (Fxu_Cube *)1)) +#define Fxu_MatrixRingVarsAdd( Matrix, Var ) ((*((Matrix)->ppTailVars ) = Var ), ((Matrix)->ppTailVars = &(Var)->pOrder ), ((Var)->pOrder = (Fxu_Var *)1)) +// iterating through the rings +#define Fxu_MatrixForEachCubeInRing( Matrix, Cube )\ + if ( (Matrix)->pOrderCubes )\ + for ( Cube = (Matrix)->pOrderCubes;\ + Cube != (Fxu_Cube *)1;\ + Cube = Cube->pOrder ) +#define Fxu_MatrixForEachCubeInRingSafe( Matrix, Cube, Cube2 )\ + if ( (Matrix)->pOrderCubes )\ + for ( Cube = (Matrix)->pOrderCubes, Cube2 = ((Cube != (Fxu_Cube *)1)? Cube->pOrder: (Fxu_Cube *)1);\ + Cube != (Fxu_Cube *)1;\ + Cube = Cube2, Cube2 = ((Cube != (Fxu_Cube *)1)? Cube->pOrder: (Fxu_Cube *)1) ) +#define Fxu_MatrixForEachVarInRing( Matrix, Var )\ + if ( (Matrix)->pOrderVars )\ + for ( Var = (Matrix)->pOrderVars;\ + Var != (Fxu_Var *)1;\ + Var = Var->pOrder ) +#define Fxu_MatrixForEachVarInRingSafe( Matrix, Var, Var2 )\ + if ( (Matrix)->pOrderVars )\ + for ( Var = (Matrix)->pOrderVars, Var2 = ((Var != (Fxu_Var *)1)? Var->pOrder: (Fxu_Var *)1);\ + Var != (Fxu_Var *)1;\ + Var = Var2, Var2 = ((Var != (Fxu_Var *)1)? Var->pOrder: (Fxu_Var *)1) ) +// the procedures are related to the above macros +extern void Fxu_MatrixRingCubesUnmark( Fxu_Matrix * p ); +extern void Fxu_MatrixRingVarsUnmark( Fxu_Matrix * p ); + + +// macros working with memory +// MEM_ALLOC: allocate the given number (Size) of items of type (Type) +// MEM_FREE: deallocate the pointer (Pointer) to the given number (Size) of items of type (Type) +#ifdef USE_SYSTEM_MEMORY_MANAGEMENT +#define MEM_ALLOC_FXU( Manager, Type, Size ) ((Type *)malloc( (Size) * sizeof(Type) )) +#define MEM_FREE_FXU( Manager, Type, Size, Pointer ) if ( Pointer ) { free(Pointer); Pointer = NULL; } +#else +#define MEM_ALLOC_FXU( Manager, Type, Size )\ + ((Type *)Fxu_MemFetch( Manager, (Size) * sizeof(Type) )) +#define MEM_FREE_FXU( Manager, Type, Size, Pointer )\ + if ( Pointer ) { Fxu_MemRecycle( Manager, (char *)(Pointer), (Size) * sizeof(Type) ); Pointer = NULL; } +#endif + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/*===== fxu.c ====================================================*/ +extern char * Fxu_MemFetch( Fxu_Matrix * p, int nBytes ); +extern void Fxu_MemRecycle( Fxu_Matrix * p, char * pItem, int nBytes ); +/*===== fxuCreate.c ====================================================*/ +/*===== fxuReduce.c ====================================================*/ +/*===== fxuPrint.c ====================================================*/ +extern void Fxu_MatrixPrint( FILE * pFile, Fxu_Matrix * p ); +extern void Fxu_MatrixPrintDivisorProfile( FILE * pFile, Fxu_Matrix * p ); +/*===== fxuSelect.c ====================================================*/ +extern int Fxu_Select( Fxu_Matrix * p, Fxu_Single ** ppSingle, Fxu_Double ** ppDouble ); +extern int Fxu_SelectSCD( Fxu_Matrix * p, int Weight, Fxu_Var ** ppVar1, Fxu_Var ** ppVar2 ); +/*===== fxuUpdate.c ====================================================*/ +extern void Fxu_Update( Fxu_Matrix * p, Fxu_Single * pSingle, Fxu_Double * pDouble ); +extern void Fxu_UpdateDouble( Fxu_Matrix * p ); +extern void Fxu_UpdateSingle( Fxu_Matrix * p ); +/*===== fxuPair.c ====================================================*/ +extern void Fxu_PairCanonicize( Fxu_Cube ** ppCube1, Fxu_Cube ** ppCube2 ); +extern unsigned Fxu_PairHashKeyArray( Fxu_Matrix * p, int piVarsC1[], int piVarsC2[], int nVarsC1, int nVarsC2 ); +extern unsigned Fxu_PairHashKey( Fxu_Matrix * p, Fxu_Cube * pCube1, Fxu_Cube * pCube2, int * pnBase, int * pnLits1, int * pnLits2 ); +extern unsigned Fxu_PairHashKeyMv( Fxu_Matrix * p, Fxu_Cube * pCube1, Fxu_Cube * pCube2, int * pnBase, int * pnLits1, int * pnLits2 ); +extern int Fxu_PairCompare( Fxu_Pair * pPair1, Fxu_Pair * pPair2 ); +extern void Fxu_PairAllocStorage( Fxu_Var * pVar, int nCubes ); +extern void Fxu_PairFreeStorage( Fxu_Var * pVar ); +extern void Fxu_PairClearStorage( Fxu_Cube * pCube ); +extern Fxu_Pair * Fxu_PairAlloc( Fxu_Matrix * p, Fxu_Cube * pCube1, Fxu_Cube * pCube2 ); +extern void Fxu_PairAdd( Fxu_Pair * pPair ); +/*===== fxuSingle.c ====================================================*/ +extern void Fxu_MatrixComputeSingles( Fxu_Matrix * p, int fUse0, int nSingleMax ); +extern void Fxu_MatrixComputeSinglesOne( Fxu_Matrix * p, Fxu_Var * pVar ); +extern int Fxu_SingleCountCoincidence( Fxu_Matrix * p, Fxu_Var * pVar1, Fxu_Var * pVar2 ); +/*===== fxuMatrix.c ====================================================*/ +// matrix +extern Fxu_Matrix * Fxu_MatrixAllocate(); +extern void Fxu_MatrixDelete( Fxu_Matrix * p ); +// double-cube divisor +extern void Fxu_MatrixAddDivisor( Fxu_Matrix * p, Fxu_Cube * pCube1, Fxu_Cube * pCube2 ); +extern void Fxu_MatrixDelDivisor( Fxu_Matrix * p, Fxu_Double * pDiv ); +// single-cube divisor +extern void Fxu_MatrixAddSingle( Fxu_Matrix * p, Fxu_Var * pVar1, Fxu_Var * pVar2, int Weight ); +// variable +extern Fxu_Var * Fxu_MatrixAddVar( Fxu_Matrix * p ); +// cube +extern Fxu_Cube * Fxu_MatrixAddCube( Fxu_Matrix * p, Fxu_Var * pVar, int iCube ); +// literal +extern void Fxu_MatrixAddLiteral( Fxu_Matrix * p, Fxu_Cube * pCube, Fxu_Var * pVar ); +extern void Fxu_MatrixDelLiteral( Fxu_Matrix * p, Fxu_Lit * pLit ); +/*===== fxuList.c ====================================================*/ +// matrix -> variable +extern void Fxu_ListMatrixAddVariable( Fxu_Matrix * p, Fxu_Var * pVar ); +extern void Fxu_ListMatrixDelVariable( Fxu_Matrix * p, Fxu_Var * pVar ); +// matrix -> cube +extern void Fxu_ListMatrixAddCube( Fxu_Matrix * p, Fxu_Cube * pCube ); +extern void Fxu_ListMatrixDelCube( Fxu_Matrix * p, Fxu_Cube * pCube ); +// matrix -> single +extern void Fxu_ListMatrixAddSingle( Fxu_Matrix * p, Fxu_Single * pSingle ); +extern void Fxu_ListMatrixDelSingle( Fxu_Matrix * p, Fxu_Single * pSingle ); +// table -> divisor +extern void Fxu_ListTableAddDivisor( Fxu_Matrix * p, Fxu_Double * pDiv ); +extern void Fxu_ListTableDelDivisor( Fxu_Matrix * p, Fxu_Double * pDiv ); +// cube -> literal +extern void Fxu_ListCubeAddLiteral( Fxu_Cube * pCube, Fxu_Lit * pLit ); +extern void Fxu_ListCubeDelLiteral( Fxu_Cube * pCube, Fxu_Lit * pLit ); +// var -> literal +extern void Fxu_ListVarAddLiteral( Fxu_Var * pVar, Fxu_Lit * pLit ); +extern void Fxu_ListVarDelLiteral( Fxu_Var * pVar, Fxu_Lit * pLit ); +// divisor -> pair +extern void Fxu_ListDoubleAddPairLast( Fxu_Double * pDiv, Fxu_Pair * pLink ); +extern void Fxu_ListDoubleAddPairFirst( Fxu_Double * pDiv, Fxu_Pair * pLink ); +extern void Fxu_ListDoubleAddPairMiddle( Fxu_Double * pDiv, Fxu_Pair * pSpot, Fxu_Pair * pLink ); +extern void Fxu_ListDoubleDelPair( Fxu_Double * pDiv, Fxu_Pair * pPair ); +/*===== fxuHeapDouble.c ====================================================*/ +extern Fxu_HeapDouble * Fxu_HeapDoubleStart(); +extern void Fxu_HeapDoubleStop( Fxu_HeapDouble * p ); +extern void Fxu_HeapDoublePrint( FILE * pFile, Fxu_HeapDouble * p ); +extern void Fxu_HeapDoubleCheck( Fxu_HeapDouble * p ); +extern void Fxu_HeapDoubleCheckOne( Fxu_HeapDouble * p, Fxu_Double * pDiv ); + +extern void Fxu_HeapDoubleInsert( Fxu_HeapDouble * p, Fxu_Double * pDiv ); +extern void Fxu_HeapDoubleUpdate( Fxu_HeapDouble * p, Fxu_Double * pDiv ); +extern void Fxu_HeapDoubleDelete( Fxu_HeapDouble * p, Fxu_Double * pDiv ); +extern int Fxu_HeapDoubleReadMaxWeight( Fxu_HeapDouble * p ); +extern Fxu_Double * Fxu_HeapDoubleReadMax( Fxu_HeapDouble * p ); +extern Fxu_Double * Fxu_HeapDoubleGetMax( Fxu_HeapDouble * p ); +/*===== fxuHeapSingle.c ====================================================*/ +extern Fxu_HeapSingle * Fxu_HeapSingleStart(); +extern void Fxu_HeapSingleStop( Fxu_HeapSingle * p ); +extern void Fxu_HeapSinglePrint( FILE * pFile, Fxu_HeapSingle * p ); +extern void Fxu_HeapSingleCheck( Fxu_HeapSingle * p ); +extern void Fxu_HeapSingleCheckOne( Fxu_HeapSingle * p, Fxu_Single * pSingle ); + +extern void Fxu_HeapSingleInsert( Fxu_HeapSingle * p, Fxu_Single * pSingle ); +extern void Fxu_HeapSingleUpdate( Fxu_HeapSingle * p, Fxu_Single * pSingle ); +extern void Fxu_HeapSingleDelete( Fxu_HeapSingle * p, Fxu_Single * pSingle ); +extern int Fxu_HeapSingleReadMaxWeight( Fxu_HeapSingle * p ); +extern Fxu_Single * Fxu_HeapSingleReadMax( Fxu_HeapSingle * p ); +extern Fxu_Single * Fxu_HeapSingleGetMax( Fxu_HeapSingle * p ); + +#endif + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + diff --git a/src/opt/fxu/fxuList.c b/src/opt/fxu/fxuList.c new file mode 100644 index 00000000..52995804 --- /dev/null +++ b/src/opt/fxu/fxuList.c @@ -0,0 +1,522 @@ +/**CFile**************************************************************** + + FileName [fxuList.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Operations on lists.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: fxuList.c,v 1.0 2003/02/01 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "fxuInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +// matrix -> var + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_ListMatrixAddVariable( Fxu_Matrix * p, Fxu_Var * pLink ) +{ + Fxu_ListVar * pList = &p->lVars; + if ( pList->pHead == NULL ) + { + pList->pHead = pLink; + pList->pTail = pLink; + pLink->pPrev = NULL; + pLink->pNext = NULL; + } + else + { + pLink->pNext = NULL; + pList->pTail->pNext = pLink; + pLink->pPrev = pList->pTail; + pList->pTail = pLink; + } + pList->nItems++; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_ListMatrixDelVariable( Fxu_Matrix * p, Fxu_Var * pLink ) +{ + Fxu_ListVar * pList = &p->lVars; + if ( pList->pHead == pLink ) + pList->pHead = pLink->pNext; + if ( pList->pTail == pLink ) + pList->pTail = pLink->pPrev; + if ( pLink->pPrev ) + pLink->pPrev->pNext = pLink->pNext; + if ( pLink->pNext ) + pLink->pNext->pPrev = pLink->pPrev; + pList->nItems--; +} + + +// matrix -> cube + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_ListMatrixAddCube( Fxu_Matrix * p, Fxu_Cube * pLink ) +{ + Fxu_ListCube * pList = &p->lCubes; + if ( pList->pHead == NULL ) + { + pList->pHead = pLink; + pList->pTail = pLink; + pLink->pPrev = NULL; + pLink->pNext = NULL; + } + else + { + pLink->pNext = NULL; + pList->pTail->pNext = pLink; + pLink->pPrev = pList->pTail; + pList->pTail = pLink; + } + pList->nItems++; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_ListMatrixDelCube( Fxu_Matrix * p, Fxu_Cube * pLink ) +{ + Fxu_ListCube * pList = &p->lCubes; + if ( pList->pHead == pLink ) + pList->pHead = pLink->pNext; + if ( pList->pTail == pLink ) + pList->pTail = pLink->pPrev; + if ( pLink->pPrev ) + pLink->pPrev->pNext = pLink->pNext; + if ( pLink->pNext ) + pLink->pNext->pPrev = pLink->pPrev; + pList->nItems--; +} + + +// matrix -> single + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_ListMatrixAddSingle( Fxu_Matrix * p, Fxu_Single * pLink ) +{ + Fxu_ListSingle * pList = &p->lSingles; + if ( pList->pHead == NULL ) + { + pList->pHead = pLink; + pList->pTail = pLink; + pLink->pPrev = NULL; + pLink->pNext = NULL; + } + else + { + pLink->pNext = NULL; + pList->pTail->pNext = pLink; + pLink->pPrev = pList->pTail; + pList->pTail = pLink; + } + pList->nItems++; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_ListMatrixDelSingle( Fxu_Matrix * p, Fxu_Single * pLink ) +{ + Fxu_ListSingle * pList = &p->lSingles; + if ( pList->pHead == pLink ) + pList->pHead = pLink->pNext; + if ( pList->pTail == pLink ) + pList->pTail = pLink->pPrev; + if ( pLink->pPrev ) + pLink->pPrev->pNext = pLink->pNext; + if ( pLink->pNext ) + pLink->pNext->pPrev = pLink->pPrev; + pList->nItems--; +} + + +// table -> divisor + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_ListTableAddDivisor( Fxu_Matrix * p, Fxu_Double * pLink ) +{ + Fxu_ListDouble * pList = &(p->pTable[pLink->Key]); + if ( pList->pHead == NULL ) + { + pList->pHead = pLink; + pList->pTail = pLink; + pLink->pPrev = NULL; + pLink->pNext = NULL; + } + else + { + pLink->pNext = NULL; + pList->pTail->pNext = pLink; + pLink->pPrev = pList->pTail; + pList->pTail = pLink; + } + pList->nItems++; + p->nDivs++; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_ListTableDelDivisor( Fxu_Matrix * p, Fxu_Double * pLink ) +{ + Fxu_ListDouble * pList = &(p->pTable[pLink->Key]); + if ( pList->pHead == pLink ) + pList->pHead = pLink->pNext; + if ( pList->pTail == pLink ) + pList->pTail = pLink->pPrev; + if ( pLink->pPrev ) + pLink->pPrev->pNext = pLink->pNext; + if ( pLink->pNext ) + pLink->pNext->pPrev = pLink->pPrev; + pList->nItems--; + p->nDivs--; +} + + +// cube -> literal + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_ListCubeAddLiteral( Fxu_Cube * pCube, Fxu_Lit * pLink ) +{ + Fxu_ListLit * pList = &(pCube->lLits); + if ( pList->pHead == NULL ) + { + pList->pHead = pLink; + pList->pTail = pLink; + pLink->pHPrev = NULL; + pLink->pHNext = NULL; + } + else + { + pLink->pHNext = NULL; + pList->pTail->pHNext = pLink; + pLink->pHPrev = pList->pTail; + pList->pTail = pLink; + } + pList->nItems++; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_ListCubeDelLiteral( Fxu_Cube * pCube, Fxu_Lit * pLink ) +{ + Fxu_ListLit * pList = &(pCube->lLits); + if ( pList->pHead == pLink ) + pList->pHead = pLink->pHNext; + if ( pList->pTail == pLink ) + pList->pTail = pLink->pHPrev; + if ( pLink->pHPrev ) + pLink->pHPrev->pHNext = pLink->pHNext; + if ( pLink->pHNext ) + pLink->pHNext->pHPrev = pLink->pHPrev; + pList->nItems--; +} + + +// var -> literal + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_ListVarAddLiteral( Fxu_Var * pVar, Fxu_Lit * pLink ) +{ + Fxu_ListLit * pList = &(pVar->lLits); + if ( pList->pHead == NULL ) + { + pList->pHead = pLink; + pList->pTail = pLink; + pLink->pVPrev = NULL; + pLink->pVNext = NULL; + } + else + { + pLink->pVNext = NULL; + pList->pTail->pVNext = pLink; + pLink->pVPrev = pList->pTail; + pList->pTail = pLink; + } + pList->nItems++; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_ListVarDelLiteral( Fxu_Var * pVar, Fxu_Lit * pLink ) +{ + Fxu_ListLit * pList = &(pVar->lLits); + if ( pList->pHead == pLink ) + pList->pHead = pLink->pVNext; + if ( pList->pTail == pLink ) + pList->pTail = pLink->pVPrev; + if ( pLink->pVPrev ) + pLink->pVPrev->pVNext = pLink->pVNext; + if ( pLink->pVNext ) + pLink->pVNext->pVPrev = pLink->pVPrev; + pList->nItems--; +} + + + +// divisor -> pair + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_ListDoubleAddPairLast( Fxu_Double * pDiv, Fxu_Pair * pLink ) +{ + Fxu_ListPair * pList = &pDiv->lPairs; + if ( pList->pHead == NULL ) + { + pList->pHead = pLink; + pList->pTail = pLink; + pLink->pDPrev = NULL; + pLink->pDNext = NULL; + } + else + { + pLink->pDNext = NULL; + pList->pTail->pDNext = pLink; + pLink->pDPrev = pList->pTail; + pList->pTail = pLink; + } + pList->nItems++; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_ListDoubleAddPairFirst( Fxu_Double * pDiv, Fxu_Pair * pLink ) +{ + Fxu_ListPair * pList = &pDiv->lPairs; + if ( pList->pHead == NULL ) + { + pList->pHead = pLink; + pList->pTail = pLink; + pLink->pDPrev = NULL; + pLink->pDNext = NULL; + } + else + { + pLink->pDPrev = NULL; + pList->pHead->pDPrev = pLink; + pLink->pDNext = pList->pHead; + pList->pHead = pLink; + } + pList->nItems++; +} + +/**Function************************************************************* + + Synopsis [Adds the entry in the middle of the list after the spot.] + + Description [Assumes that spot points to the link, after which the given + link should be added. Spot cannot be NULL or the tail of the list. + Therefore, the head and the tail of the list are not changed.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_ListDoubleAddPairMiddle( Fxu_Double * pDiv, Fxu_Pair * pSpot, Fxu_Pair * pLink ) +{ + Fxu_ListPair * pList = &pDiv->lPairs; + assert( pSpot ); + assert( pSpot != pList->pTail ); + pLink->pDPrev = pSpot; + pLink->pDNext = pSpot->pDNext; + pLink->pDPrev->pDNext = pLink; + pLink->pDNext->pDPrev = pLink; + pList->nItems++; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_ListDoubleDelPair( Fxu_Double * pDiv, Fxu_Pair * pLink ) +{ + Fxu_ListPair * pList = &pDiv->lPairs; + if ( pList->pHead == pLink ) + pList->pHead = pLink->pDNext; + if ( pList->pTail == pLink ) + pList->pTail = pLink->pDPrev; + if ( pLink->pDPrev ) + pLink->pDPrev->pDNext = pLink->pDNext; + if ( pLink->pDNext ) + pLink->pDNext->pDPrev = pLink->pDPrev; + pList->nItems--; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_ListDoubleAddPairPlace( Fxu_Double * pDiv, Fxu_Pair * pPair, Fxu_Pair * pPairSpot ) +{ + printf( "Fxu_ListDoubleAddPairPlace() is called!\n" ); +} + + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/fxu/fxuMatrix.c b/src/opt/fxu/fxuMatrix.c new file mode 100644 index 00000000..93ec7b90 --- /dev/null +++ b/src/opt/fxu/fxuMatrix.c @@ -0,0 +1,374 @@ +/**CFile**************************************************************** + + FileName [fxuMatrix.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Procedures to manipulate the sparse matrix.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: fxuMatrix.c,v 1.0 2003/02/01 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "fxuInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +extern unsigned int Cudd_Prime( unsigned int p ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Fxu_Matrix * Fxu_MatrixAllocate() +{ + Fxu_Matrix * p; + p = ALLOC( Fxu_Matrix, 1 ); + memset( p, 0, sizeof(Fxu_Matrix) ); + p->nTableSize = Cudd_Prime(10000); + p->pTable = ALLOC( Fxu_ListDouble, p->nTableSize ); + memset( p->pTable, 0, sizeof(Fxu_ListDouble) * p->nTableSize ); +#ifndef USE_SYSTEM_MEMORY_MANAGEMENT + { + // get the largest size in bytes for the following structures: + // Fxu_Cube, Fxu_Var, Fxu_Lit, Fxu_Pair, Fxu_Double, Fxu_Single + // (currently, Fxu_Var, Fxu_Pair, Fxu_Double take 10 machine words) + int nSizeMax, nSizeCur; + nSizeMax = -1; + nSizeCur = sizeof(Fxu_Cube); + if ( nSizeMax < nSizeCur ) + nSizeMax = nSizeCur; + nSizeCur = sizeof(Fxu_Var); + if ( nSizeMax < nSizeCur ) + nSizeMax = nSizeCur; + nSizeCur = sizeof(Fxu_Lit); + if ( nSizeMax < nSizeCur ) + nSizeMax = nSizeCur; + nSizeCur = sizeof(Fxu_Pair); + if ( nSizeMax < nSizeCur ) + nSizeMax = nSizeCur; + nSizeCur = sizeof(Fxu_Double); + if ( nSizeMax < nSizeCur ) + nSizeMax = nSizeCur; + nSizeCur = sizeof(Fxu_Single); + if ( nSizeMax < nSizeCur ) + nSizeMax = nSizeCur; + p->pMemMan = Extra_MmFixedStart( nSizeMax ); + } +#endif + p->pHeapDouble = Fxu_HeapDoubleStart(); + p->pHeapSingle = Fxu_HeapSingleStart(); + p->vPairs = Vec_PtrAlloc( 100 ); + return p; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_MatrixDelete( Fxu_Matrix * p ) +{ + Fxu_HeapDoubleCheck( p->pHeapDouble ); + Fxu_HeapDoubleStop( p->pHeapDouble ); + Fxu_HeapSingleStop( p->pHeapSingle ); + + // delete other things +#ifdef USE_SYSTEM_MEMORY_MANAGEMENT + // this code is not needed when the custom memory manager is used + { + Fxu_Cube * pCube, * pCube2; + Fxu_Var * pVar, * pVar2; + Fxu_Lit * pLit, * pLit2; + Fxu_Double * pDiv, * pDiv2; + Fxu_Single * pSingle, * pSingle2; + Fxu_Pair * pPair, * pPair2; + int i; + // delete the divisors + Fxu_MatrixForEachDoubleSafe( p, pDiv, pDiv2, i ) + { + Fxu_DoubleForEachPairSafe( pDiv, pPair, pPair2 ) + MEM_FREE_FXU( p, Fxu_Pair, 1, pPair ); + MEM_FREE_FXU( p, Fxu_Double, 1, pDiv ); + } + Fxu_MatrixForEachSingleSafe( p, pSingle, pSingle2 ) + MEM_FREE_FXU( p, Fxu_Single, 1, pSingle ); + // delete the entries + Fxu_MatrixForEachCube( p, pCube ) + Fxu_CubeForEachLiteralSafe( pCube, pLit, pLit2 ) + MEM_FREE_FXU( p, Fxu_Lit, 1, pLit ); + // delete the cubes + Fxu_MatrixForEachCubeSafe( p, pCube, pCube2 ) + MEM_FREE_FXU( p, Fxu_Cube, 1, pCube ); + // delete the vars + Fxu_MatrixForEachVariableSafe( p, pVar, pVar2 ) + MEM_FREE_FXU( p, Fxu_Var, 1, pVar ); + } +#else + Extra_MmFixedStop( p->pMemMan ); +#endif + + Vec_PtrFree( p->vPairs ); + FREE( p->pppPairs ); + FREE( p->ppPairs ); +// FREE( p->pPairsTemp ); + FREE( p->pTable ); + FREE( p->ppVars ); + FREE( p ); +} + + + +/**Function************************************************************* + + Synopsis [Adds a variable to the matrix.] + + Description [This procedure always adds variables at the end of the matrix. + It assigns the var's node and number. It adds the var to the linked list of + all variables and to the table of all nodes.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Fxu_Var * Fxu_MatrixAddVar( Fxu_Matrix * p ) +{ + Fxu_Var * pVar; + pVar = MEM_ALLOC_FXU( p, Fxu_Var, 1 ); + memset( pVar, 0, sizeof(Fxu_Var) ); + pVar->iVar = p->lVars.nItems; + p->ppVars[pVar->iVar] = pVar; + Fxu_ListMatrixAddVariable( p, pVar ); + return pVar; +} + +/**Function************************************************************* + + Synopsis [Adds a literal to the matrix.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Fxu_Cube * Fxu_MatrixAddCube( Fxu_Matrix * p, Fxu_Var * pVar, int iCube ) +{ + Fxu_Cube * pCube; + pCube = MEM_ALLOC_FXU( p, Fxu_Cube, 1 ); + memset( pCube, 0, sizeof(Fxu_Cube) ); + pCube->pVar = pVar; + pCube->iCube = iCube; + Fxu_ListMatrixAddCube( p, pCube ); + return pCube; +} + +/**Function************************************************************* + + Synopsis [Adds a literal to the matrix.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_MatrixAddLiteral( Fxu_Matrix * p, Fxu_Cube * pCube, Fxu_Var * pVar ) +{ + Fxu_Lit * pLit; + pLit = MEM_ALLOC_FXU( p, Fxu_Lit, 1 ); + memset( pLit, 0, sizeof(Fxu_Lit) ); + // insert the literal into two linked lists + Fxu_ListCubeAddLiteral( pCube, pLit ); + Fxu_ListVarAddLiteral( pVar, pLit ); + // set the back pointers + pLit->pCube = pCube; + pLit->pVar = pVar; + pLit->iCube = pCube->iCube; + pLit->iVar = pVar->iVar; + // increment the literal counter + p->nEntries++; +} + +/**Function************************************************************* + + Synopsis [Deletes the divisor from the matrix.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_MatrixDelDivisor( Fxu_Matrix * p, Fxu_Double * pDiv ) +{ + // delete divisor from the table + Fxu_ListTableDelDivisor( p, pDiv ); + // recycle the divisor + MEM_FREE_FXU( p, Fxu_Double, 1, pDiv ); +} + +/**Function************************************************************* + + Synopsis [Deletes the literal fromthe matrix.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_MatrixDelLiteral( Fxu_Matrix * p, Fxu_Lit * pLit ) +{ + // delete the literal + Fxu_ListCubeDelLiteral( pLit->pCube, pLit ); + Fxu_ListVarDelLiteral( pLit->pVar, pLit ); + MEM_FREE_FXU( p, Fxu_Lit, 1, pLit ); + // increment the literal counter + p->nEntries--; +} + + +/**Function************************************************************* + + Synopsis [Creates and adds a single cube divisor.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_MatrixAddSingle( Fxu_Matrix * p, Fxu_Var * pVar1, Fxu_Var * pVar2, int Weight ) +{ + Fxu_Single * pSingle; + assert( pVar1->iVar < pVar2->iVar ); + pSingle = MEM_ALLOC_FXU( p, Fxu_Single, 1 ); + memset( pSingle, 0, sizeof(Fxu_Single) ); + pSingle->Num = p->lSingles.nItems; + pSingle->Weight = Weight; + pSingle->HNum = 0; + pSingle->pVar1 = pVar1; + pSingle->pVar2 = pVar2; + Fxu_ListMatrixAddSingle( p, pSingle ); + // add to the heap + Fxu_HeapSingleInsert( p->pHeapSingle, pSingle ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_MatrixAddDivisor( Fxu_Matrix * p, Fxu_Cube * pCube1, Fxu_Cube * pCube2 ) +{ + Fxu_Pair * pPair; + Fxu_Double * pDiv; + int nBase, nLits1, nLits2; + int fFound; + unsigned Key; + + // canonicize the pair + Fxu_PairCanonicize( &pCube1, &pCube2 ); + // compute the hash key + Key = Fxu_PairHashKey( p, pCube1, pCube2, &nBase, &nLits1, &nLits2 ); + + // create the cube pair + pPair = Fxu_PairAlloc( p, pCube1, pCube2 ); + pPair->nBase = nBase; + pPair->nLits1 = nLits1; + pPair->nLits2 = nLits2; + + // check if the divisor for this pair already exists + fFound = 0; + Key %= p->nTableSize; + Fxu_TableForEachDouble( p, Key, pDiv ) + { + if ( Fxu_PairCompare( pPair, pDiv->lPairs.pTail ) ) // they are equal + { + fFound = 1; + break; + } + } + + if ( !fFound ) + { // create the new divisor + pDiv = MEM_ALLOC_FXU( p, Fxu_Double, 1 ); + memset( pDiv, 0, sizeof(Fxu_Double) ); + pDiv->Key = Key; + // set the number of this divisor + pDiv->Num = p->nDivsTotal++; // p->nDivs; + // insert the divisor in the table + Fxu_ListTableAddDivisor( p, pDiv ); + // set the initial cost of the divisor + pDiv->Weight -= pPair->nLits1 + pPair->nLits2; + } + + // link the pair to the cubes + Fxu_PairAdd( pPair ); + // connect the pair and the divisor + pPair->pDiv = pDiv; + Fxu_ListDoubleAddPairLast( pDiv, pPair ); + // update the max number of pairs in a divisor +// if ( p->nPairsMax < pDiv->lPairs.nItems ) +// p->nPairsMax = pDiv->lPairs.nItems; + // update the divisor's weight + pDiv->Weight += pPair->nLits1 + pPair->nLits2 - 1 + pPair->nBase; + if ( fFound ) // update the divisor in the heap + Fxu_HeapDoubleUpdate( p->pHeapDouble, pDiv ); + else // add the new divisor to the heap + Fxu_HeapDoubleInsert( p->pHeapDouble, pDiv ); +} + +/* + { + int piVarsC1[100], piVarsC2[100], nVarsC1, nVarsC2; + Fxu_Double * pDivCur; + Fxu_MatrixGetDoubleVars( p, pDiv, piVarsC1, piVarsC2, &nVarsC1, &nVarsC2 ); + pDivCur = Fxu_MatrixFindDouble( p, piVarsC1, piVarsC2, nVarsC1, nVarsC2 ); + assert( pDivCur == pDiv ); + } +*/ + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/fxu/fxuPair.c b/src/opt/fxu/fxuPair.c new file mode 100644 index 00000000..3c031ce8 --- /dev/null +++ b/src/opt/fxu/fxuPair.c @@ -0,0 +1,555 @@ +/**CFile**************************************************************** + + FileName [fxuPair.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Operations on cube pairs.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: fxuPair.c,v 1.0 2003/02/01 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "fxuInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +#define MAX_PRIMES 304 + +static s_Primes[MAX_PRIMES] = +{ + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, + 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, + 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, + 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, + 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, + 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, + 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, + 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, + 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, + 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, + 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, + 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, + 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, + 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, + 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, + 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, + 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, + 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, + 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, + 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, + 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, + 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, + 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, + 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, + 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, + 1993, 1997, 1999, 2003 +}; + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Find the canonical permutation of two cubes in the pair.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_PairCanonicize( Fxu_Cube ** ppCube1, Fxu_Cube ** ppCube2 ) +{ + Fxu_Lit * pLit1, * pLit2; + Fxu_Cube * pCubeTemp; + + // walk through the cubes to determine + // the one that has higher first variable + pLit1 = (*ppCube1)->lLits.pHead; + pLit2 = (*ppCube2)->lLits.pHead; + while ( 1 ) + { + if ( pLit1->iVar == pLit2->iVar ) + { + pLit1 = pLit1->pHNext; + pLit2 = pLit2->pHNext; + continue; + } + assert( pLit1 && pLit2 ); // this is true if the covers are SCC-free + if ( pLit1->iVar > pLit2->iVar ) + { // swap the cubes + pCubeTemp = *ppCube1; + *ppCube1 = *ppCube2; + *ppCube2 = pCubeTemp; + } + break; + } +} + +/**Function************************************************************* + + Synopsis [Find the canonical permutation of two cubes in the pair.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_PairCanonicize2( Fxu_Cube ** ppCube1, Fxu_Cube ** ppCube2 ) +{ + Fxu_Cube * pCubeTemp; + // canonicize the pair by ordering the cubes + if ( (*ppCube1)->iCube > (*ppCube2)->iCube ) + { // swap the cubes + pCubeTemp = *ppCube1; + *ppCube1 = *ppCube2; + *ppCube2 = pCubeTemp; + } +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned Fxu_PairHashKeyArray( Fxu_Matrix * p, int piVarsC1[], int piVarsC2[], int nVarsC1, int nVarsC2 ) +{ + int Offset1 = 100, Offset2 = 200, i; + unsigned Key; + // compute the hash key + Key = 0; + for ( i = 0; i < nVarsC1; i++ ) + Key ^= s_Primes[Offset1+i] * piVarsC1[i]; + for ( i = 0; i < nVarsC2; i++ ) + Key ^= s_Primes[Offset2+i] * piVarsC2[i]; + return Key; +} + +/**Function************************************************************* + + Synopsis [Computes the hash key of the divisor represented by the pair of cubes.] + + Description [Goes through the variables in both cubes. Skips the identical + ones (this corresponds to making the cubes cube-free). Computes the hash + value of the cubes. Assigns the number of literals in the base and in the + cubes without base.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned Fxu_PairHashKey( Fxu_Matrix * p, Fxu_Cube * pCube1, Fxu_Cube * pCube2, + int * pnBase, int * pnLits1, int * pnLits2 ) +{ + int Offset1 = 100, Offset2 = 200; + int nBase, nLits1, nLits2; + Fxu_Lit * pLit1, * pLit2; + unsigned Key; + + // compute the hash key + Key = 0; + nLits1 = 0; + nLits2 = 0; + nBase = 0; + pLit1 = pCube1->lLits.pHead; + pLit2 = pCube2->lLits.pHead; + while ( 1 ) + { + if ( pLit1 && pLit2 ) + { + if ( pLit1->iVar == pLit2->iVar ) + { // ensure cube-free + pLit1 = pLit1->pHNext; + pLit2 = pLit2->pHNext; + // add this literal to the base + nBase++; + } + else if ( pLit1->iVar < pLit2->iVar ) + { + Key ^= s_Primes[Offset1+nLits1] * pLit1->iVar; + pLit1 = pLit1->pHNext; + nLits1++; + } + else + { + Key ^= s_Primes[Offset2+nLits2] * pLit2->iVar; + pLit2 = pLit2->pHNext; + nLits2++; + } + } + else if ( pLit1 && !pLit2 ) + { + Key ^= s_Primes[Offset1+nLits1] * pLit1->iVar; + pLit1 = pLit1->pHNext; + nLits1++; + } + else if ( !pLit1 && pLit2 ) + { + Key ^= s_Primes[Offset2+nLits2] * pLit2->iVar; + pLit2 = pLit2->pHNext; + nLits2++; + } + else + break; + } + *pnBase = nBase; + *pnLits1 = nLits1; + *pnLits2 = nLits2; + return Key; +} + +/**Function************************************************************* + + Synopsis [Compares the two pairs.] + + Description [Returns 1 if the divisors represented by these pairs + are equal.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Fxu_PairCompare( Fxu_Pair * pPair1, Fxu_Pair * pPair2 ) +{ + Fxu_Lit * pD1C1, * pD1C2; + Fxu_Lit * pD2C1, * pD2C2; + int TopVar1, TopVar2; + int Code; + + if ( pPair1->nLits1 != pPair2->nLits1 ) + return 0; + if ( pPair1->nLits2 != pPair2->nLits2 ) + return 0; + + pD1C1 = pPair1->pCube1->lLits.pHead; + pD1C2 = pPair1->pCube2->lLits.pHead; + + pD2C1 = pPair2->pCube1->lLits.pHead; + pD2C2 = pPair2->pCube2->lLits.pHead; + + Code = pD1C1? 8: 0; + Code |= pD1C2? 4: 0; + Code |= pD2C1? 2: 0; + Code |= pD2C2? 1: 0; + assert( Code == 15 ); + + while ( 1 ) + { + switch ( Code ) + { + case 0: // -- -- NULL NULL NULL NULL + return 1; + case 1: // -- -1 NULL NULL NULL pD2C2 + return 0; + case 2: // -- 1- NULL NULL pD2C1 NULL + return 0; + case 3: // -- 11 NULL NULL pD2C1 pD2C2 + if ( pD2C1->iVar != pD2C2->iVar ) + return 0; + pD2C1 = pD2C1->pHNext; + pD2C2 = pD2C2->pHNext; + break; + case 4: // -1 -- NULL pD1C2 NULL NULL + return 0; + case 5: // -1 -1 NULL pD1C2 NULL pD2C2 + if ( pD1C2->iVar != pD2C2->iVar ) + return 0; + pD1C2 = pD1C2->pHNext; + pD2C2 = pD2C2->pHNext; + break; + case 6: // -1 1- NULL pD1C2 pD2C1 NULL + return 0; + case 7: // -1 11 NULL pD1C2 pD2C1 pD2C2 + TopVar2 = Fxu_Min( pD2C1->iVar, pD2C2->iVar ); + if ( TopVar2 == pD1C2->iVar ) + { + if ( pD2C1->iVar <= pD2C2->iVar ) + return 0; + pD1C2 = pD1C2->pHNext; + pD2C2 = pD2C2->pHNext; + } + else if ( TopVar2 < pD1C2->iVar ) + { + if ( pD2C1->iVar != pD2C2->iVar ) + return 0; + pD2C1 = pD2C1->pHNext; + pD2C2 = pD2C2->pHNext; + } + else + return 0; + break; + case 8: // 1- -- pD1C1 NULL NULL NULL + return 0; + case 9: // 1- -1 pD1C1 NULL NULL pD2C2 + return 0; + case 10: // 1- 1- pD1C1 NULL pD2C1 NULL + if ( pD1C1->iVar != pD2C1->iVar ) + return 0; + pD1C1 = pD1C1->pHNext; + pD2C1 = pD2C1->pHNext; + break; + case 11: // 1- 11 pD1C1 NULL pD2C1 pD2C2 + TopVar2 = Fxu_Min( pD2C1->iVar, pD2C2->iVar ); + if ( TopVar2 == pD1C1->iVar ) + { + if ( pD2C1->iVar >= pD2C2->iVar ) + return 0; + pD1C1 = pD1C1->pHNext; + pD2C1 = pD2C1->pHNext; + } + else if ( TopVar2 < pD1C1->iVar ) + { + if ( pD2C1->iVar != pD2C2->iVar ) + return 0; + pD2C1 = pD2C1->pHNext; + pD2C2 = pD2C2->pHNext; + } + else + return 0; + break; + case 12: // 11 -- pD1C1 pD1C2 NULL NULL + if ( pD1C1->iVar != pD1C2->iVar ) + return 0; + pD1C1 = pD1C1->pHNext; + pD1C2 = pD1C2->pHNext; + break; + case 13: // 11 -1 pD1C1 pD1C2 NULL pD2C2 + TopVar1 = Fxu_Min( pD1C1->iVar, pD1C2->iVar ); + if ( TopVar1 == pD2C2->iVar ) + { + if ( pD1C1->iVar <= pD1C2->iVar ) + return 0; + pD1C2 = pD1C2->pHNext; + pD2C2 = pD2C2->pHNext; + } + else if ( TopVar1 < pD2C2->iVar ) + { + if ( pD1C1->iVar != pD1C2->iVar ) + return 0; + pD1C1 = pD1C1->pHNext; + pD1C2 = pD1C2->pHNext; + } + else + return 0; + break; + case 14: // 11 1- pD1C1 pD1C2 pD2C1 NULL + TopVar1 = Fxu_Min( pD1C1->iVar, pD1C2->iVar ); + if ( TopVar1 == pD2C1->iVar ) + { + if ( pD1C1->iVar >= pD1C2->iVar ) + return 0; + pD1C1 = pD1C1->pHNext; + pD2C1 = pD2C1->pHNext; + } + else if ( TopVar1 < pD2C1->iVar ) + { + if ( pD1C1->iVar != pD1C2->iVar ) + return 0; + pD1C1 = pD1C1->pHNext; + pD1C2 = pD1C2->pHNext; + } + else + return 0; + break; + case 15: // 11 11 pD1C1 pD1C2 pD2C1 pD2C2 + TopVar1 = Fxu_Min( pD1C1->iVar, pD1C2->iVar ); + TopVar2 = Fxu_Min( pD2C1->iVar, pD2C2->iVar ); + if ( TopVar1 == TopVar2 ) + { + if ( pD1C1->iVar == pD1C2->iVar ) + { + if ( pD2C1->iVar != pD2C2->iVar ) + return 0; + pD1C1 = pD1C1->pHNext; + pD1C2 = pD1C2->pHNext; + pD2C1 = pD2C1->pHNext; + pD2C2 = pD2C2->pHNext; + } + else + { + if ( pD2C1->iVar == pD2C2->iVar ) + return 0; + if ( pD1C1->iVar < pD1C2->iVar ) + { + if ( pD2C1->iVar > pD2C2->iVar ) + return 0; + pD1C1 = pD1C1->pHNext; + pD2C1 = pD2C1->pHNext; + } + else + { + if ( pD2C1->iVar < pD2C2->iVar ) + return 0; + pD1C2 = pD1C2->pHNext; + pD2C2 = pD2C2->pHNext; + } + } + } + else if ( TopVar1 < TopVar2 ) + { + if ( pD1C1->iVar != pD1C2->iVar ) + return 0; + pD1C1 = pD1C1->pHNext; + pD1C2 = pD1C2->pHNext; + } + else + { + if ( pD2C1->iVar != pD2C2->iVar ) + return 0; + pD2C1 = pD2C1->pHNext; + pD2C2 = pD2C2->pHNext; + } + break; + default: + assert( 0 ); + break; + } + + Code = pD1C1? 8: 0; + Code |= pD1C2? 4: 0; + Code |= pD2C1? 2: 0; + Code |= pD2C2? 1: 0; + } + return 1; +} + + +/**Function************************************************************* + + Synopsis [Allocates the storage for cubes pairs.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_PairAllocStorage( Fxu_Var * pVar, int nCubes ) +{ + int k; +// assert( pVar->nCubes == 0 ); + pVar->nCubes = nCubes; + // allocate memory for all the pairs + pVar->ppPairs = ALLOC( Fxu_Pair **, nCubes ); + pVar->ppPairs[0] = ALLOC( Fxu_Pair *, nCubes * nCubes ); + memset( pVar->ppPairs[0], 0, sizeof(Fxu_Pair *) * nCubes * nCubes ); + for ( k = 1; k < nCubes; k++ ) + pVar->ppPairs[k] = pVar->ppPairs[k-1] + nCubes; +} + +/**Function************************************************************* + + Synopsis [Clears all pairs associated with this cube.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_PairClearStorage( Fxu_Cube * pCube ) +{ + Fxu_Var * pVar; + int i; + pVar = pCube->pVar; + for ( i = 0; i < pVar->nCubes; i++ ) + { + pVar->ppPairs[pCube->iCube][i] = NULL; + pVar->ppPairs[i][pCube->iCube] = NULL; + } +} + +/**Function************************************************************* + + Synopsis [Clears all pairs associated with this cube.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_PairFreeStorage( Fxu_Var * pVar ) +{ + if ( pVar->ppPairs ) + { + FREE( pVar->ppPairs[0] ); + FREE( pVar->ppPairs ); + } +} + +/**Function************************************************************* + + Synopsis [Adds the pair to storage.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Fxu_Pair * Fxu_PairAlloc( Fxu_Matrix * p, Fxu_Cube * pCube1, Fxu_Cube * pCube2 ) +{ + Fxu_Pair * pPair; + assert( pCube1->pVar == pCube2->pVar ); + pPair = MEM_ALLOC_FXU( p, Fxu_Pair, 1 ); + memset( pPair, 0, sizeof(Fxu_Pair) ); + pPair->pCube1 = pCube1; + pPair->pCube2 = pCube2; + pPair->iCube1 = pCube1->iCube; + pPair->iCube2 = pCube2->iCube; + return pPair; +} + +/**Function************************************************************* + + Synopsis [Adds the pair to storage.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_PairAdd( Fxu_Pair * pPair ) +{ + Fxu_Var * pVar; + + pVar = pPair->pCube1->pVar; + assert( pVar == pPair->pCube2->pVar ); + + pVar->ppPairs[pPair->iCube1][pPair->iCube2] = pPair; + pVar->ppPairs[pPair->iCube2][pPair->iCube1] = pPair; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/fxu/fxuPrint.c b/src/opt/fxu/fxuPrint.c new file mode 100644 index 00000000..232b109a --- /dev/null +++ b/src/opt/fxu/fxuPrint.c @@ -0,0 +1,195 @@ +/**CFile**************************************************************** + + FileName [fxuPrint.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Various printing procedures.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: fxuPrint.c,v 1.0 2003/02/01 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "fxuInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_MatrixPrint( FILE * pFile, Fxu_Matrix * p ) +{ + Fxu_Var * pVar; + Fxu_Cube * pCube; + Fxu_Double * pDiv; + Fxu_Single * pSingle; + Fxu_Lit * pLit; + Fxu_Pair * pPair; + int i, LastNum; + int fStdout; + + fStdout = 1; + if ( pFile == NULL ) + { + pFile = fopen( "matrix.txt", "w" ); + fStdout = 0; + } + + fprintf( pFile, "Matrix has %d vars, %d cubes, %d literals, %d divisors.\n", + p->lVars.nItems, p->lCubes.nItems, p->nEntries, p->nDivs ); + fprintf( pFile, "Divisors selected so far: single = %d, double = %d.\n", + p->nDivs1, p->nDivs2 ); + fprintf( pFile, "\n" ); + + // print the numbers on top of the matrix + for ( i = 0; i < 12; i++ ) + fprintf( pFile, " " ); + Fxu_MatrixForEachVariable( p, pVar ) + fprintf( pFile, "%d", pVar->iVar % 10 ); + fprintf( pFile, "\n" ); + + // print the rows + Fxu_MatrixForEachCube( p, pCube ) + { + fprintf( pFile, "%4d", pCube->iCube ); + fprintf( pFile, " " ); + fprintf( pFile, "%4d", pCube->pVar->iVar ); + fprintf( pFile, " " ); + + // print the literals + LastNum = -1; + Fxu_CubeForEachLiteral( pCube, pLit ) + { + for ( i = LastNum + 1; i < pLit->pVar->iVar; i++ ) + fprintf( pFile, "." ); + fprintf( pFile, "1" ); + LastNum = i; + } + for ( i = LastNum + 1; i < p->lVars.nItems; i++ ) + fprintf( pFile, "." ); + fprintf( pFile, "\n" ); + } + fprintf( pFile, "\n" ); + + // print the double-cube divisors + fprintf( pFile, "The double divisors are:\n" ); + Fxu_MatrixForEachDouble( p, pDiv, i ) + { + fprintf( pFile, "Divisor #%3d (lit=%d,%d) (w=%2d): ", + pDiv->Num, pDiv->lPairs.pHead->nLits1, + pDiv->lPairs.pHead->nLits2, pDiv->Weight ); + Fxu_DoubleForEachPair( pDiv, pPair ) + fprintf( pFile, " <%d, %d> (b=%d)", + pPair->pCube1->iCube, pPair->pCube2->iCube, pPair->nBase ); + fprintf( pFile, "\n" ); + } + fprintf( pFile, "\n" ); + + // print the divisors associated with each cube + fprintf( pFile, "The cubes are:\n" ); + Fxu_MatrixForEachCube( p, pCube ) + { + fprintf( pFile, "Cube #%3d: ", pCube->iCube ); + if ( pCube->pVar->ppPairs ) + Fxu_CubeForEachPair( pCube, pPair, i ) + fprintf( pFile, " <%d %d> (d=%d) (b=%d)", + pPair->iCube1, pPair->iCube2, pPair->pDiv->Num, pPair->nBase ); + fprintf( pFile, "\n" ); + } + fprintf( pFile, "\n" ); + + // print the single-cube divisors + fprintf( pFile, "The single divisors are:\n" ); + Fxu_MatrixForEachSingle( p, pSingle ) + { + fprintf( pFile, "Single-cube divisor #%5d: Var1 = %4d. Var2 = %4d. Weight = %2d\n", + pSingle->Num, pSingle->pVar1->iVar, pSingle->pVar2->iVar, pSingle->Weight ); + } + fprintf( pFile, "\n" ); + +/* + { + int Index; + fprintf( pFile, "Distribution of divisors in the hash table:\n" ); + for ( Index = 0; Index < p->nTableSize; Index++ ) + fprintf( pFile, " %d", p->pTable[Index].nItems ); + fprintf( pFile, "\n" ); + } +*/ + if ( !fStdout ) + fclose( pFile ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_MatrixPrintDivisorProfile( FILE * pFile, Fxu_Matrix * p ) +{ + Fxu_Double * pDiv; + int WeightMax; + int * pProfile; + int Counter1; // the number of -1 weight + int CounterL; // the number of less than -1 weight + int i; + + WeightMax = Fxu_HeapDoubleReadMaxWeight( p->pHeapDouble ); + pProfile = ALLOC( int, (WeightMax + 1) ); + memset( pProfile, 0, sizeof(int) * (WeightMax + 1) ); + + Counter1 = 0; + CounterL = 0; + Fxu_MatrixForEachDouble( p, pDiv, i ) + { + assert( pDiv->Weight <= WeightMax ); + if ( pDiv->Weight == -1 ) + Counter1++; + else if ( pDiv->Weight < 0 ) + CounterL++; + else + pProfile[ pDiv->Weight ]++; + } + + fprintf( pFile, "The double divisors profile:\n" ); + fprintf( pFile, "Weight < -1 divisors = %6d\n", CounterL ); + fprintf( pFile, "Weight -1 divisors = %6d\n", Counter1 ); + for ( i = 0; i <= WeightMax; i++ ) + if ( pProfile[i] ) + fprintf( pFile, "Weight %3d divisors = %6d\n", i, pProfile[i] ); + fprintf( pFile, "End of divisor profile printout\n" ); + FREE( pProfile ); +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/fxu/fxuReduce.c b/src/opt/fxu/fxuReduce.c new file mode 100644 index 00000000..0ab8a157 --- /dev/null +++ b/src/opt/fxu/fxuReduce.c @@ -0,0 +1,204 @@ +/**CFile**************************************************************** + + FileName [fxuReduce.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Procedures to reduce the number of considered cube pairs.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: fxuReduce.c,v 1.0 2003/02/01 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "fxuInt.h" +#include "fxu.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static int Fxu_CountPairDiffs( char * pCover, unsigned char pDiffs[] ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Precomputes the pairs to use for creating two-cube divisors.] + + Description [This procedure takes the matrix with variables and cubes + allocated (p), the original covers of the nodes (i-sets) and their number + (ppCovers,nCovers). The maximum number of pairs to compute and the total + number of pairs in existence. This procedure adds to the storage of + divisors exactly the given number of pairs (nPairsMax) while taking + first those pairs that have the smallest number of literals in their + cube-free form.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Fxu_PreprocessCubePairs( Fxu_Matrix * p, Vec_Ptr_t * vCovers, int nPairsTotal, int nPairsMax ) +{ + unsigned char * pnLitsDiff; // storage for the counters of diff literals + int * pnPairCounters; // the counters of pairs for each number of diff literals + Fxu_Cube * pCubeFirst, * pCubeLast; + Fxu_Cube * pCube1, * pCube2; + Fxu_Var * pVar; + int nCubes, nBitsMax, nSum; + int CutOffNum, CutOffQuant; + int iPair, iQuant, k, c; + int clk = clock(); + char * pSopCover; + int nFanins; + + assert( nPairsMax < nPairsTotal ); + + // allocate storage for counter of diffs + pnLitsDiff = ALLOC( unsigned char, nPairsTotal ); + // go through the covers and precompute the distances between the pairs + iPair = 0; + nBitsMax = -1; + for ( c = 0; c < vCovers->nSize; c++ ) + if ( pSopCover = vCovers->pArray[c] ) + { + nFanins = Abc_SopGetVarNum(pSopCover); + // precompute the differences + Fxu_CountPairDiffs( pSopCover, pnLitsDiff + iPair ); + // update the counter + nCubes = Abc_SopGetCubeNum( pSopCover ); + iPair += nCubes * (nCubes - 1) / 2; + if ( nBitsMax < nFanins ) + nBitsMax = nFanins; + } + assert( iPair == nPairsTotal ); + + // allocate storage for counters of cube pairs by difference + pnPairCounters = ALLOC( int, 2 * nBitsMax ); + memset( pnPairCounters, 0, sizeof(int) * 2 * nBitsMax ); + // count the number of different pairs + for ( k = 0; k < nPairsTotal; k++ ) + pnPairCounters[ pnLitsDiff[k] ]++; + // determine what pairs to take starting from the lower + // so that there would be exactly pPairsMax pairs + if ( pnPairCounters[0] != 0 ) + { + printf( "The SOPs of the nodes are not cube-free. Run \"bdd; sop\" before \"fx\".\n" ); + return 0; + } + if ( pnPairCounters[1] != 0 ) + { + printf( "The SOPs of the nodes are not SCC-free. Run \"bdd; sop\" before \"fx\".\n" ); + return 0; + } + assert( pnPairCounters[0] == 0 ); // otherwise, covers are not dup-free + assert( pnPairCounters[1] == 0 ); // otherwise, covers are not SCC-free + nSum = 0; + for ( k = 0; k < 2 * nBitsMax; k++ ) + { + nSum += pnPairCounters[k]; + if ( nSum >= nPairsMax ) + { + CutOffNum = k; + CutOffQuant = pnPairCounters[k] - (nSum - nPairsMax); + break; + } + } + FREE( pnPairCounters ); + + // set to 0 all the pairs above the cut-off number and quantity + iQuant = 0; + iPair = 0; + for ( k = 0; k < nPairsTotal; k++ ) + if ( pnLitsDiff[k] > CutOffNum ) + pnLitsDiff[k] = 0; + else if ( pnLitsDiff[k] == CutOffNum ) + { + if ( iQuant++ >= CutOffQuant ) + pnLitsDiff[k] = 0; + else + iPair++; + } + else + iPair++; + assert( iPair == nPairsMax ); + + // collect the corresponding pairs and add the divisors + iPair = 0; + for ( c = 0; c < vCovers->nSize; c++ ) + if ( pSopCover = vCovers->pArray[c] ) + { + // get the var + pVar = p->ppVars[2*c+1]; + // get the first cube + pCubeFirst = pVar->pFirst; + // get the last cube + pCubeLast = pCubeFirst; + for ( k = 0; k < pVar->nCubes; k++ ) + pCubeLast = pCubeLast->pNext; + assert( pCubeLast == NULL || pCubeLast->pVar != pVar ); + + // go through the cube pairs + for ( pCube1 = pCubeFirst; pCube1 != pCubeLast; pCube1 = pCube1->pNext ) + for ( pCube2 = pCube1->pNext; pCube2 != pCubeLast; pCube2 = pCube2->pNext ) + if ( pnLitsDiff[iPair++] ) + { // create the divisors for this pair + Fxu_MatrixAddDivisor( p, pCube1, pCube2 ); + } + } + assert( iPair == nPairsTotal ); + FREE( pnLitsDiff ); +//PRT( "Preprocess", clock() - clk ); + return 1; +} + + +/**Function************************************************************* + + Synopsis [Counts the differences in each cube pair in the cover.] + + Description [Takes the cover (pCover) and the array where the + diff counters go (pDiffs). The array pDiffs should have as many + entries as there are different pairs of cubes in the cover: n(n-1)/2. + Fills out the array pDiffs with the following info: For each cube + pair, included in the array is the number of literals in both cubes + after they are made cube free.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Fxu_CountPairDiffs( char * pCover, unsigned char pDiffs[] ) +{ + char * pCube1, * pCube2; + int nOnes, nCubePairs, nFanins, v; + nCubePairs = 0; + nFanins = Abc_SopGetVarNum(pCover); + Abc_SopForEachCube( pCover, nFanins, pCube1 ) + Abc_SopForEachCube( pCube1, nFanins, pCube2 ) + { + if ( pCube1 == pCube2 ) + continue; + nOnes = 0; + for ( v = 0; v < nFanins; v++ ) + nOnes += (pCube1[v] != pCube2[v]); + pDiffs[nCubePairs++] = nOnes; + } + return 1; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/fxu/fxuSelect.c b/src/opt/fxu/fxuSelect.c new file mode 100644 index 00000000..b9265487 --- /dev/null +++ b/src/opt/fxu/fxuSelect.c @@ -0,0 +1,603 @@ +/**CFile**************************************************************** + + FileName [fxuSelect.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Procedures to select the best divisor/complement pair.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: fxuSelect.c,v 1.0 2003/02/01 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "fxuInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +#define MAX_SIZE_LOOKAHEAD 20 + +static int Fxu_MatrixFindComplement( Fxu_Matrix * p, int iVar ); + +static Fxu_Double * Fxu_MatrixFindComplementSingle( Fxu_Matrix * p, Fxu_Single * pSingle ); +static Fxu_Single * Fxu_MatrixFindComplementDouble2( Fxu_Matrix * p, Fxu_Double * pDouble ); +static Fxu_Double * Fxu_MatrixFindComplementDouble4( Fxu_Matrix * p, Fxu_Double * pDouble ); + +Fxu_Double * Fxu_MatrixFindDouble( Fxu_Matrix * p, + int piVarsC1[], int piVarsC2[], int nVarsC1, int nVarsC2 ); +void Fxu_MatrixGetDoubleVars( Fxu_Matrix * p, Fxu_Double * pDouble, + int piVarsC1[], int piVarsC2[], int * pnVarsC1, int * pnVarsC2 ); + + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Selects the best pair (Single,Double) and returns their weight.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Fxu_Select( Fxu_Matrix * p, Fxu_Single ** ppSingle, Fxu_Double ** ppDouble ) +{ + // the top entries + Fxu_Single * pSingles[MAX_SIZE_LOOKAHEAD]; + Fxu_Double * pDoubles[MAX_SIZE_LOOKAHEAD]; + // the complements + Fxu_Double * pSCompl[MAX_SIZE_LOOKAHEAD]; + Fxu_Single * pDComplS[MAX_SIZE_LOOKAHEAD]; + Fxu_Double * pDComplD[MAX_SIZE_LOOKAHEAD]; + Fxu_Pair * pPair; + int nSingles; + int nDoubles; + int i; + int WeightBest; + int WeightCur; + int iNum, fBestS; + + // collect the top entries from the queues + for ( nSingles = 0; nSingles < MAX_SIZE_LOOKAHEAD; nSingles++ ) + { + pSingles[nSingles] = Fxu_HeapSingleGetMax( p->pHeapSingle ); + if ( pSingles[nSingles] == NULL ) + break; + } + // put them back into the queue + for ( i = 0; i < nSingles; i++ ) + if ( pSingles[i] ) + Fxu_HeapSingleInsert( p->pHeapSingle, pSingles[i] ); + + // the same for doubles + // collect the top entries from the queues + for ( nDoubles = 0; nDoubles < MAX_SIZE_LOOKAHEAD; nDoubles++ ) + { + pDoubles[nDoubles] = Fxu_HeapDoubleGetMax( p->pHeapDouble ); + if ( pDoubles[nDoubles] == NULL ) + break; + } + // put them back into the queue + for ( i = 0; i < nDoubles; i++ ) + if ( pDoubles[i] ) + Fxu_HeapDoubleInsert( p->pHeapDouble, pDoubles[i] ); + + // for each single, find the complement double (if any) + for ( i = 0; i < nSingles; i++ ) + if ( pSingles[i] ) + pSCompl[i] = Fxu_MatrixFindComplementSingle( p, pSingles[i] ); + + // for each double, find the complement single or double (if any) + for ( i = 0; i < nDoubles; i++ ) + if ( pDoubles[i] ) + { + pPair = pDoubles[i]->lPairs.pHead; + if ( pPair->nLits1 == 1 && pPair->nLits2 == 1 ) + { + pDComplS[i] = Fxu_MatrixFindComplementDouble2( p, pDoubles[i] ); + pDComplD[i] = NULL; + } +// else if ( pPair->nLits1 == 2 && pPair->nLits2 == 2 ) +// { +// pDComplS[i] = NULL; +// pDComplD[i] = Fxu_MatrixFindComplementDouble4( p, pDoubles[i] ); +// } + else + { + pDComplS[i] = NULL; + pDComplD[i] = NULL; + } + } + + // select the best pair + WeightBest = -1; + for ( i = 0; i < nSingles; i++ ) + { + WeightCur = pSingles[i]->Weight; + if ( pSCompl[i] ) + { + // add the weight of the double + WeightCur += pSCompl[i]->Weight; + // there is no need to implement this double, so... + pPair = pSCompl[i]->lPairs.pHead; + WeightCur += pPair->nLits1 + pPair->nLits2; + } + if ( WeightBest < WeightCur ) + { + WeightBest = WeightCur; + *ppSingle = pSingles[i]; + *ppDouble = pSCompl[i]; + fBestS = 1; + iNum = i; + } + } + for ( i = 0; i < nDoubles; i++ ) + { + WeightCur = pDoubles[i]->Weight; + if ( pDComplS[i] ) + { + // add the weight of the single + WeightCur += pDComplS[i]->Weight; + // there is no need to implement this double, so... + pPair = pDoubles[i]->lPairs.pHead; + WeightCur += pPair->nLits1 + pPair->nLits2; + } + if ( WeightBest < WeightCur ) + { + WeightBest = WeightCur; + *ppSingle = pDComplS[i]; + *ppDouble = pDoubles[i]; + fBestS = 0; + iNum = i; + } + } +/* + // print the statistics + printf( "\n" ); + for ( i = 0; i < nSingles; i++ ) + { + printf( "Single #%d: Weight = %3d. ", i, pSingles[i]->Weight ); + printf( "Compl: " ); + if ( pSCompl[i] == NULL ) + printf( "None." ); + else + printf( "D Weight = %3d Sum = %3d", + pSCompl[i]->Weight, pSCompl[i]->Weight + pSingles[i]->Weight ); + printf( "\n" ); + } + printf( "\n" ); + for ( i = 0; i < nDoubles; i++ ) + { + printf( "Double #%d: Weight = %3d. ", i, pDoubles[i]->Weight ); + printf( "Compl: " ); + if ( pDComplS[i] == NULL && pDComplD[i] == NULL ) + printf( "None." ); + else if ( pDComplS[i] ) + printf( "S Weight = %3d Sum = %3d", + pDComplS[i]->Weight, pDComplS[i]->Weight + pDoubles[i]->Weight ); + else if ( pDComplD[i] ) + printf( "D Weight = %3d Sum = %3d", + pDComplD[i]->Weight, pDComplD[i]->Weight + pDoubles[i]->Weight ); + printf( "\n" ); + } + if ( WeightBest == -1 ) + printf( "Selected NONE\n" ); + else + { + printf( "Selected = %s. ", fBestS? "S": "D" ); + printf( "Number = %d. ", iNum ); + printf( "Weight = %d.\n", WeightBest ); + } + printf( "\n" ); +*/ + return WeightBest; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Fxu_Double * Fxu_MatrixFindComplementSingle( Fxu_Matrix * p, Fxu_Single * pSingle ) +{ +// int * pValue2Node = p->pValue2Node; + int iVar1, iVar2; + int iVar1C, iVar2C; + // get the variables of this single div + iVar1 = pSingle->pVar1->iVar; + iVar2 = pSingle->pVar2->iVar; + iVar1C = Fxu_MatrixFindComplement( p, iVar1 ); + iVar2C = Fxu_MatrixFindComplement( p, iVar2 ); + if ( iVar1C == -1 || iVar2C == -1 ) + return NULL; + assert( iVar1C < iVar2C ); + return Fxu_MatrixFindDouble( p, &iVar1C, &iVar2C, 1, 1 ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Fxu_Single * Fxu_MatrixFindComplementDouble2( Fxu_Matrix * p, Fxu_Double * pDouble ) +{ +// int * pValue2Node = p->pValue2Node; + int piVarsC1[10], piVarsC2[10]; + int nVarsC1, nVarsC2; + int iVar1, iVar2, iVarTemp; + int iVar1C, iVar2C; + Fxu_Single * pSingle; + + // get the variables of this double div + Fxu_MatrixGetDoubleVars( p, pDouble, piVarsC1, piVarsC2, &nVarsC1, &nVarsC2 ); + assert( nVarsC1 == 1 ); + assert( nVarsC2 == 1 ); + iVar1 = piVarsC1[0]; + iVar2 = piVarsC2[0]; + assert( iVar1 < iVar2 ); + + iVar1C = Fxu_MatrixFindComplement( p, iVar1 ); + iVar2C = Fxu_MatrixFindComplement( p, iVar2 ); + if ( iVar1C == -1 || iVar2C == -1 ) + return NULL; + + // go through the queque and find this one +// assert( iVar1C < iVar2C ); + if ( iVar1C > iVar2C ) + { + iVarTemp = iVar1C; + iVar1C = iVar2C; + iVar2C = iVarTemp; + } + + Fxu_MatrixForEachSingle( p, pSingle ) + if ( pSingle->pVar1->iVar == iVar1C && pSingle->pVar2->iVar == iVar2C ) + return pSingle; + return NULL; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Fxu_Double * Fxu_MatrixFindComplementDouble4( Fxu_Matrix * p, Fxu_Double * pDouble ) +{ +// int * pValue2Node = p->pValue2Node; + int piVarsC1[10], piVarsC2[10]; + int nVarsC1, nVarsC2; + int iVar11, iVar12, iVar21, iVar22; + int iVar11C, iVar12C, iVar21C, iVar22C; + int RetValue; + + // get the variables of this double div + Fxu_MatrixGetDoubleVars( p, pDouble, piVarsC1, piVarsC2, &nVarsC1, &nVarsC2 ); + assert( nVarsC1 == 2 && nVarsC2 == 2 ); + + iVar11 = piVarsC1[0]; + iVar12 = piVarsC1[1]; + iVar21 = piVarsC2[0]; + iVar22 = piVarsC2[1]; + assert( iVar11 < iVar21 ); + + iVar11C = Fxu_MatrixFindComplement( p, iVar11 ); + iVar12C = Fxu_MatrixFindComplement( p, iVar12 ); + iVar21C = Fxu_MatrixFindComplement( p, iVar21 ); + iVar22C = Fxu_MatrixFindComplement( p, iVar22 ); + if ( iVar11C == -1 || iVar12C == -1 || iVar21C == -1 || iVar22C == -1 ) + return NULL; + if ( iVar11C != iVar21 || iVar12C != iVar22 || + iVar21C != iVar11 || iVar22C != iVar12 ) + return NULL; + + // a'b' + ab => a'b + ab' + // a'b + ab' => a'b' + ab + // swap the second pair in each cube + RetValue = piVarsC1[1]; + piVarsC1[1] = piVarsC2[1]; + piVarsC2[1] = RetValue; + + return Fxu_MatrixFindDouble( p, piVarsC1, piVarsC2, 2, 2 ); +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Fxu_MatrixFindComplement( Fxu_Matrix * p, int iVar ) +{ + return iVar ^ 1; +/* +// int * pValue2Node = p->pValue2Node; + int iVarC; + int iNode; + int Beg, End; + + // get the nodes + iNode = pValue2Node[iVar]; + // get the first node with the same var + for ( Beg = iVar; Beg >= 0; Beg-- ) + if ( pValue2Node[Beg] != iNode ) + { + Beg++; + break; + } + // get the last node with the same var + for ( End = iVar; ; End++ ) + if ( pValue2Node[End] != iNode ) + { + End--; + break; + } + + // if one of the vars is not binary, quit + if ( End - Beg > 1 ) + return -1; + + // get the complements + if ( iVar == Beg ) + iVarC = End; + else if ( iVar == End ) + iVarC = Beg; + else + { + assert( 0 ); + } + return iVarC; +*/ +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_MatrixGetDoubleVars( Fxu_Matrix * p, Fxu_Double * pDouble, + int piVarsC1[], int piVarsC2[], int * pnVarsC1, int * pnVarsC2 ) +{ + Fxu_Pair * pPair; + Fxu_Lit * pLit1, * pLit2; + int nLits1, nLits2; + + // get the first pair + pPair = pDouble->lPairs.pHead; + // init the parameters + nLits1 = 0; + nLits2 = 0; + pLit1 = pPair->pCube1->lLits.pHead; + pLit2 = pPair->pCube2->lLits.pHead; + while ( 1 ) + { + if ( pLit1 && pLit2 ) + { + if ( pLit1->iVar == pLit2->iVar ) + { // ensure cube-free + pLit1 = pLit1->pHNext; + pLit2 = pLit2->pHNext; + } + else if ( pLit1->iVar < pLit2->iVar ) + { + piVarsC1[nLits1++] = pLit1->iVar; + pLit1 = pLit1->pHNext; + } + else + { + piVarsC2[nLits2++] = pLit2->iVar; + pLit2 = pLit2->pHNext; + } + } + else if ( pLit1 && !pLit2 ) + { + piVarsC1[nLits1++] = pLit1->iVar; + pLit1 = pLit1->pHNext; + } + else if ( !pLit1 && pLit2 ) + { + piVarsC2[nLits2++] = pLit2->iVar; + pLit2 = pLit2->pHNext; + } + else + break; + } + *pnVarsC1 = nLits1; + *pnVarsC2 = nLits2; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Fxu_Double * Fxu_MatrixFindDouble( Fxu_Matrix * p, + int piVarsC1[], int piVarsC2[], int nVarsC1, int nVarsC2 ) +{ + int piVarsC1_[100], piVarsC2_[100]; + int nVarsC1_, nVarsC2_, i; + Fxu_Double * pDouble; + Fxu_Pair * pPair; + unsigned Key; + + assert( nVarsC1 > 0 ); + assert( nVarsC2 > 0 ); + assert( piVarsC1[0] < piVarsC2[0] ); + + // get the hash key + Key = Fxu_PairHashKeyArray( p, piVarsC1, piVarsC2, nVarsC1, nVarsC2 ); + + // check if the divisor for this pair already exists + Key %= p->nTableSize; + Fxu_TableForEachDouble( p, Key, pDouble ) + { + pPair = pDouble->lPairs.pHead; + if ( pPair->nLits1 != nVarsC1 ) + continue; + if ( pPair->nLits2 != nVarsC2 ) + continue; + // get the cubes of this divisor + Fxu_MatrixGetDoubleVars( p, pDouble, piVarsC1_, piVarsC2_, &nVarsC1_, &nVarsC2_ ); + // compare lits of the first cube + for ( i = 0; i < nVarsC1; i++ ) + if ( piVarsC1[i] != piVarsC1_[i] ) + break; + if ( i != nVarsC1 ) + continue; + // compare lits of the second cube + for ( i = 0; i < nVarsC2; i++ ) + if ( piVarsC2[i] != piVarsC2_[i] ) + break; + if ( i != nVarsC2 ) + continue; + return pDouble; + } + return NULL; +} + + + + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Fxu_SelectSCD( Fxu_Matrix * p, int WeightLimit, Fxu_Var ** ppVar1, Fxu_Var ** ppVar2 ) +{ +// int * pValue2Node = p->pValue2Node; + Fxu_Var * pVar1; + Fxu_Var * pVar2, * pVarTemp; + Fxu_Lit * pLitV, * pLitH; + int Coin; + int CounterAll; + int CounterTest; + int WeightCur; + int WeightBest; + + CounterAll = 0; + CounterTest = 0; + + WeightBest = -10; + + // iterate through the columns in the matrix + Fxu_MatrixForEachVariable( p, pVar1 ) + { + // start collecting the affected vars + Fxu_MatrixRingVarsStart( p ); + + // go through all the literals of this variable + for ( pLitV = pVar1->lLits.pHead; pLitV; pLitV = pLitV->pVNext ) + { + // for this literal, go through all the horizontal literals + for ( pLitH = pLitV->pHNext; pLitH; pLitH = pLitH->pHNext ) + { + // get another variable + pVar2 = pLitH->pVar; + CounterAll++; + // skip the var if it is already used + if ( pVar2->pOrder ) + continue; + // skip the var if it belongs to the same node +// if ( pValue2Node[pVar1->iVar] == pValue2Node[pVar2->iVar] ) +// continue; + // collect the var + Fxu_MatrixRingVarsAdd( p, pVar2 ); + } + } + // stop collecting the selected vars + Fxu_MatrixRingVarsStop( p ); + + // iterate through the selected vars + Fxu_MatrixForEachVarInRing( p, pVar2 ) + { + CounterTest++; + + // count the coincidence + Coin = Fxu_SingleCountCoincidence( p, pVar1, pVar2 ); + assert( Coin > 0 ); + + // get the new weight + WeightCur = Coin - 2; + + // compare the weights + if ( WeightBest < WeightCur ) + { + WeightBest = WeightCur; + *ppVar1 = pVar1; + *ppVar2 = pVar2; + } + } + // unmark the vars + Fxu_MatrixForEachVarInRingSafe( p, pVar2, pVarTemp ) + pVar2->pOrder = NULL; + Fxu_MatrixRingVarsReset( p ); + } + +// if ( WeightBest == WeightLimit ) +// return -1; + return WeightBest; +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/fxu/fxuSingle.c b/src/opt/fxu/fxuSingle.c new file mode 100644 index 00000000..73d9a76c --- /dev/null +++ b/src/opt/fxu/fxuSingle.c @@ -0,0 +1,284 @@ +/**CFile**************************************************************** + + FileName [fxuSingle.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Procedures to compute the set of single-cube divisors.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: fxuSingle.c,v 1.0 2003/02/01 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "fxuInt.h" +#include "vec.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static void Fxu_MatrixComputeSinglesOneCollect( Fxu_Matrix * p, Fxu_Var * pVar, Vec_Ptr_t * vSingles ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Computes and adds all single-cube divisors to storage.] + + Description [This procedure should be called once when the matrix is + already contructed before the process of logic extraction begins..] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_MatrixComputeSingles( Fxu_Matrix * p, int fUse0, int nSingleMax ) +{ + Fxu_Var * pVar; + Vec_Ptr_t * vSingles; + int i, k; + // set the weight limit + p->nWeightLimit = 1 - fUse0; + // iterate through columns in the matrix and collect single-cube divisors + vSingles = Vec_PtrAlloc( 10000 ); + Fxu_MatrixForEachVariable( p, pVar ) + Fxu_MatrixComputeSinglesOneCollect( p, pVar, vSingles ); + p->nSingleTotal = Vec_PtrSize(vSingles) / 3; + // check if divisors should be filtered + if ( Vec_PtrSize(vSingles) > nSingleMax ) + { + int * pWeigtCounts, nDivCount, Weight, i, c;; + assert( Vec_PtrSize(vSingles) % 3 == 0 ); + // count how many divisors have the given weight + pWeigtCounts = ALLOC( int, 1000 ); + memset( pWeigtCounts, 0, sizeof(int) * 1000 ); + for ( i = 2; i < Vec_PtrSize(vSingles); i += 3 ) + { + Weight = (int)Vec_PtrEntry(vSingles, i); + if ( Weight >= 999 ) + pWeigtCounts[999]++; + else + pWeigtCounts[Weight]++; + } + // select the bound on the weight (above this bound, singles will be included) + nDivCount = 0; + for ( c = 999; c >= 0; c-- ) + { + nDivCount += pWeigtCounts[c]; + if ( nDivCount >= nSingleMax ) + break; + } + free( pWeigtCounts ); + // collect singles with the given costs + k = 0; + for ( i = 2; i < Vec_PtrSize(vSingles); i += 3 ) + { + Weight = (int)Vec_PtrEntry(vSingles, i); + if ( Weight < c ) + continue; + Vec_PtrWriteEntry( vSingles, k++, Vec_PtrEntry(vSingles, i-2) ); + Vec_PtrWriteEntry( vSingles, k++, Vec_PtrEntry(vSingles, i-1) ); + Vec_PtrWriteEntry( vSingles, k++, Vec_PtrEntry(vSingles, i) ); + if ( k/3 == nSingleMax ) + break; + } + Vec_PtrShrink( vSingles, k ); + // adjust the weight limit + p->nWeightLimit = c; + } + // collect the selected divisors + assert( Vec_PtrSize(vSingles) % 3 == 0 ); + for ( i = 0; i < Vec_PtrSize(vSingles); i += 3 ) + { + Fxu_MatrixAddSingle( p, + Vec_PtrEntry(vSingles,i), + Vec_PtrEntry(vSingles,i+1), + (int)Vec_PtrEntry(vSingles,i+2) ); + } + Vec_PtrFree( vSingles ); +} + +/**Function************************************************************* + + Synopsis [Adds the single-cube divisors associated with a new column.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_MatrixComputeSinglesOneCollect( Fxu_Matrix * p, Fxu_Var * pVar, Vec_Ptr_t * vSingles ) +{ + Fxu_Lit * pLitV, * pLitH; + Fxu_Var * pVar2; + int Coin; + int WeightCur; + + // start collecting the affected vars + Fxu_MatrixRingVarsStart( p ); + // go through all the literals of this variable + for ( pLitV = pVar->lLits.pHead; pLitV; pLitV = pLitV->pVNext ) + // for this literal, go through all the horizontal literals + for ( pLitH = pLitV->pHPrev; pLitH; pLitH = pLitH->pHPrev ) + { + // get another variable + pVar2 = pLitH->pVar; + // skip the var if it is already used + if ( pVar2->pOrder ) + continue; + // skip the var if it belongs to the same node +// if ( pValue2Node[pVar->iVar] == pValue2Node[pVar2->iVar] ) +// continue; + // collect the var + Fxu_MatrixRingVarsAdd( p, pVar2 ); + } + // stop collecting the selected vars + Fxu_MatrixRingVarsStop( p ); + + // iterate through the selected vars + Fxu_MatrixForEachVarInRing( p, pVar2 ) + { + // count the coincidence + Coin = Fxu_SingleCountCoincidence( p, pVar2, pVar ); + assert( Coin > 0 ); + // get the new weight + WeightCur = Coin - 2; + // peformance fix (August 24, 2007) + if ( WeightCur >= p->nWeightLimit ) + { + Vec_PtrPush( vSingles, pVar2 ); + Vec_PtrPush( vSingles, pVar ); + Vec_PtrPush( vSingles, (void *)WeightCur ); + } + } + + // unmark the vars + Fxu_MatrixRingVarsUnmark( p ); +} + +/**Function************************************************************* + + Synopsis [Adds the single-cube divisors associated with a new column.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_MatrixComputeSinglesOne( Fxu_Matrix * p, Fxu_Var * pVar ) +{ + Fxu_Lit * pLitV, * pLitH; + Fxu_Var * pVar2; + int Coin; + int WeightCur; + + // start collecting the affected vars + Fxu_MatrixRingVarsStart( p ); + // go through all the literals of this variable + for ( pLitV = pVar->lLits.pHead; pLitV; pLitV = pLitV->pVNext ) + // for this literal, go through all the horizontal literals + for ( pLitH = pLitV->pHPrev; pLitH; pLitH = pLitH->pHPrev ) + { + // get another variable + pVar2 = pLitH->pVar; + // skip the var if it is already used + if ( pVar2->pOrder ) + continue; + // skip the var if it belongs to the same node +// if ( pValue2Node[pVar->iVar] == pValue2Node[pVar2->iVar] ) +// continue; + // collect the var + Fxu_MatrixRingVarsAdd( p, pVar2 ); + } + // stop collecting the selected vars + Fxu_MatrixRingVarsStop( p ); + + // iterate through the selected vars + Fxu_MatrixForEachVarInRing( p, pVar2 ) + { + // count the coincidence + Coin = Fxu_SingleCountCoincidence( p, pVar2, pVar ); + assert( Coin > 0 ); + // get the new weight + WeightCur = Coin - 2; + // peformance fix (August 24, 2007) +// if ( WeightCur >= 0 ) +// Fxu_MatrixAddSingle( p, pVar2, pVar, WeightCur ); + if ( WeightCur >= p->nWeightLimit ) + Fxu_MatrixAddSingle( p, pVar2, pVar, WeightCur ); + } + // unmark the vars + Fxu_MatrixRingVarsUnmark( p ); +} + +/**Function************************************************************* + + Synopsis [Computes the coincidence count of two columns.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Fxu_SingleCountCoincidence( Fxu_Matrix * p, Fxu_Var * pVar1, Fxu_Var * pVar2 ) +{ + Fxu_Lit * pLit1, * pLit2; + int Result; + + // compute the coincidence count + Result = 0; + pLit1 = pVar1->lLits.pHead; + pLit2 = pVar2->lLits.pHead; + while ( 1 ) + { + if ( pLit1 && pLit2 ) + { + if ( pLit1->pCube->pVar->iVar == pLit2->pCube->pVar->iVar ) + { // the variables are the same + if ( pLit1->iCube == pLit2->iCube ) + { // the literals are the same + pLit1 = pLit1->pVNext; + pLit2 = pLit2->pVNext; + // add this literal to the coincidence + Result++; + } + else if ( pLit1->iCube < pLit2->iCube ) + pLit1 = pLit1->pVNext; + else + pLit2 = pLit2->pVNext; + } + else if ( pLit1->pCube->pVar->iVar < pLit2->pCube->pVar->iVar ) + pLit1 = pLit1->pVNext; + else + pLit2 = pLit2->pVNext; + } + else if ( pLit1 && !pLit2 ) + pLit1 = pLit1->pVNext; + else if ( !pLit1 && pLit2 ) + pLit2 = pLit2->pVNext; + else + break; + } + return Result; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/fxu/fxuUpdate.c b/src/opt/fxu/fxuUpdate.c new file mode 100644 index 00000000..274f79f6 --- /dev/null +++ b/src/opt/fxu/fxuUpdate.c @@ -0,0 +1,806 @@ +/**CFile**************************************************************** + + FileName [fxuUpdate.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Updating the sparse matrix when divisors are accepted.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: fxuUpdate.c,v 1.0 2003/02/01 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "fxuInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static void Fxu_UpdateDoublePairs( Fxu_Matrix * p, Fxu_Double * pDouble, Fxu_Var * pVar ); +static void Fxu_UpdateMatrixDoubleCreateCubes( Fxu_Matrix * p, Fxu_Cube * pCube1, Fxu_Cube * pCube2, Fxu_Double * pDiv ); +static void Fxu_UpdateMatrixDoubleClean( Fxu_Matrix * p, Fxu_Cube * pCubeUse, Fxu_Cube * pCubeRem ); +static void Fxu_UpdateMatrixSingleClean( Fxu_Matrix * p, Fxu_Var * pVar1, Fxu_Var * pVar2, Fxu_Var * pVarNew ); + +static void Fxu_UpdateCreateNewVars( Fxu_Matrix * p, Fxu_Var ** ppVarC, Fxu_Var ** ppVarD, int nCubes ); +static int Fxu_UpdatePairCompare( Fxu_Pair ** ppP1, Fxu_Pair ** ppP2 ); +static void Fxu_UpdatePairsSort( Fxu_Matrix * p, Fxu_Double * pDouble ); + +static void Fxu_UpdateCleanOldDoubles( Fxu_Matrix * p, Fxu_Double * pDiv, Fxu_Cube * pCube ); +static void Fxu_UpdateAddNewDoubles( Fxu_Matrix * p, Fxu_Cube * pCube ); +static void Fxu_UpdateCleanOldSingles( Fxu_Matrix * p ); +static void Fxu_UpdateAddNewSingles( Fxu_Matrix * p, Fxu_Var * pVar ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Updates the matrix after selecting two divisors.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_Update( Fxu_Matrix * p, Fxu_Single * pSingle, Fxu_Double * pDouble ) +{ + Fxu_Cube * pCube, * pCubeNew; + Fxu_Var * pVarC, * pVarD; + Fxu_Var * pVar1, * pVar2; + + // consider trivial cases + if ( pSingle == NULL ) + { + assert( pDouble->Weight == Fxu_HeapDoubleReadMaxWeight( p->pHeapDouble ) ); + Fxu_UpdateDouble( p ); + return; + } + if ( pDouble == NULL ) + { + assert( pSingle->Weight == Fxu_HeapSingleReadMaxWeight( p->pHeapSingle ) ); + Fxu_UpdateSingle( p ); + return; + } + + // get the variables of the single + pVar1 = pSingle->pVar1; + pVar2 = pSingle->pVar2; + + // remove the best double from the heap + Fxu_HeapDoubleDelete( p->pHeapDouble, pDouble ); + // remove the best divisor from the table + Fxu_ListTableDelDivisor( p, pDouble ); + + // create two new columns (vars) + Fxu_UpdateCreateNewVars( p, &pVarC, &pVarD, 1 ); + // create one new row (cube) + pCubeNew = Fxu_MatrixAddCube( p, pVarD, 0 ); + pCubeNew->pFirst = pCubeNew; + // set the first cube of the positive var + pVarD->pFirst = pCubeNew; + + // start collecting the affected vars and cubes + Fxu_MatrixRingCubesStart( p ); + Fxu_MatrixRingVarsStart( p ); + // add the vars + Fxu_MatrixRingVarsAdd( p, pVar1 ); + Fxu_MatrixRingVarsAdd( p, pVar2 ); + // remove the literals and collect the affected cubes + // remove the divisors associated with this cube + // add to the affected cube the literal corresponding to the new column + Fxu_UpdateMatrixSingleClean( p, pVar1, pVar2, pVarD ); + // replace each two cubes of the pair by one new cube + // the new cube contains the base and the new literal + Fxu_UpdateDoublePairs( p, pDouble, pVarC ); + // stop collecting the affected vars and cubes + Fxu_MatrixRingCubesStop( p ); + Fxu_MatrixRingVarsStop( p ); + + // add the literals to the new cube + assert( pVar1->iVar < pVar2->iVar ); + assert( Fxu_SingleCountCoincidence( p, pVar1, pVar2 ) == 0 ); + Fxu_MatrixAddLiteral( p, pCubeNew, pVar1 ); + Fxu_MatrixAddLiteral( p, pCubeNew, pVar2 ); + + // create new doubles; we cannot add them in the same loop + // because we first have to create *all* new cubes for each node + Fxu_MatrixForEachCubeInRing( p, pCube ) + Fxu_UpdateAddNewDoubles( p, pCube ); + // update the singles after removing some literals + Fxu_UpdateCleanOldSingles( p ); + + // undo the temporary rings with cubes and vars + Fxu_MatrixRingCubesUnmark( p ); + Fxu_MatrixRingVarsUnmark( p ); + // we should undo the rings before creating new singles + + // create new singles + Fxu_UpdateAddNewSingles( p, pVarC ); + Fxu_UpdateAddNewSingles( p, pVarD ); + + // recycle the divisor + MEM_FREE_FXU( p, Fxu_Double, 1, pDouble ); + p->nDivs3++; +} + +/**Function************************************************************* + + Synopsis [Updates after accepting single cube divisor.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_UpdateSingle( Fxu_Matrix * p ) +{ + Fxu_Single * pSingle; + Fxu_Cube * pCube, * pCubeNew; + Fxu_Var * pVarC, * pVarD; + Fxu_Var * pVar1, * pVar2; + + // read the best divisor from the heap + pSingle = Fxu_HeapSingleReadMax( p->pHeapSingle ); + // get the variables of this single-cube divisor + pVar1 = pSingle->pVar1; + pVar2 = pSingle->pVar2; + + // create two new columns (vars) + Fxu_UpdateCreateNewVars( p, &pVarC, &pVarD, 1 ); + // create one new row (cube) + pCubeNew = Fxu_MatrixAddCube( p, pVarD, 0 ); + pCubeNew->pFirst = pCubeNew; + // set the first cube + pVarD->pFirst = pCubeNew; + + // start collecting the affected vars and cubes + Fxu_MatrixRingCubesStart( p ); + Fxu_MatrixRingVarsStart( p ); + // add the vars + Fxu_MatrixRingVarsAdd( p, pVar1 ); + Fxu_MatrixRingVarsAdd( p, pVar2 ); + // remove the literals and collect the affected cubes + // remove the divisors associated with this cube + // add to the affected cube the literal corresponding to the new column + Fxu_UpdateMatrixSingleClean( p, pVar1, pVar2, pVarD ); + // stop collecting the affected vars and cubes + Fxu_MatrixRingCubesStop( p ); + Fxu_MatrixRingVarsStop( p ); + + // add the literals to the new cube + assert( pVar1->iVar < pVar2->iVar ); + assert( Fxu_SingleCountCoincidence( p, pVar1, pVar2 ) == 0 ); + Fxu_MatrixAddLiteral( p, pCubeNew, pVar1 ); + Fxu_MatrixAddLiteral( p, pCubeNew, pVar2 ); + + // create new doubles; we cannot add them in the same loop + // because we first have to create *all* new cubes for each node + Fxu_MatrixForEachCubeInRing( p, pCube ) + Fxu_UpdateAddNewDoubles( p, pCube ); + // update the singles after removing some literals + Fxu_UpdateCleanOldSingles( p ); + // we should undo the rings before creating new singles + + // unmark the cubes + Fxu_MatrixRingCubesUnmark( p ); + Fxu_MatrixRingVarsUnmark( p ); + + // create new singles + Fxu_UpdateAddNewSingles( p, pVarC ); + Fxu_UpdateAddNewSingles( p, pVarD ); + p->nDivs1++; +} + +/**Function************************************************************* + + Synopsis [Updates the matrix after accepting a double cube divisor.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_UpdateDouble( Fxu_Matrix * p ) +{ + Fxu_Double * pDiv; + Fxu_Cube * pCube, * pCubeNew1, * pCubeNew2; + Fxu_Var * pVarC, * pVarD; + + // remove the best divisor from the heap + pDiv = Fxu_HeapDoubleGetMax( p->pHeapDouble ); + // remove the best divisor from the table + Fxu_ListTableDelDivisor( p, pDiv ); + + // create two new columns (vars) + Fxu_UpdateCreateNewVars( p, &pVarC, &pVarD, 2 ); + // create two new rows (cubes) + pCubeNew1 = Fxu_MatrixAddCube( p, pVarD, 0 ); + pCubeNew1->pFirst = pCubeNew1; + pCubeNew2 = Fxu_MatrixAddCube( p, pVarD, 1 ); + pCubeNew2->pFirst = pCubeNew1; + // set the first cube + pVarD->pFirst = pCubeNew1; + + // add the literals to the new cubes + Fxu_UpdateMatrixDoubleCreateCubes( p, pCubeNew1, pCubeNew2, pDiv ); + + // start collecting the affected cubes and vars + Fxu_MatrixRingCubesStart( p ); + Fxu_MatrixRingVarsStart( p ); + // replace each two cubes of the pair by one new cube + // the new cube contains the base and the new literal + Fxu_UpdateDoublePairs( p, pDiv, pVarD ); + // stop collecting the affected cubes and vars + Fxu_MatrixRingCubesStop( p ); + Fxu_MatrixRingVarsStop( p ); + + // create new doubles; we cannot add them in the same loop + // because we first have to create *all* new cubes for each node + Fxu_MatrixForEachCubeInRing( p, pCube ) + Fxu_UpdateAddNewDoubles( p, pCube ); + // update the singles after removing some literals + Fxu_UpdateCleanOldSingles( p ); + + // undo the temporary rings with cubes and vars + Fxu_MatrixRingCubesUnmark( p ); + Fxu_MatrixRingVarsUnmark( p ); + // we should undo the rings before creating new singles + + // create new singles + Fxu_UpdateAddNewSingles( p, pVarC ); + Fxu_UpdateAddNewSingles( p, pVarD ); + + // recycle the divisor + MEM_FREE_FXU( p, Fxu_Double, 1, pDiv ); + p->nDivs2++; +} + +/**Function************************************************************* + + Synopsis [Update the pairs.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_UpdateDoublePairs( Fxu_Matrix * p, Fxu_Double * pDouble, Fxu_Var * pVar ) +{ + Fxu_Pair * pPair; + Fxu_Cube * pCubeUse, * pCubeRem; + int i; + + // collect and sort the pairs + Fxu_UpdatePairsSort( p, pDouble ); +// for ( i = 0; i < p->nPairsTemp; i++ ) + for ( i = 0; i < p->vPairs->nSize; i++ ) + { + // get the pair +// pPair = p->pPairsTemp[i]; + pPair = p->vPairs->pArray[i]; + // out of the two cubes, select the one which comes earlier + pCubeUse = Fxu_PairMinCube( pPair ); + pCubeRem = Fxu_PairMaxCube( pPair ); + // collect the affected cube + assert( pCubeUse->pOrder == NULL ); + Fxu_MatrixRingCubesAdd( p, pCubeUse ); + + // remove some literals from pCubeUse and all literals from pCubeRem + Fxu_UpdateMatrixDoubleClean( p, pCubeUse, pCubeRem ); + // add a literal that depends on the new variable + Fxu_MatrixAddLiteral( p, pCubeUse, pVar ); + // check the literal count + assert( pCubeUse->lLits.nItems == pPair->nBase + 1 ); + assert( pCubeRem->lLits.nItems == 0 ); + + // update the divisors by removing useless pairs + Fxu_UpdateCleanOldDoubles( p, pDouble, pCubeUse ); + Fxu_UpdateCleanOldDoubles( p, pDouble, pCubeRem ); + // remove the pair + MEM_FREE_FXU( p, Fxu_Pair, 1, pPair ); + } + p->vPairs->nSize = 0; +} + +/**Function************************************************************* + + Synopsis [Add two cubes corresponding to the given double-cube divisor.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_UpdateMatrixDoubleCreateCubes( Fxu_Matrix * p, Fxu_Cube * pCube1, Fxu_Cube * pCube2, Fxu_Double * pDiv ) +{ + Fxu_Lit * pLit1, * pLit2; + Fxu_Pair * pPair; + int nBase, nLits1, nLits2; + + // fill in the SOP and copy the fanins + nBase = nLits1 = nLits2 = 0; + pPair = pDiv->lPairs.pHead; + pLit1 = pPair->pCube1->lLits.pHead; + pLit2 = pPair->pCube2->lLits.pHead; + while ( 1 ) + { + if ( pLit1 && pLit2 ) + { + if ( pLit1->iVar == pLit2->iVar ) + { // skip the cube free part + pLit1 = pLit1->pHNext; + pLit2 = pLit2->pHNext; + nBase++; + } + else if ( pLit1->iVar < pLit2->iVar ) + { // add literal to the first cube + Fxu_MatrixAddLiteral( p, pCube1, pLit1->pVar ); + // move to the next literal in this cube + pLit1 = pLit1->pHNext; + nLits1++; + } + else + { // add literal to the second cube + Fxu_MatrixAddLiteral( p, pCube2, pLit2->pVar ); + // move to the next literal in this cube + pLit2 = pLit2->pHNext; + nLits2++; + } + } + else if ( pLit1 && !pLit2 ) + { // add literal to the first cube + Fxu_MatrixAddLiteral( p, pCube1, pLit1->pVar ); + // move to the next literal in this cube + pLit1 = pLit1->pHNext; + nLits1++; + } + else if ( !pLit1 && pLit2 ) + { // add literal to the second cube + Fxu_MatrixAddLiteral( p, pCube2, pLit2->pVar ); + // move to the next literal in this cube + pLit2 = pLit2->pHNext; + nLits2++; + } + else + break; + } + assert( pPair->nLits1 == nLits1 ); + assert( pPair->nLits2 == nLits2 ); + assert( pPair->nBase == nBase ); +} + + +/**Function************************************************************* + + Synopsis [Create the node equal to double-cube divisor.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_UpdateMatrixDoubleClean( Fxu_Matrix * p, Fxu_Cube * pCubeUse, Fxu_Cube * pCubeRem ) +{ + Fxu_Lit * pLit1, * bLit1Next; + Fxu_Lit * pLit2, * bLit2Next; + + // initialize the starting literals + pLit1 = pCubeUse->lLits.pHead; + pLit2 = pCubeRem->lLits.pHead; + bLit1Next = pLit1? pLit1->pHNext: NULL; + bLit2Next = pLit2? pLit2->pHNext: NULL; + // go through the pair and remove the literals in the base + // from the first cube and all literals from the second cube + while ( 1 ) + { + if ( pLit1 && pLit2 ) + { + if ( pLit1->iVar == pLit2->iVar ) + { // this literal is present in both cubes - it belongs to the base + // mark the affected var + if ( pLit1->pVar->pOrder == NULL ) + Fxu_MatrixRingVarsAdd( p, pLit1->pVar ); + // leave the base in pCubeUse; delete it from pCubeRem + Fxu_MatrixDelLiteral( p, pLit2 ); + // step to the next literals + pLit1 = bLit1Next; + pLit2 = bLit2Next; + bLit1Next = pLit1? pLit1->pHNext: NULL; + bLit2Next = pLit2? pLit2->pHNext: NULL; + } + else if ( pLit1->iVar < pLit2->iVar ) + { // this literal is present in pCubeUse - remove it + // mark the affected var + if ( pLit1->pVar->pOrder == NULL ) + Fxu_MatrixRingVarsAdd( p, pLit1->pVar ); + // delete this literal + Fxu_MatrixDelLiteral( p, pLit1 ); + // step to the next literals + pLit1 = bLit1Next; + bLit1Next = pLit1? pLit1->pHNext: NULL; + } + else + { // this literal is present in pCubeRem - remove it + // mark the affected var + if ( pLit2->pVar->pOrder == NULL ) + Fxu_MatrixRingVarsAdd( p, pLit2->pVar ); + // delete this literal + Fxu_MatrixDelLiteral( p, pLit2 ); + // step to the next literals + pLit2 = bLit2Next; + bLit2Next = pLit2? pLit2->pHNext: NULL; + } + } + else if ( pLit1 && !pLit2 ) + { // this literal is present in pCubeUse - leave it + // mark the affected var + if ( pLit1->pVar->pOrder == NULL ) + Fxu_MatrixRingVarsAdd( p, pLit1->pVar ); + // delete this literal + Fxu_MatrixDelLiteral( p, pLit1 ); + // step to the next literals + pLit1 = bLit1Next; + bLit1Next = pLit1? pLit1->pHNext: NULL; + } + else if ( !pLit1 && pLit2 ) + { // this literal is present in pCubeRem - remove it + // mark the affected var + if ( pLit2->pVar->pOrder == NULL ) + Fxu_MatrixRingVarsAdd( p, pLit2->pVar ); + // delete this literal + Fxu_MatrixDelLiteral( p, pLit2 ); + // step to the next literals + pLit2 = bLit2Next; + bLit2Next = pLit2? pLit2->pHNext: NULL; + } + else + break; + } +} + +/**Function************************************************************* + + Synopsis [Updates the matrix after selecting a single cube divisor.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_UpdateMatrixSingleClean( Fxu_Matrix * p, Fxu_Var * pVar1, Fxu_Var * pVar2, Fxu_Var * pVarNew ) +{ + Fxu_Lit * pLit1, * bLit1Next; + Fxu_Lit * pLit2, * bLit2Next; + + // initialize the starting literals + pLit1 = pVar1->lLits.pHead; + pLit2 = pVar2->lLits.pHead; + bLit1Next = pLit1? pLit1->pVNext: NULL; + bLit2Next = pLit2? pLit2->pVNext: NULL; + while ( 1 ) + { + if ( pLit1 && pLit2 ) + { + if ( pLit1->pCube->pVar->iVar == pLit2->pCube->pVar->iVar ) + { // these literals coincide + if ( pLit1->iCube == pLit2->iCube ) + { // these literals coincide + + // collect the affected cube + assert( pLit1->pCube->pOrder == NULL ); + Fxu_MatrixRingCubesAdd( p, pLit1->pCube ); + + // add the literal to this cube corresponding to the new column + Fxu_MatrixAddLiteral( p, pLit1->pCube, pVarNew ); + // clean the old cubes + Fxu_UpdateCleanOldDoubles( p, NULL, pLit1->pCube ); + + // remove the literals + Fxu_MatrixDelLiteral( p, pLit1 ); + Fxu_MatrixDelLiteral( p, pLit2 ); + + // go to the next literals + pLit1 = bLit1Next; + pLit2 = bLit2Next; + bLit1Next = pLit1? pLit1->pVNext: NULL; + bLit2Next = pLit2? pLit2->pVNext: NULL; + } + else if ( pLit1->iCube < pLit2->iCube ) + { + pLit1 = bLit1Next; + bLit1Next = pLit1? pLit1->pVNext: NULL; + } + else + { + pLit2 = bLit2Next; + bLit2Next = pLit2? pLit2->pVNext: NULL; + } + } + else if ( pLit1->pCube->pVar->iVar < pLit2->pCube->pVar->iVar ) + { + pLit1 = bLit1Next; + bLit1Next = pLit1? pLit1->pVNext: NULL; + } + else + { + pLit2 = bLit2Next; + bLit2Next = pLit2? pLit2->pVNext: NULL; + } + } + else if ( pLit1 && !pLit2 ) + { + pLit1 = bLit1Next; + bLit1Next = pLit1? pLit1->pVNext: NULL; + } + else if ( !pLit1 && pLit2 ) + { + pLit2 = bLit2Next; + bLit2Next = pLit2? pLit2->pVNext: NULL; + } + else + break; + } +} + +/**Function************************************************************* + + Synopsis [Sort the pairs.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_UpdatePairsSort( Fxu_Matrix * p, Fxu_Double * pDouble ) +{ + Fxu_Pair * pPair; + // order the pairs by the first cube to ensure that new literals are added + // to the matrix from top to bottom - collect pairs into the array + p->vPairs->nSize = 0; + Fxu_DoubleForEachPair( pDouble, pPair ) + Vec_PtrPush( p->vPairs, pPair ); + if ( p->vPairs->nSize < 2 ) + return; + // sort + qsort( (void *)p->vPairs->pArray, p->vPairs->nSize, sizeof(Fxu_Pair *), + (int (*)(const void *, const void *)) Fxu_UpdatePairCompare ); + assert( Fxu_UpdatePairCompare( (Fxu_Pair**)p->vPairs->pArray, (Fxu_Pair**)p->vPairs->pArray + p->vPairs->nSize - 1 ) < 0 ); +} + +/**Function************************************************************* + + Synopsis [Compares the vars by their number.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Fxu_UpdatePairCompare( Fxu_Pair ** ppP1, Fxu_Pair ** ppP2 ) +{ + Fxu_Cube * pC1 = (*ppP1)->pCube1; + Fxu_Cube * pC2 = (*ppP2)->pCube1; + int iP1CubeMin, iP2CubeMin; + if ( pC1->pVar->iVar < pC2->pVar->iVar ) + return -1; + if ( pC1->pVar->iVar > pC2->pVar->iVar ) + return 1; + iP1CubeMin = Fxu_PairMinCubeInt( *ppP1 ); + iP2CubeMin = Fxu_PairMinCubeInt( *ppP2 ); + if ( iP1CubeMin < iP2CubeMin ) + return -1; + if ( iP1CubeMin > iP2CubeMin ) + return 1; + assert( 0 ); + return 0; +} + + +/**Function************************************************************* + + Synopsis [Create new variables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_UpdateCreateNewVars( Fxu_Matrix * p, Fxu_Var ** ppVarC, Fxu_Var ** ppVarD, int nCubes ) +{ + Fxu_Var * pVarC, * pVarD; + + // add a new column for the complement + pVarC = Fxu_MatrixAddVar( p ); + pVarC->nCubes = 0; + // add a new column for the divisor + pVarD = Fxu_MatrixAddVar( p ); + pVarD->nCubes = nCubes; + + // mark this entry in the Value2Node array +// assert( p->pValue2Node[pVarC->iVar] > 0 ); +// p->pValue2Node[pVarD->iVar ] = p->pValue2Node[pVarC->iVar]; +// p->pValue2Node[pVarD->iVar+1] = p->pValue2Node[pVarC->iVar]+1; + + *ppVarC = pVarC; + *ppVarD = pVarD; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_UpdateCleanOldDoubles( Fxu_Matrix * p, Fxu_Double * pDiv, Fxu_Cube * pCube ) +{ + Fxu_Double * pDivCur; + Fxu_Pair * pPair; + int i; + + // if the cube is a recently introduced one + // it does not have pairs allocated + // in this case, there is nothing to update + if ( pCube->pVar->ppPairs == NULL ) + return; + + // go through all the pairs of this cube + Fxu_CubeForEachPair( pCube, pPair, i ) + { + // get the divisor of this pair + pDivCur = pPair->pDiv; + // skip the current divisor + if ( pDivCur == pDiv ) + continue; + // remove this pair + Fxu_ListDoubleDelPair( pDivCur, pPair ); + // the divisor may have become useless by now + if ( pDivCur->lPairs.nItems == 0 ) + { + assert( pDivCur->Weight == pPair->nBase - 1 ); + Fxu_HeapDoubleDelete( p->pHeapDouble, pDivCur ); + Fxu_MatrixDelDivisor( p, pDivCur ); + } + else + { + // update the divisor's weight + pDivCur->Weight -= pPair->nLits1 + pPair->nLits2 - 1 + pPair->nBase; + Fxu_HeapDoubleUpdate( p->pHeapDouble, pDivCur ); + } + MEM_FREE_FXU( p, Fxu_Pair, 1, pPair ); + } + // finally erase all the pair info associated with this cube + Fxu_PairClearStorage( pCube ); +} + +/**Function************************************************************* + + Synopsis [Adds the new divisors that depend on the cube.] + + Description [Go through all the non-empty cubes of this cover + (except the given cube) and, for each of them, add the new divisor + with the given cube.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_UpdateAddNewDoubles( Fxu_Matrix * p, Fxu_Cube * pCube ) +{ + Fxu_Cube * pTemp; + assert( pCube->pOrder ); + + // if the cube is a recently introduced one + // it does not have pairs allocated + // in this case, there is nothing to update + if ( pCube->pVar->ppPairs == NULL ) + return; + + for ( pTemp = pCube->pFirst; pTemp->pVar == pCube->pVar; pTemp = pTemp->pNext ) + { + // do not add pairs with the empty cubes + if ( pTemp->lLits.nItems == 0 ) + continue; + // to prevent adding duplicated pairs of the new cubes + // do not add the pair, if the current cube is marked + if ( pTemp->pOrder && pTemp >= pCube ) + continue; + Fxu_MatrixAddDivisor( p, pTemp, pCube ); + } +} + +/**Function************************************************************* + + Synopsis [Removes old single cube divisors.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_UpdateCleanOldSingles( Fxu_Matrix * p ) +{ + Fxu_Single * pSingle, * pSingle2; + int WeightNew; + int Counter = 0; + + Fxu_MatrixForEachSingleSafe( p, pSingle, pSingle2 ) + { + // if at least one of the variables is marked, recalculate + if ( pSingle->pVar1->pOrder || pSingle->pVar2->pOrder ) + { + Counter++; + // get the new weight + WeightNew = -2 + Fxu_SingleCountCoincidence( p, pSingle->pVar1, pSingle->pVar2 ); + if ( WeightNew >= 0 ) + { + pSingle->Weight = WeightNew; + Fxu_HeapSingleUpdate( p->pHeapSingle, pSingle ); + } + else + { + Fxu_HeapSingleDelete( p->pHeapSingle, pSingle ); + Fxu_ListMatrixDelSingle( p, pSingle ); + MEM_FREE_FXU( p, Fxu_Single, 1, pSingle ); + } + } + } +// printf( "Called procedure %d times.\n", Counter ); +} + +/**Function************************************************************* + + Synopsis [Updates the single cube divisors.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fxu_UpdateAddNewSingles( Fxu_Matrix * p, Fxu_Var * pVar ) +{ + Fxu_MatrixComputeSinglesOne( p, pVar ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/fxu/module.make b/src/opt/fxu/module.make new file mode 100644 index 00000000..dd8acd40 --- /dev/null +++ b/src/opt/fxu/module.make @@ -0,0 +1,12 @@ +SRC += src/opt/fxu/fxu.c \ + src/opt/fxu/fxuCreate.c \ + src/opt/fxu/fxuHeapD.c \ + src/opt/fxu/fxuHeapS.c \ + src/opt/fxu/fxuList.c \ + src/opt/fxu/fxuMatrix.c \ + src/opt/fxu/fxuPair.c \ + src/opt/fxu/fxuPrint.c \ + src/opt/fxu/fxuReduce.c \ + src/opt/fxu/fxuSelect.c \ + src/opt/fxu/fxuSingle.c \ + src/opt/fxu/fxuUpdate.c diff --git a/src/opt/lpk/lpk.h b/src/opt/lpk/lpk.h new file mode 100644 index 00000000..2a642db2 --- /dev/null +++ b/src/opt/lpk/lpk.h @@ -0,0 +1,84 @@ +/**CFile**************************************************************** + + FileName [lpk.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Fast Boolean matching for LUT structures.] + + Synopsis [External declarations.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - April 28, 2007.] + + Revision [$Id: lpk.h,v 1.00 2007/04/28 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef __LPK_H__ +#define __LPK_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// BASIC TYPES /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Lpk_Par_t_ Lpk_Par_t; +struct Lpk_Par_t_ +{ + // user-controlled parameters + int nLutsMax; // (N) the maximum number of LUTs in the structure + int nLutsOver; // (Q) the maximum number of LUTs not in the MFFC + int nVarsShared; // (S) the maximum number of shared variables (crossbars) + int nGrowthLevel; // (L) the maximum increase in the node level after resynthesis + int fSatur; // iterate till saturation + int fZeroCost; // accept zero-cost replacements + int fFirst; // use root node and first cut only + int fOldAlgo; // use old algorithm + int fVerbose; // the verbosiness flag + int fVeryVerbose; // additional verbose info printout + // internal parameters + int nLutSize; // (K) the LUT size (determined by the input network) + int nVarsMax; // (V) the largest number of variables: V = N * (K-1) + 1 +}; + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// ITERATORS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +/*=== lpkCore.c ========================================================*/ +extern int Lpk_Resynthesize( Abc_Ntk_t * pNtk, Lpk_Par_t * pPars ); + + +#ifdef __cplusplus +} +#endif + +#endif + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + diff --git a/src/opt/lpk/lpkAbcDec.c b/src/opt/lpk/lpkAbcDec.c new file mode 100644 index 00000000..aa2d4bc0 --- /dev/null +++ b/src/opt/lpk/lpkAbcDec.c @@ -0,0 +1,290 @@ +/**CFile**************************************************************** + + FileName [lpkAbcDec.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Fast Boolean matching for LUT structures.] + + Synopsis [The new core procedure.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - April 28, 2007.] + + Revision [$Id: lpkAbcDec.c,v 1.00 2007/04/28 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "lpkInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Implements the function.] + + Description [Returns the node implementing this function.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Abc_Obj_t * Lpk_ImplementFun( Lpk_Man_t * pMan, Abc_Ntk_t * pNtk, Vec_Ptr_t * vLeaves, Lpk_Fun_t * p ) +{ + extern Hop_Obj_t * Kit_TruthToHop( Hop_Man_t * pMan, unsigned * pTruth, int nVars, Vec_Int_t * vMemory ); + unsigned * pTruth; + Abc_Obj_t * pObjNew; + int i; + if ( p->fMark ) + pMan->nMuxes++; + else + pMan->nDsds++; + // create the new node + pObjNew = Abc_NtkCreateNode( pNtk ); + for ( i = 0; i < (int)p->nVars; i++ ) + Abc_ObjAddFanin( pObjNew, Abc_ObjRegular(Vec_PtrEntry(vLeaves, p->pFanins[i])) ); + Abc_ObjSetLevel( pObjNew, Abc_ObjLevelNew(pObjNew) ); + // assign the node's function + pTruth = Lpk_FunTruth(p, 0); + if ( p->nVars == 0 ) + { + pObjNew->pData = Hop_NotCond( Hop_ManConst1(pNtk->pManFunc), !(pTruth[0] & 1) ); + return pObjNew; + } + if ( p->nVars == 1 ) + { + pObjNew->pData = Hop_NotCond( Hop_ManPi(pNtk->pManFunc, 0), (pTruth[0] & 1) ); + return pObjNew; + } + // create the logic function + pObjNew->pData = Kit_TruthToHop( pNtk->pManFunc, pTruth, p->nVars, NULL ); + return pObjNew; +} + +/**Function************************************************************* + + Synopsis [Implements the function.] + + Description [Returns the node implementing this function.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Abc_Obj_t * Lpk_Implement_rec( Lpk_Man_t * pMan, Abc_Ntk_t * pNtk, Vec_Ptr_t * vLeaves, Lpk_Fun_t * pFun ) +{ + Abc_Obj_t * pFanin, * pRes; + int i; + // prepare the leaves of the function + for ( i = 0; i < (int)pFun->nVars; i++ ) + { + pFanin = Vec_PtrEntry( vLeaves, pFun->pFanins[i] ); + if ( !Abc_ObjIsComplement(pFanin) ) + Lpk_Implement_rec( pMan, pNtk, vLeaves, (Lpk_Fun_t *)pFanin ); + pFanin = Vec_PtrEntry( vLeaves, pFun->pFanins[i] ); + assert( Abc_ObjIsComplement(pFanin) ); + } + // construct the function + pRes = Lpk_ImplementFun( pMan, pNtk, vLeaves, pFun ); + // replace the function + Vec_PtrWriteEntry( vLeaves, pFun->Id, Abc_ObjNot(pRes) ); + Lpk_FunFree( pFun ); + return pRes; +} + +/**Function************************************************************* + + Synopsis [Implements the function.] + + Description [Returns the node implementing this function.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Abc_Obj_t * Lpk_Implement( Lpk_Man_t * pMan, Abc_Ntk_t * pNtk, Vec_Ptr_t * vLeaves, int nLeavesOld ) +{ + Abc_Obj_t * pFanin, * pRes; + int i; + assert( nLeavesOld < Vec_PtrSize(vLeaves) ); + // mark implemented nodes + Vec_PtrForEachEntryStop( vLeaves, pFanin, i, nLeavesOld ) + Vec_PtrWriteEntry( vLeaves, i, Abc_ObjNot(pFanin) ); + // recursively construct starting from the first entry + pRes = Lpk_Implement_rec( pMan, pNtk, vLeaves, Vec_PtrEntry( vLeaves, nLeavesOld ) ); + Vec_PtrShrink( vLeaves, nLeavesOld ); + return pRes; +} + +/**Function************************************************************* + + Synopsis [Decomposes the function using recursive MUX decomposition.] + + Description [Returns the ID of the top-most decomposition node + implementing this function, or 0 if there is no decomposition satisfying + the constraints on area and delay.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Lpk_Decompose_rec( Lpk_Man_t * pMan, Lpk_Fun_t * p ) +{ + static Lpk_Res_t Res0, * pRes0 = &Res0; + Lpk_Res_t * pResMux, * pResDsd; + Lpk_Fun_t * p2; + int clk; + + // is only called for non-trivial blocks + assert( p->nLutK >= 3 && p->nLutK <= 6 ); + assert( p->nVars > p->nLutK ); + // skip if area bound is exceeded + if ( Lpk_LutNumLuts(p->nVars, p->nLutK) > (int)p->nAreaLim ) + return 0; + // skip if delay bound is exceeded + if ( Lpk_SuppDelay(p->uSupp, p->pDelays) > (int)p->nDelayLim ) + return 0; + + // compute supports if needed + if ( !p->fSupports ) + Lpk_FunComputeCofSupps( p ); + + // check DSD decomposition +clk = clock(); + pResDsd = Lpk_DsdAnalize( pMan, p, pMan->pPars->nVarsShared ); +pMan->timeEvalDsdAn += clock() - clk; + if ( pResDsd && (pResDsd->nBSVars == (int)p->nLutK || pResDsd->nBSVars == (int)p->nLutK - 1) && + pResDsd->AreaEst <= (int)p->nAreaLim && pResDsd->DelayEst <= (int)p->nDelayLim ) + { +clk = clock(); + p2 = Lpk_DsdSplit( pMan, p, pResDsd->pCofVars, pResDsd->nCofVars, pResDsd->BSVars ); +pMan->timeEvalDsdSp += clock() - clk; + assert( p2->nVars <= (int)p->nLutK ); + if ( p->nVars > p->nLutK && !Lpk_Decompose_rec( pMan, p ) ) + return 0; + return 1; + } + + // check MUX decomposition +clk = clock(); + pResMux = Lpk_MuxAnalize( pMan, p ); +pMan->timeEvalMuxAn += clock() - clk; +// pResMux = NULL; + assert( !pResMux || (pResMux->DelayEst <= (int)p->nDelayLim && pResMux->AreaEst <= (int)p->nAreaLim) ); + // accept MUX decomposition if it is "good" + if ( pResMux && pResMux->nSuppSizeS <= (int)p->nLutK && pResMux->nSuppSizeL <= (int)p->nLutK ) + pResDsd = NULL; + else if ( pResMux && pResDsd ) + { + // compare two decompositions + if ( pResMux->AreaEst < pResDsd->AreaEst || + (pResMux->AreaEst == pResDsd->AreaEst && pResMux->nSuppSizeL < pResDsd->nSuppSizeL) || + (pResMux->AreaEst == pResDsd->AreaEst && pResMux->nSuppSizeL == pResDsd->nSuppSizeL && pResMux->DelayEst < pResDsd->DelayEst) ) + pResDsd = NULL; + else + pResMux = NULL; + } + assert( pResMux == NULL || pResDsd == NULL ); + if ( pResMux ) + { +clk = clock(); + p2 = Lpk_MuxSplit( pMan, p, pResMux->Variable, pResMux->Polarity ); +pMan->timeEvalMuxSp += clock() - clk; + if ( p2->nVars > p->nLutK && !Lpk_Decompose_rec( pMan, p2 ) ) + return 0; + if ( p->nVars > p->nLutK && !Lpk_Decompose_rec( pMan, p ) ) + return 0; + return 1; + } + if ( pResDsd ) + { +clk = clock(); + p2 = Lpk_DsdSplit( pMan, p, pResDsd->pCofVars, pResDsd->nCofVars, pResDsd->BSVars ); +pMan->timeEvalDsdSp += clock() - clk; + assert( p2->nVars <= (int)p->nLutK ); + if ( p->nVars > p->nLutK && !Lpk_Decompose_rec( pMan, p ) ) + return 0; + return 1; + } + return 0; +} + +/**Function************************************************************* + + Synopsis [Removes decomposed nodes from the array of fanins.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Lpk_DecomposeClean( Vec_Ptr_t * vLeaves, int nLeavesOld ) +{ + Lpk_Fun_t * pFunc; + int i; + Vec_PtrForEachEntryStart( vLeaves, pFunc, i, nLeavesOld ) + Lpk_FunFree( pFunc ); + Vec_PtrShrink( vLeaves, nLeavesOld ); +} + +/**Function************************************************************* + + Synopsis [Decomposes the function using recursive MUX decomposition.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Abc_Obj_t * Lpk_Decompose( Lpk_Man_t * p, Abc_Ntk_t * pNtk, Vec_Ptr_t * vLeaves, unsigned * pTruth, unsigned * puSupps, int nLutK, int AreaLim, int DelayLim ) +{ + Lpk_Fun_t * pFun; + Abc_Obj_t * pObjNew = NULL; + int nLeaves = Vec_PtrSize( vLeaves ); + pFun = Lpk_FunCreate( pNtk, vLeaves, pTruth, nLutK, AreaLim, DelayLim ); + if ( puSupps[0] || puSupps[1] ) + { +/* + int i; + Lpk_FunComputeCofSupps( pFun ); + for ( i = 0; i < nLeaves; i++ ) + { + assert( pFun->puSupps[2*i+0] == puSupps[2*i+0] ); + assert( pFun->puSupps[2*i+1] == puSupps[2*i+1] ); + } +*/ + memcpy( pFun->puSupps, puSupps, sizeof(unsigned) * 2 * nLeaves ); + pFun->fSupports = 1; + } + Lpk_FunSuppMinimize( pFun ); + if ( pFun->nVars <= pFun->nLutK ) + pObjNew = Lpk_ImplementFun( p, pNtk, vLeaves, pFun ); + else if ( Lpk_Decompose_rec(p, pFun) ) + pObjNew = Lpk_Implement( p, pNtk, vLeaves, nLeaves ); + Lpk_DecomposeClean( vLeaves, nLeaves ); + return pObjNew; +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/lpk/lpkAbcDsd.c b/src/opt/lpk/lpkAbcDsd.c new file mode 100644 index 00000000..f4095914 --- /dev/null +++ b/src/opt/lpk/lpkAbcDsd.c @@ -0,0 +1,603 @@ +/**CFile**************************************************************** + + FileName [lpkAbcDsd.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Fast Boolean matching for LUT structures.] + + Synopsis [LUT-decomposition based on recursive DSD.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - April 28, 2007.] + + Revision [$Id: lpkAbcDsd.c,v 1.00 2007/04/28 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "lpkInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Cofactors TTs w.r.t. all vars and finds the best var.] + + Description [The best variable is the variable with the minimum + sum total of the support sizes of all truth tables. This procedure + computes and returns cofactors w.r.t. the best variable.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Lpk_FunComputeMinSuppSizeVar( Lpk_Fun_t * p, unsigned ** ppTruths, int nTruths, unsigned ** ppCofs, unsigned uNonDecSupp ) +{ + int i, Var, VarBest, nSuppSize0, nSuppSize1, nSuppTotalMin, nSuppTotalCur, nSuppMaxMin, nSuppMaxCur; + assert( nTruths > 0 ); + VarBest = -1; + Lpk_SuppForEachVar( p->uSupp, Var ) + { + if ( (uNonDecSupp & (1 << Var)) == 0 ) + continue; + nSuppMaxCur = 0; + nSuppTotalCur = 0; + for ( i = 0; i < nTruths; i++ ) + { + if ( nTruths == 1 ) + { + nSuppSize0 = Kit_WordCountOnes( p->puSupps[2*Var+0] ); + nSuppSize1 = Kit_WordCountOnes( p->puSupps[2*Var+1] ); + } + else + { + Kit_TruthCofactor0New( ppCofs[2*i+0], ppTruths[i], p->nVars, Var ); + Kit_TruthCofactor1New( ppCofs[2*i+1], ppTruths[i], p->nVars, Var ); + nSuppSize0 = Kit_TruthSupportSize( ppCofs[2*i+0], p->nVars ); + nSuppSize1 = Kit_TruthSupportSize( ppCofs[2*i+1], p->nVars ); + } + nSuppMaxCur = ABC_MAX( nSuppMaxCur, nSuppSize0 ); + nSuppMaxCur = ABC_MAX( nSuppMaxCur, nSuppSize1 ); + nSuppTotalCur += nSuppSize0 + nSuppSize1; + } + if ( VarBest == -1 || nSuppMaxMin > nSuppMaxCur || + (nSuppMaxMin == nSuppMaxCur && nSuppTotalMin > nSuppTotalCur) ) + { + VarBest = Var; + nSuppMaxMin = nSuppMaxCur; + nSuppTotalMin = nSuppTotalCur; + } + } + // recompute cofactors for the best var + for ( i = 0; i < nTruths; i++ ) + { + Kit_TruthCofactor0New( ppCofs[2*i+0], ppTruths[i], p->nVars, VarBest ); + Kit_TruthCofactor1New( ppCofs[2*i+1], ppTruths[i], p->nVars, VarBest ); + } + return VarBest; +} + +/**Function************************************************************* + + Synopsis [Recursively computes decomposable subsets.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned Lpk_ComputeBoundSets_rec( Kit_DsdNtk_t * p, int iLit, Vec_Int_t * vSets, int nSizeMax ) +{ + unsigned i, iLitFanin, uSupport, uSuppCur; + Kit_DsdObj_t * pObj; + // consider the case of simple gate + pObj = Kit_DsdNtkObj( p, Kit_DsdLit2Var(iLit) ); + if ( pObj == NULL ) + return (1 << Kit_DsdLit2Var(iLit)); + if ( pObj->Type == KIT_DSD_AND || pObj->Type == KIT_DSD_XOR ) + { + unsigned uSupps[16], Limit, s; + uSupport = 0; + Kit_DsdObjForEachFanin( p, pObj, iLitFanin, i ) + { + uSupps[i] = Lpk_ComputeBoundSets_rec( p, iLitFanin, vSets, nSizeMax ); + uSupport |= uSupps[i]; + } + // create all subsets, except empty and full + Limit = (1 << pObj->nFans) - 1; + for ( s = 1; s < Limit; s++ ) + { + uSuppCur = 0; + for ( i = 0; i < pObj->nFans; i++ ) + if ( s & (1 << i) ) + uSuppCur |= uSupps[i]; + if ( Kit_WordCountOnes(uSuppCur) <= nSizeMax ) + Vec_IntPush( vSets, uSuppCur ); + } + return uSupport; + } + assert( pObj->Type == KIT_DSD_PRIME ); + // get the cumulative support of all fanins + uSupport = 0; + Kit_DsdObjForEachFanin( p, pObj, iLitFanin, i ) + { + uSuppCur = Lpk_ComputeBoundSets_rec( p, iLitFanin, vSets, nSizeMax ); + uSupport |= uSuppCur; + if ( Kit_WordCountOnes(uSuppCur) <= nSizeMax ) + Vec_IntPush( vSets, uSuppCur ); + } + return uSupport; +} + +/**Function************************************************************* + + Synopsis [Computes the set of subsets of decomposable variables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Int_t * Lpk_ComputeBoundSets( Kit_DsdNtk_t * p, int nSizeMax ) +{ + Vec_Int_t * vSets; + unsigned uSupport, Entry; + int Number, i; + assert( p->nVars <= 16 ); + vSets = Vec_IntAlloc( 100 ); + Vec_IntPush( vSets, 0 ); + if ( Kit_DsdNtkRoot(p)->Type == KIT_DSD_CONST1 ) + return vSets; + if ( Kit_DsdNtkRoot(p)->Type == KIT_DSD_VAR ) + { + uSupport = ( 1 << Kit_DsdLit2Var(Kit_DsdNtkRoot(p)->pFans[0]) ); + if ( Kit_WordCountOnes(uSupport) <= nSizeMax ) + Vec_IntPush( vSets, uSupport ); + return vSets; + } + uSupport = Lpk_ComputeBoundSets_rec( p, p->Root, vSets, nSizeMax ); + assert( (uSupport & 0xFFFF0000) == 0 ); + // add the total support of the network + if ( Kit_WordCountOnes(uSupport) <= nSizeMax ) + Vec_IntPush( vSets, uSupport ); + // set the remaining variables + Vec_IntForEachEntry( vSets, Number, i ) + { + Entry = Number; + Vec_IntWriteEntry( vSets, i, Entry | ((uSupport & ~Entry) << 16) ); + } + return vSets; +} + +/**Function************************************************************* + + Synopsis [Prints the sets of subsets.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static void Lpk_PrintSetOne( int uSupport ) +{ + unsigned k; + for ( k = 0; k < 16; k++ ) + if ( uSupport & (1<> 16)) ) + continue; + if ( Kit_WordCountOnes(Entry & 0xffff) <= nSizeMax ) + Vec_IntPush( vSets, Entry ); + } + return vSets; +} + +/**Function************************************************************* + + Synopsis [Performs DSD-based decomposition of the function.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Lpk_FunCompareBoundSets( Lpk_Fun_t * p, Vec_Int_t * vBSets, int nCofDepth, unsigned uNonDecSupp, unsigned uLateArrSupp, Lpk_Res_t * pRes ) +{ + int fVerbose = 0; + unsigned uBoundSet; + int i, nVarsBS, nVarsRem, Delay, Area; + + // compare the resulting boundsets + memset( pRes, 0, sizeof(Lpk_Res_t) ); + Vec_IntForEachEntry( vBSets, uBoundSet, i ) + { + if ( (uBoundSet & 0xFFFF) == 0 ) // skip empty boundset + continue; + if ( (uBoundSet & uNonDecSupp) == 0 ) // skip those boundsets that are not in the domain of interest + continue; + if ( (uBoundSet & uLateArrSupp) ) // skip those boundsets that are late arriving + continue; +if ( fVerbose ) +Lpk_PrintSetOne( uBoundSet ); + assert( (uBoundSet & (uBoundSet >> 16)) == 0 ); + nVarsBS = Kit_WordCountOnes( uBoundSet & 0xFFFF ); + if ( nVarsBS == 1 ) + continue; + assert( nVarsBS <= (int)p->nLutK - nCofDepth ); + nVarsRem = p->nVars - nVarsBS + 1; + Area = 1 + Lpk_LutNumLuts( nVarsRem, p->nLutK ); + Delay = 1 + Lpk_SuppDelay( uBoundSet & 0xFFFF, p->pDelays ); +if ( fVerbose ) +printf( "area = %d limit = %d delay = %d limit = %d\n", Area, (int)p->nAreaLim, Delay, (int)p->nDelayLim ); + if ( Area > (int)p->nAreaLim || Delay > (int)p->nDelayLim ) + continue; + if ( pRes->BSVars == 0 || pRes->nSuppSizeL > nVarsRem || (pRes->nSuppSizeL == nVarsRem && pRes->DelayEst > Delay) ) + { + pRes->nBSVars = nVarsBS; + pRes->BSVars = (uBoundSet & 0xFFFF); + pRes->nSuppSizeS = nVarsBS + nCofDepth; + pRes->nSuppSizeL = nVarsRem; + pRes->DelayEst = Delay; + pRes->AreaEst = Area; + } + } +if ( fVerbose ) +{ +if ( pRes->BSVars ) +{ +printf( "Found bound set " ); +Lpk_PrintSetOne( pRes->BSVars ); +printf( "\n" ); +} +else +printf( "Did not find boundsets.\n" ); +printf( "\n" ); +} + if ( pRes->BSVars ) + { + assert( pRes->DelayEst <= (int)p->nDelayLim ); + assert( pRes->AreaEst <= (int)p->nAreaLim ); + } +} + + +/**Function************************************************************* + + Synopsis [Finds late arriving inputs, which cannot be in the bound set.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned Lpk_DsdLateArriving( Lpk_Fun_t * p ) +{ + unsigned i, uLateArrSupp = 0; + Lpk_SuppForEachVar( p->uSupp, i ) + if ( p->pDelays[i] > (int)p->nDelayLim - 2 ) + uLateArrSupp |= (1 << i); + return uLateArrSupp; +} + +/**Function************************************************************* + + Synopsis [Performs DSD-based decomposition of the function.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Lpk_DsdAnalizeOne( Lpk_Fun_t * p, unsigned * ppTruths[5][16], Kit_DsdNtk_t * pNtks[], char pCofVars[], int nCofDepth, Lpk_Res_t * pRes ) +{ + int fVerbose = 0; + Vec_Int_t * pvBSets[4][8]; + unsigned uNonDecSupp, uLateArrSupp; + int i, k, nNonDecSize, nNonDecSizeMax; + assert( nCofDepth >= 1 && nCofDepth <= 3 ); + assert( nCofDepth < (int)p->nLutK - 1 ); + assert( p->fSupports ); + + // find the support of the largest non-DSD block + nNonDecSizeMax = 0; + uNonDecSupp = p->uSupp; + for ( i = 0; i < (1<<(nCofDepth-1)); i++ ) + { + nNonDecSize = Kit_DsdNonDsdSizeMax( pNtks[i] ); + if ( nNonDecSizeMax < nNonDecSize ) + { + nNonDecSizeMax = nNonDecSize; + uNonDecSupp = Kit_DsdNonDsdSupports( pNtks[i] ); + } + else if ( nNonDecSizeMax == nNonDecSize ) + uNonDecSupp |= Kit_DsdNonDsdSupports( pNtks[i] ); + } + + // remove those variables that cannot be used because of delay constraints + // if variables arrival time is more than p->DelayLim - 2, it cannot be used + uLateArrSupp = Lpk_DsdLateArriving( p ); + if ( (uNonDecSupp & ~uLateArrSupp) == 0 ) + { + memset( pRes, 0, sizeof(Lpk_Res_t) ); + return 0; + } + + // find the next cofactoring variable + pCofVars[nCofDepth-1] = Lpk_FunComputeMinSuppSizeVar( p, ppTruths[nCofDepth-1], 1<<(nCofDepth-1), ppTruths[nCofDepth], uNonDecSupp & ~uLateArrSupp ); + + // derive decomposed networks + for ( i = 0; i < (1<nVars ); +if ( fVerbose ) +Kit_DsdPrint( stdout, pNtks[i] ); + pvBSets[nCofDepth][i] = Lpk_ComputeBoundSets( pNtks[i], p->nLutK - nCofDepth ); // try restricting to those in uNonDecSupp!!! + } + + // derive the set of feasible boundsets + for ( i = nCofDepth - 1; i >= 0; i-- ) + for ( k = 0; k < (1<nLutK - nCofDepth ); + // compare bound-sets + Lpk_FunCompareBoundSets( p, pvBSets[0][0], nCofDepth, uNonDecSupp, uLateArrSupp, pRes ); + // free the bound sets + for ( i = nCofDepth; i >= 0; i-- ) + for ( k = 0; k < (1<BSVars ) + { + pRes->nCofVars = nCofDepth; + for ( i = 0; i < nCofDepth; i++ ) + pRes->pCofVars[i] = pCofVars[i]; + } + return 1; +} + +/**Function************************************************************* + + Synopsis [Performs DSD-based decomposition of the function.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Lpk_Res_t * Lpk_DsdAnalize( Lpk_Man_t * pMan, Lpk_Fun_t * p, int nShared ) +{ + static Lpk_Res_t Res0, * pRes0 = &Res0; + static Lpk_Res_t Res1, * pRes1 = &Res1; + static Lpk_Res_t Res2, * pRes2 = &Res2; + static Lpk_Res_t Res3, * pRes3 = &Res3; + int fUseBackLooking = 1; + Lpk_Res_t * pRes = NULL; + Vec_Int_t * vBSets; + Kit_DsdNtk_t * pNtks[8] = {NULL}; + char pCofVars[5]; + int i; + + assert( p->nLutK >= 3 ); + assert( nShared >= 0 && nShared <= 3 ); + assert( p->uSupp == Kit_BitMask(p->nVars) ); + + // try decomposition without cofactoring + pNtks[0] = Kit_DsdDecomposeExpand( Lpk_FunTruth( p, 0 ), p->nVars ); + if ( pMan->pPars->fVerbose ) + pMan->nBlocks[ Kit_DsdNonDsdSizeMax(pNtks[0]) ]++; + vBSets = Lpk_ComputeBoundSets( pNtks[0], p->nLutK ); + Lpk_FunCompareBoundSets( p, vBSets, 0, 0xFFFF, Lpk_DsdLateArriving(p), pRes0 ); + Vec_IntFree( vBSets ); + + // check the result + if ( pRes0->nBSVars == (int)p->nLutK ) + { pRes = pRes0; goto finish; } + if ( pRes0->nBSVars == (int)p->nLutK - 1 ) + { pRes = pRes0; goto finish; } + if ( nShared == 0 ) + goto finish; + + // prepare storage + Kit_TruthCopy( pMan->ppTruths[0][0], Lpk_FunTruth( p, 0 ), p->nVars ); + + // cofactor 1 time + if ( !Lpk_DsdAnalizeOne( p, pMan->ppTruths, pNtks, pCofVars, 1, pRes1 ) ) + goto finish; + assert( pRes1->nBSVars <= (int)p->nLutK - 1 ); + if ( pRes1->nBSVars == (int)p->nLutK - 1 ) + { pRes = pRes1; goto finish; } + if ( pRes0->nBSVars == (int)p->nLutK - 2 ) + { pRes = pRes0; goto finish; } + if ( pRes1->nBSVars == (int)p->nLutK - 2 ) + { pRes = pRes1; goto finish; } + if ( nShared == 1 ) + goto finish; + + // cofactor 2 times + if ( p->nLutK >= 4 ) + { + if ( !Lpk_DsdAnalizeOne( p, pMan->ppTruths, pNtks, pCofVars, 2, pRes2 ) ) + goto finish; + assert( pRes2->nBSVars <= (int)p->nLutK - 2 ); + if ( pRes2->nBSVars == (int)p->nLutK - 2 ) + { pRes = pRes2; goto finish; } + if ( fUseBackLooking ) + { + if ( pRes0->nBSVars == (int)p->nLutK - 3 ) + { pRes = pRes0; goto finish; } + if ( pRes1->nBSVars == (int)p->nLutK - 3 ) + { pRes = pRes1; goto finish; } + } + if ( pRes2->nBSVars == (int)p->nLutK - 3 ) + { pRes = pRes2; goto finish; } + if ( nShared == 2 ) + goto finish; + assert( nShared == 3 ); + } + + // cofactor 3 times + if ( p->nLutK >= 5 ) + { + if ( !Lpk_DsdAnalizeOne( p, pMan->ppTruths, pNtks, pCofVars, 3, pRes3 ) ) + goto finish; + assert( pRes3->nBSVars <= (int)p->nLutK - 3 ); + if ( pRes3->nBSVars == (int)p->nLutK - 3 ) + { pRes = pRes3; goto finish; } + if ( fUseBackLooking ) + { + if ( pRes0->nBSVars == (int)p->nLutK - 4 ) + { pRes = pRes0; goto finish; } + if ( pRes1->nBSVars == (int)p->nLutK - 4 ) + { pRes = pRes1; goto finish; } + if ( pRes2->nBSVars == (int)p->nLutK - 4 ) + { pRes = pRes2; goto finish; } + } + if ( pRes3->nBSVars == (int)p->nLutK - 4 ) + { pRes = pRes3; goto finish; } + } + +finish: + // free the networks + for ( i = 0; i < (1<ppTruths[0][0], Lpk_FunTruth(p, 0), p->nVars ); + // get the vacuous variable + iVacVar = Kit_WordFindFirstBit( uBoundSet ); + // compute the cofactors + for ( i = 0; i < nCofVars; i++ ) + for ( k = 0; k < (1<ppTruths[i+1][2*k+0], pMan->ppTruths[i][k], p->nVars, pCofVars[i] ); + Kit_TruthCofactor1New( pMan->ppTruths[i+1][2*k+1], pMan->ppTruths[i][k], p->nVars, pCofVars[i] ); + } + // decompose each cofactor w.r.t. the bound set + nCofs = (1<ppTruths[nCofVars][k], p->nVars ); + Kit_DsdTruthPartialTwo( pMan->pDsdMan, pNtkDec, uBoundSet, iVacVar, pMan->ppTruths[nCofVars+1][k], pMan->ppTruths[nCofVars+1][nCofs+k] ); + Kit_DsdNtkFree( pNtkDec ); + } + // compute the composition/decomposition functions (they will be in pMan->ppTruths[1][0]/pMan->ppTruths[1][1]) + for ( i = nCofVars; i >= 1; i-- ) + for ( k = 0; k < (1<ppTruths[i][k], pMan->ppTruths[i+1][2*k+0], pMan->ppTruths[i+1][2*k+1], p->nVars, pCofVars[i-1] ); + + // derive the new component (decomposition function) + pNew = Lpk_FunDup( p, pMan->ppTruths[1][1] ); + // update the old component (composition function) + Kit_TruthCopy( Lpk_FunTruth(p, 0), pMan->ppTruths[1][0], p->nVars ); + p->uSupp = Kit_TruthSupport( Lpk_FunTruth(p, 0), p->nVars ); + p->pFanins[iVacVar] = pNew->Id; + p->pDelays[iVacVar] = Lpk_SuppDelay( pNew->uSupp, pNew->pDelays ); + // support minimize both + p->fSupports = 0; + Lpk_FunSuppMinimize( p ); + Lpk_FunSuppMinimize( pNew ); + // update delay and area requirements + pNew->nDelayLim = p->pDelays[iVacVar]; + pNew->nAreaLim = 1; + p->nAreaLim = p->nAreaLim - 1; + return pNew; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/lpk/lpkAbcMux.c b/src/opt/lpk/lpkAbcMux.c new file mode 100644 index 00000000..d6f579ee --- /dev/null +++ b/src/opt/lpk/lpkAbcMux.c @@ -0,0 +1,235 @@ +/**CFile**************************************************************** + + FileName [lpkAbcMux.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Fast Boolean matching for LUT structures.] + + Synopsis [LUT-decomposition based on recursive MUX decomposition.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - April 28, 2007.] + + Revision [$Id: lpkAbcMux.c,v 1.00 2007/04/28 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "lpkInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Checks the possibility of MUX decomposition.] + + Description [Returns the best variable to use for MUX decomposition.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Lpk_Res_t * Lpk_MuxAnalize( Lpk_Man_t * pMan, Lpk_Fun_t * p ) +{ + static Lpk_Res_t Res, * pRes = &Res; + int nSuppSize0, nSuppSize1, nSuppSizeS, nSuppSizeL; + int Var, Area, Polarity, Delay, Delay0, Delay1, DelayA, DelayB; + memset( pRes, 0, sizeof(Lpk_Res_t) ); + assert( p->uSupp == Kit_BitMask(p->nVars) ); + assert( p->fSupports ); + // derive the delay and area after MUX-decomp with each var - and find the best var + pRes->Variable = -1; + Lpk_SuppForEachVar( p->uSupp, Var ) + { + nSuppSize0 = Kit_WordCountOnes(p->puSupps[2*Var+0]); + nSuppSize1 = Kit_WordCountOnes(p->puSupps[2*Var+1]); + assert( nSuppSize0 < (int)p->nVars ); + assert( nSuppSize1 < (int)p->nVars ); + if ( nSuppSize0 < 1 || nSuppSize1 < 1 ) + continue; +//printf( "%d %d ", nSuppSize0, nSuppSize1 ); + if ( nSuppSize0 <= (int)p->nLutK - 2 && nSuppSize1 <= (int)p->nLutK - 2 ) + { + // include cof var into 0-block + DelayA = Lpk_SuppDelay( p->puSupps[2*Var+0] | (1<pDelays ); + DelayB = Lpk_SuppDelay( p->puSupps[2*Var+1] , p->pDelays ); + Delay0 = ABC_MAX( DelayA, DelayB + 1 ); + // include cof var into 1-block + DelayA = Lpk_SuppDelay( p->puSupps[2*Var+1] | (1<pDelays ); + DelayB = Lpk_SuppDelay( p->puSupps[2*Var+0] , p->pDelays ); + Delay1 = ABC_MAX( DelayA, DelayB + 1 ); + // get the best delay + Delay = ABC_MIN( Delay0, Delay1 ); + Area = 2; + Polarity = (int)(Delay == Delay1); + } + else if ( nSuppSize0 <= (int)p->nLutK - 2 ) + { + DelayA = Lpk_SuppDelay( p->puSupps[2*Var+0] | (1<pDelays ); + DelayB = Lpk_SuppDelay( p->puSupps[2*Var+1] , p->pDelays ); + Delay = ABC_MAX( DelayA, DelayB + 1 ); + Area = 1 + Lpk_LutNumLuts( nSuppSize1, p->nLutK ); + Polarity = 0; + } + else if ( nSuppSize1 <= (int)p->nLutK - 2 ) + { + DelayA = Lpk_SuppDelay( p->puSupps[2*Var+1] | (1<pDelays ); + DelayB = Lpk_SuppDelay( p->puSupps[2*Var+0] , p->pDelays ); + Delay = ABC_MAX( DelayA, DelayB + 1 ); + Area = 1 + Lpk_LutNumLuts( nSuppSize0, p->nLutK ); + Polarity = 1; + } + else if ( nSuppSize0 <= (int)p->nLutK ) + { + DelayA = Lpk_SuppDelay( p->puSupps[2*Var+1] | (1<pDelays ); + DelayB = Lpk_SuppDelay( p->puSupps[2*Var+0] , p->pDelays ); + Delay = ABC_MAX( DelayA, DelayB + 1 ); + Area = 1 + Lpk_LutNumLuts( nSuppSize1+2, p->nLutK ); + Polarity = 1; + } + else if ( nSuppSize1 <= (int)p->nLutK ) + { + DelayA = Lpk_SuppDelay( p->puSupps[2*Var+0] | (1<pDelays ); + DelayB = Lpk_SuppDelay( p->puSupps[2*Var+1] , p->pDelays ); + Delay = ABC_MAX( DelayA, DelayB + 1 ); + Area = 1 + Lpk_LutNumLuts( nSuppSize0+2, p->nLutK ); + Polarity = 0; + } + else + { + // include cof var into 0-block + DelayA = Lpk_SuppDelay( p->puSupps[2*Var+0] | (1<pDelays ); + DelayB = Lpk_SuppDelay( p->puSupps[2*Var+1] , p->pDelays ); + Delay0 = ABC_MAX( DelayA, DelayB + 1 ); + // include cof var into 1-block + DelayA = Lpk_SuppDelay( p->puSupps[2*Var+1] | (1<pDelays ); + DelayB = Lpk_SuppDelay( p->puSupps[2*Var+0] , p->pDelays ); + Delay1 = ABC_MAX( DelayA, DelayB + 1 ); + // get the best delay + Delay = ABC_MIN( Delay0, Delay1 ); + if ( Delay == Delay0 ) + Area = Lpk_LutNumLuts( nSuppSize0+2, p->nLutK ) + Lpk_LutNumLuts( nSuppSize1, p->nLutK ); + else + Area = Lpk_LutNumLuts( nSuppSize1+2, p->nLutK ) + Lpk_LutNumLuts( nSuppSize0, p->nLutK ); + Polarity = (int)(Delay == Delay1); + } + // find the best variable + if ( Delay > (int)p->nDelayLim ) + continue; + if ( Area > (int)p->nAreaLim ) + continue; + nSuppSizeS = ABC_MIN( nSuppSize0 + 2 *!Polarity, nSuppSize1 + 2 * Polarity ); + nSuppSizeL = ABC_MAX( nSuppSize0 + 2 *!Polarity, nSuppSize1 + 2 * Polarity ); + if ( nSuppSizeL > (int)p->nVars ) + continue; + if ( pRes->Variable == -1 || pRes->AreaEst > Area || + (pRes->AreaEst == Area && pRes->nSuppSizeS + pRes->nSuppSizeL > nSuppSizeS + nSuppSizeL) || + (pRes->AreaEst == Area && pRes->nSuppSizeS + pRes->nSuppSizeL == nSuppSizeS + nSuppSizeL && pRes->DelayEst > Delay) ) + { + pRes->Variable = Var; + pRes->Polarity = Polarity; + pRes->AreaEst = Area; + pRes->DelayEst = Delay; + pRes->nSuppSizeS = nSuppSizeS; + pRes->nSuppSizeL = nSuppSizeL; + } + } + return pRes->Variable == -1 ? NULL : pRes; +} + +/**Function************************************************************* + + Synopsis [Transforms the function decomposed by the MUX decomposition.] + + Description [Returns the best variable to use for MUX decomposition.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Lpk_Fun_t * Lpk_MuxSplit( Lpk_Man_t * pMan, Lpk_Fun_t * p, int Var, int Pol ) +{ + Lpk_Fun_t * pNew; + unsigned * pTruth = Lpk_FunTruth( p, 0 ); + unsigned * pTruth0 = Lpk_FunTruth( p, 1 ); + unsigned * pTruth1 = Lpk_FunTruth( p, 2 ); +// unsigned uSupp; + int iVarVac; + assert( Var >= 0 && Var < (int)p->nVars ); + assert( p->nAreaLim >= 2 ); + assert( p->uSupp == Kit_BitMask(p->nVars) ); + Kit_TruthCofactor0New( pTruth0, pTruth, p->nVars, Var ); + Kit_TruthCofactor1New( pTruth1, pTruth, p->nVars, Var ); +/* +uSupp = Kit_TruthSupport( pTruth, p->nVars ); +Extra_PrintBinary( stdout, &uSupp, 16 ); printf( "\n" ); +uSupp = Kit_TruthSupport( pTruth0, p->nVars ); +Extra_PrintBinary( stdout, &uSupp, 16 ); printf( "\n" ); +uSupp = Kit_TruthSupport( pTruth1, p->nVars ); +Extra_PrintBinary( stdout, &uSupp, 16 ); printf( "\n\n" ); +*/ + // derive the new component + pNew = Lpk_FunDup( p, Pol ? pTruth0 : pTruth1 ); + // update the support of the old component + p->uSupp = Kit_TruthSupport( Pol ? pTruth1 : pTruth0, p->nVars ); + p->uSupp |= (1 << Var); + // update the truth table of the old component + iVarVac = Kit_WordFindFirstBit( ~p->uSupp ); + assert( iVarVac < (int)p->nVars ); + p->uSupp |= (1 << iVarVac); + Kit_TruthIthVar( pTruth, p->nVars, iVarVac ); + if ( Pol ) + Kit_TruthMuxVar( pTruth, pTruth, pTruth1, p->nVars, Var ); + else + Kit_TruthMuxVar( pTruth, pTruth0, pTruth, p->nVars, Var ); + assert( p->uSupp == Kit_TruthSupport(pTruth, p->nVars) ); + // set the decomposed variable + p->pFanins[iVarVac] = pNew->Id; + p->pDelays[iVarVac] = p->nDelayLim - 1; + // support minimize both + p->fSupports = 0; + Lpk_FunSuppMinimize( p ); + Lpk_FunSuppMinimize( pNew ); + // update delay and area requirements + pNew->nDelayLim = p->nDelayLim - 1; + if ( pNew->nVars <= pNew->nLutK ) + { + pNew->nAreaLim = 1; + p->nAreaLim = p->nAreaLim - 1; + } + else if ( p->nVars <= p->nLutK ) + { + pNew->nAreaLim = p->nAreaLim - 1; + p->nAreaLim = 1; + } + else if ( p->nVars < pNew->nVars ) + { + pNew->nAreaLim = p->nAreaLim / 2 + p->nAreaLim % 2; + p->nAreaLim = p->nAreaLim / 2 - p->nAreaLim % 2; + } + else // if ( pNew->nVars < p->nVars ) + { + pNew->nAreaLim = p->nAreaLim / 2 - p->nAreaLim % 2; + p->nAreaLim = p->nAreaLim / 2 + p->nAreaLim % 2; + } + pNew->fMark = 1; + return pNew; +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/lpk/lpkAbcUtil.c b/src/opt/lpk/lpkAbcUtil.c new file mode 100644 index 00000000..3f917ce2 --- /dev/null +++ b/src/opt/lpk/lpkAbcUtil.c @@ -0,0 +1,244 @@ +/**CFile**************************************************************** + + FileName [lpkAbcUtil.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Fast Boolean matching for LUT structures.] + + Synopsis [Procedures working on decomposed functions.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - April 28, 2007.] + + Revision [$Id: lpkAbcUtil.c,v 1.00 2007/04/28 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "lpkInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Allocates the function.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Lpk_Fun_t * Lpk_FunAlloc( int nVars ) +{ + Lpk_Fun_t * p; + p = (Lpk_Fun_t *)malloc( sizeof(Lpk_Fun_t) + sizeof(unsigned) * Kit_TruthWordNum(nVars) * 3 ); + memset( p, 0, sizeof(Lpk_Fun_t) ); + return p; +} + +/**Function************************************************************* + + Synopsis [Deletes the function] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Lpk_FunFree( Lpk_Fun_t * p ) +{ + free( p ); +} + +/**Function************************************************************* + + Synopsis [Creates the starting function.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Lpk_Fun_t * Lpk_FunCreate( Abc_Ntk_t * pNtk, Vec_Ptr_t * vLeaves, unsigned * pTruth, int nLutK, int AreaLim, int DelayLim ) +{ + Lpk_Fun_t * p; + Abc_Obj_t * pNode; + int i; + p = Lpk_FunAlloc( Vec_PtrSize(vLeaves) ); + p->Id = Vec_PtrSize(vLeaves); + p->vNodes = vLeaves; + p->nVars = Vec_PtrSize(vLeaves); + p->nLutK = nLutK; + p->nAreaLim = AreaLim; + p->nDelayLim = DelayLim; + p->uSupp = Kit_TruthSupport( pTruth, p->nVars ); + Kit_TruthCopy( Lpk_FunTruth(p,0), pTruth, p->nVars ); + Vec_PtrForEachEntry( vLeaves, pNode, i ) + { + p->pFanins[i] = i; + p->pDelays[i] = pNode->Level; + } + Vec_PtrPush( p->vNodes, p ); + return p; +} + +/**Function************************************************************* + + Synopsis [Creates the new function with the given truth table.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Lpk_Fun_t * Lpk_FunDup( Lpk_Fun_t * p, unsigned * pTruth ) +{ + Lpk_Fun_t * pNew; + pNew = Lpk_FunAlloc( p->nVars ); + pNew->Id = Vec_PtrSize(p->vNodes); + pNew->vNodes = p->vNodes; + pNew->nVars = p->nVars; + pNew->nLutK = p->nLutK; + pNew->nAreaLim = p->nAreaLim; + pNew->nDelayLim = p->nDelayLim; + pNew->uSupp = Kit_TruthSupport( pTruth, p->nVars ); + Kit_TruthCopy( Lpk_FunTruth(pNew,0), pTruth, p->nVars ); + memcpy( pNew->pFanins, p->pFanins, 16 ); + memcpy( pNew->pDelays, p->pDelays, 16 ); + Vec_PtrPush( p->vNodes, pNew ); + return pNew; +} + +/**Function************************************************************* + + Synopsis [Minimizes support of the function.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Lpk_FunSuppMinimize( Lpk_Fun_t * p ) +{ + int i, k, nVarsNew; + // compress the truth table + if ( p->uSupp == Kit_BitMask(p->nVars) ) + return 0; + // invalidate support info + p->fSupports = 0; +//Extra_PrintBinary( stdout, &p->uSupp, p->nVars ); printf( "\n" ); + // minimize support + nVarsNew = Kit_WordCountOnes(p->uSupp); + Kit_TruthShrink( Lpk_FunTruth(p, 1), Lpk_FunTruth(p, 0), nVarsNew, p->nVars, p->uSupp, 1 ); + k = 0; + Lpk_SuppForEachVar( p->uSupp, i ) + { + p->pFanins[k] = p->pFanins[i]; + p->pDelays[k] = p->pDelays[i]; +/* + if ( p->fSupports ) + { + p->puSupps[2*k+0] = p->puSupps[2*i+0]; + p->puSupps[2*k+1] = p->puSupps[2*i+1]; + } +*/ + k++; + } + assert( k == nVarsNew ); + p->nVars = k; + p->uSupp = Kit_BitMask(p->nVars); + return 1; +} + +/**Function************************************************************* + + Synopsis [Computes cofactors w.r.t. each variable.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Lpk_FunComputeCofSupps( Lpk_Fun_t * p ) +{ + unsigned * pTruth = Lpk_FunTruth( p, 0 ); + unsigned * pTruth0 = Lpk_FunTruth( p, 1 ); + unsigned * pTruth1 = Lpk_FunTruth( p, 2 ); + int Var; + assert( p->fSupports == 0 ); +// Lpk_SuppForEachVar( p->uSupp, Var ) + for ( Var = 0; Var < (int)p->nVars; Var++ ) + { + Kit_TruthCofactor0New( pTruth0, pTruth, p->nVars, Var ); + Kit_TruthCofactor1New( pTruth1, pTruth, p->nVars, Var ); + p->puSupps[2*Var+0] = Kit_TruthSupport( pTruth0, p->nVars ); + p->puSupps[2*Var+1] = Kit_TruthSupport( pTruth1, p->nVars ); + } + p->fSupports = 1; +} + +/**Function************************************************************* + + Synopsis [Get the delay of the bound set.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Lpk_SuppDelay( unsigned uSupp, char * pDelays ) +{ + int Delay, Var; + Delay = 0; + Lpk_SuppForEachVar( uSupp, Var ) + Delay = ABC_MAX( Delay, pDelays[Var] ); + return Delay + 1; +} + +/**Function************************************************************* + + Synopsis [Converts support into variables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Lpk_SuppToVars( unsigned uBoundSet, char * pVars ) +{ + int i, nVars = 0; + Lpk_SuppForEachVar( uBoundSet, i ) + pVars[nVars++] = i; + return nVars; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/lpk/lpkCore.c b/src/opt/lpk/lpkCore.c new file mode 100644 index 00000000..8b8028e3 --- /dev/null +++ b/src/opt/lpk/lpkCore.c @@ -0,0 +1,659 @@ +/**CFile**************************************************************** + + FileName [lpkCore.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Fast Boolean matching for LUT structures.] + + Synopsis [] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - April 28, 2007.] + + Revision [$Id: lpkCore.c,v 1.00 2007/04/28 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "lpkInt.h" +#include "cloud.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Prepares the mapping manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Lpk_IfManStart( Lpk_Man_t * p ) +{ + If_Par_t * pPars; + assert( p->pIfMan == NULL ); + // set defaults + pPars = ALLOC( If_Par_t, 1 ); + memset( pPars, 0, sizeof(If_Par_t) ); + // user-controlable paramters + pPars->nLutSize = p->pPars->nLutSize; + pPars->nCutsMax = 16; + pPars->nFlowIters = 0; // 1 + pPars->nAreaIters = 0; // 1 + pPars->DelayTarget = -1; + pPars->fPreprocess = 0; + pPars->fArea = 1; + pPars->fFancy = 0; + pPars->fExpRed = 0; // + pPars->fLatchPaths = 0; + pPars->fSeqMap = 0; + pPars->fVerbose = 0; + // internal parameters + pPars->fTruth = 1; + pPars->fUsePerm = 0; + pPars->nLatches = 0; + pPars->pLutLib = NULL; // Abc_FrameReadLibLut(); + pPars->pTimesArr = NULL; + pPars->pTimesArr = NULL; + pPars->fUseBdds = 0; + pPars->fUseSops = 0; + pPars->fUseCnfs = 0; + pPars->fUseMv = 0; + // start the mapping manager and set its parameters + p->pIfMan = If_ManStart( pPars ); + If_ManSetupSetAll( p->pIfMan, 1000 ); + p->pIfMan->pPars->pTimesArr = ALLOC( float, 32 ); +} + +/**Function************************************************************* + + Synopsis [Returns 1 if at least one entry has changed.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Lpk_NodeHasChanged( Lpk_Man_t * p, int iNode ) +{ + Vec_Ptr_t * vNodes; + Abc_Obj_t * pTemp; + int i; + vNodes = Vec_VecEntry( p->vVisited, iNode ); + if ( Vec_PtrSize(vNodes) == 0 ) + return 1; + Vec_PtrForEachEntry( vNodes, pTemp, i ) + { + // check if the node has changed + pTemp = Abc_NtkObj( p->pNtk, (int)pTemp ); + if ( pTemp == NULL ) + return 1; + // check if the number of fanouts has changed +// if ( Abc_ObjFanoutNum(pTemp) != (int)Vec_PtrEntry(vNodes, i+1) ) +// return 1; + i++; + } + return 0; +} + +/**Function************************************************************* + + Synopsis [Prepares the mapping manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Lpk_ExploreCut( Lpk_Man_t * p, Lpk_Cut_t * pCut, Kit_DsdNtk_t * pNtk ) +{ + extern Abc_Obj_t * Abc_NodeFromIf_rec( Abc_Ntk_t * pNtkNew, If_Man_t * pIfMan, If_Obj_t * pIfObj, Vec_Int_t * vCover ); + Kit_DsdObj_t * pRoot; + If_Obj_t * pDriver, * ppLeaves[16]; + Abc_Obj_t * pLeaf, * pObjNew; + int nGain, i, clk; + int nNodesBef; +// int nOldShared; + + // check special cases + pRoot = Kit_DsdNtkRoot( pNtk ); + if ( pRoot->Type == KIT_DSD_CONST1 ) + { + if ( Kit_DsdLitIsCompl(pNtk->Root) ) + pObjNew = Abc_NtkCreateNodeConst0( p->pNtk ); + else + pObjNew = Abc_NtkCreateNodeConst1( p->pNtk ); + Abc_NtkUpdate( p->pObj, pObjNew, p->vLevels ); + p->nGainTotal += pCut->nNodes - pCut->nNodesDup; + return 1; + } + if ( pRoot->Type == KIT_DSD_VAR ) + { + pObjNew = Abc_NtkObj( p->pNtk, pCut->pLeaves[ Kit_DsdLit2Var(pRoot->pFans[0]) ] ); + if ( Kit_DsdLitIsCompl(pNtk->Root) ^ Kit_DsdLitIsCompl(pRoot->pFans[0]) ) + pObjNew = Abc_NtkCreateNodeInv( p->pNtk, pObjNew ); + Abc_NtkUpdate( p->pObj, pObjNew, p->vLevels ); + p->nGainTotal += pCut->nNodes - pCut->nNodesDup; + return 1; + } + assert( pRoot->Type == KIT_DSD_AND || pRoot->Type == KIT_DSD_XOR || pRoot->Type == KIT_DSD_PRIME ); + + // start the mapping manager + if ( p->pIfMan == NULL ) + Lpk_IfManStart( p ); + + // prepare the mapping manager + If_ManRestart( p->pIfMan ); + // create the PI variables + for ( i = 0; i < p->pPars->nVarsMax; i++ ) + ppLeaves[i] = If_ManCreateCi( p->pIfMan ); + // set the arrival times + Lpk_CutForEachLeaf( p->pNtk, pCut, pLeaf, i ) + p->pIfMan->pPars->pTimesArr[i] = (float)pLeaf->Level; + // prepare the PI cuts + If_ManSetupCiCutSets( p->pIfMan ); + // create the internal nodes + p->fCalledOnce = 0; + p->nCalledSRed = 0; + pDriver = Lpk_MapTree_rec( p, pNtk, ppLeaves, pNtk->Root, NULL ); + if ( pDriver == NULL ) + return 0; + // create the PO node + If_ManCreateCo( p->pIfMan, If_Regular(pDriver) ); + + // perform mapping + p->pIfMan->pPars->fAreaOnly = 1; +clk = clock(); + If_ManPerformMappingComb( p->pIfMan ); +p->timeMap += clock() - clk; + + // compute the gain in area + nGain = pCut->nNodes - pCut->nNodesDup - (int)p->pIfMan->AreaGlo; + if ( p->pPars->fVeryVerbose ) + printf( " Mffc = %2d. Mapped = %2d. Gain = %3d. Depth increase = %d. SReds = %d.\n", + pCut->nNodes - pCut->nNodesDup, (int)p->pIfMan->AreaGlo, nGain, (int)p->pIfMan->RequiredGlo - (int)p->pObj->Level, p->nCalledSRed ); + + // quit if there is no gain + if ( !(nGain > 0 || (p->pPars->fZeroCost && nGain == 0)) ) + return 0; + + // quit if depth increases too much + if ( (int)p->pIfMan->RequiredGlo > Abc_ObjRequiredLevel(p->pObj) ) + return 0; + + // perform replacement + p->nGainTotal += nGain; + p->nChanges++; + if ( p->nCalledSRed ) + p->nBenefited++; + + nNodesBef = Abc_NtkNodeNum(p->pNtk); + // prepare the mapping manager + If_ManCleanNodeCopy( p->pIfMan ); + If_ManCleanCutData( p->pIfMan ); + // set the PIs of the cut + Lpk_CutForEachLeaf( p->pNtk, pCut, pLeaf, i ) + If_ObjSetCopy( If_ManCi(p->pIfMan, i), pLeaf ); + // get the area of mapping + pObjNew = Abc_NodeFromIf_rec( p->pNtk, p->pIfMan, If_Regular(pDriver), p->vCover ); + pObjNew->pData = Hop_NotCond( pObjNew->pData, If_IsComplement(pDriver) ); + // perform replacement + Abc_NtkUpdate( p->pObj, pObjNew, p->vLevels ); +//printf( "%3d : %d-%d=%d(%d) \n", p->nChanges, nNodesBef, Abc_NtkNodeNum(p->pNtk), nNodesBef-Abc_NtkNodeNum(p->pNtk), nGain ); + return 1; +} + +/**Function************************************************************* + + Synopsis [Performs resynthesis for one node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Lpk_ResynthesizeNode( Lpk_Man_t * p ) +{ + static int Count = 0; + Kit_DsdNtk_t * pDsdNtk; + Lpk_Cut_t * pCut; + unsigned * pTruth; + int i, k, nSuppSize, nCutNodes, RetValue, clk; + + // compute the cuts +clk = clock(); + if ( !Lpk_NodeCuts( p ) ) + { +p->timeCuts += clock() - clk; + return 0; + } +p->timeCuts += clock() - clk; + +//return 0; + + if ( p->pPars->fVeryVerbose ) + printf( "Node %5d : Mffc size = %5d. Cuts = %5d.\n", p->pObj->Id, p->nMffc, p->nEvals ); + // try the good cuts + p->nCutsTotal += p->nCuts; + p->nCutsUseful += p->nEvals; + for ( i = 0; i < p->nEvals; i++ ) + { + // get the cut + pCut = p->pCuts + p->pEvals[i]; + if ( p->pPars->fFirst && i == 1 ) + break; + + // skip bad cuts +// printf( "Mffc size = %d. ", Abc_NodeMffcLabel(p->pObj) ); + for ( k = 0; k < (int)pCut->nLeaves; k++ ) + Abc_NtkObj(p->pNtk, pCut->pLeaves[k])->vFanouts.nSize++; + nCutNodes = Abc_NodeMffcLabel(p->pObj); +// printf( "Mffc with cut = %d. ", nCutNodes ); + for ( k = 0; k < (int)pCut->nLeaves; k++ ) + Abc_NtkObj(p->pNtk, pCut->pLeaves[k])->vFanouts.nSize--; +// printf( "Mffc cut = %d. ", (int)pCut->nNodes - (int)pCut->nNodesDup ); +// printf( "\n" ); + if ( nCutNodes != (int)pCut->nNodes - (int)pCut->nNodesDup ) + continue; + + // compute the truth table +clk = clock(); + pTruth = Lpk_CutTruth( p, pCut, 0 ); + nSuppSize = Extra_TruthSupportSize(pTruth, pCut->nLeaves); +p->timeTruth += clock() - clk; + + pDsdNtk = Kit_DsdDecompose( pTruth, pCut->nLeaves ); +// Kit_DsdVerify( pDsdNtk, pTruth, pCut->nLeaves ); + // skip 16-input non-DSD because ISOP will not work + if ( Kit_DsdNtkRoot(pDsdNtk)->nFans == 16 ) + { + Kit_DsdNtkFree( pDsdNtk ); + continue; + } + + // if DSD has nodes that require splitting to fit them into LUTs + // we can skip those cuts that cannot lead to improvement + // (a full DSD network requires V = Nmin * (K-1) + 1 for improvement) + if ( Kit_DsdNonDsdSizeMax(pDsdNtk) > p->pPars->nLutSize && + nSuppSize >= ((int)pCut->nNodes - (int)pCut->nNodesDup - 1) * (p->pPars->nLutSize - 1) + 1 ) + { + Kit_DsdNtkFree( pDsdNtk ); + continue; + } + + if ( p->pPars->fVeryVerbose ) + { +// char * pFileName; + printf( " C%02d: L= %2d/%2d V= %2d/%d N= %d W= %4.2f ", + i, pCut->nLeaves, nSuppSize, pCut->nNodes, pCut->nNodesDup, pCut->nLuts, pCut->Weight ); + Kit_DsdPrint( stdout, pDsdNtk ); + Kit_DsdPrintFromTruth( pTruth, pCut->nLeaves ); +// pFileName = Kit_TruthDumpToFile( pTruth, pCut->nLeaves, Count++ ); +// printf( "Saved truth table in file \"%s\".\n", pFileName ); + } + + // update the network +clk = clock(); + RetValue = Lpk_ExploreCut( p, pCut, pDsdNtk ); +p->timeEval += clock() - clk; + Kit_DsdNtkFree( pDsdNtk ); + if ( RetValue ) + break; + } + return 1; +} + + +/**Function************************************************************* + + Synopsis [Computes supports of the cofactors of the function.] + + Description [This procedure should be called after Lpk_CutTruth(p,pCut,0)] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Lpk_ComputeSupports( Lpk_Man_t * p, Lpk_Cut_t * pCut, unsigned * pTruth ) +{ + unsigned * pTruthInv; + int RetValue1, RetValue2; + pTruthInv = Lpk_CutTruth( p, pCut, 1 ); + RetValue1 = Kit_CreateCloudFromTruth( p->pDsdMan->dd, pTruth, pCut->nLeaves, p->vBddDir ); + RetValue2 = Kit_CreateCloudFromTruth( p->pDsdMan->dd, pTruthInv, pCut->nLeaves, p->vBddInv ); + if ( RetValue1 && RetValue2 ) + Kit_TruthCofSupports( p->vBddDir, p->vBddInv, pCut->nLeaves, p->vMemory, p->puSupps ); + else + p->puSupps[0] = p->puSupps[1] = 0; +} + + +/**Function************************************************************* + + Synopsis [Performs resynthesis for one node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Lpk_ResynthesizeNodeNew( Lpk_Man_t * p ) +{ + static int Count = 0; + Abc_Obj_t * pObjNew, * pLeaf; + Lpk_Cut_t * pCut; + unsigned * pTruth; + int nNodesBef, nNodesAft, nCutNodes; + int i, k, clk; + int Required = Abc_ObjRequiredLevel(p->pObj); +// CloudNode * pFun2;//, * pFun1; + + // compute the cuts +clk = clock(); + if ( !Lpk_NodeCuts( p ) ) + { +p->timeCuts += clock() - clk; + return 0; + } +p->timeCuts += clock() - clk; + + if ( p->pPars->fVeryVerbose ) + printf( "Node %5d : Mffc size = %5d. Cuts = %5d. Level = %2d. Req = %2d.\n", + p->pObj->Id, p->nMffc, p->nEvals, p->pObj->Level, Required ); + // try the good cuts + p->nCutsTotal += p->nCuts; + p->nCutsUseful += p->nEvals; + for ( i = 0; i < p->nEvals; i++ ) + { + // get the cut + pCut = p->pCuts + p->pEvals[i]; + if ( p->pPars->fFirst && i == 1 ) + break; +// if ( pCut->Weight < 1.05 ) +// continue; + + // skip bad cuts +// printf( "Mffc size = %d. ", Abc_NodeMffcLabel(p->pObj) ); + for ( k = 0; k < (int)pCut->nLeaves; k++ ) + Abc_NtkObj(p->pNtk, pCut->pLeaves[k])->vFanouts.nSize++; + nCutNodes = Abc_NodeMffcLabel(p->pObj); +// printf( "Mffc with cut = %d. ", nCutNodes ); + for ( k = 0; k < (int)pCut->nLeaves; k++ ) + Abc_NtkObj(p->pNtk, pCut->pLeaves[k])->vFanouts.nSize--; +// printf( "Mffc cut = %d. ", (int)pCut->nNodes - (int)pCut->nNodesDup ); +// printf( "\n" ); + if ( nCutNodes != (int)pCut->nNodes - (int)pCut->nNodesDup ) + continue; + + // collect nodes into the array + Vec_PtrClear( p->vLeaves ); + for ( k = 0; k < (int)pCut->nLeaves; k++ ) + Vec_PtrPush( p->vLeaves, Abc_NtkObj(p->pNtk, pCut->pLeaves[k]) ); + + // compute the truth table +clk = clock(); + pTruth = Lpk_CutTruth( p, pCut, 0 ); +p->timeTruth += clock() - clk; +clk = clock(); + Lpk_ComputeSupports( p, pCut, pTruth ); +p->timeSupps += clock() - clk; +//clk = clock(); +// pFun1 = Lpk_CutTruthBdd( p, pCut ); +//p->timeTruth2 += clock() - clk; +/* +clk = clock(); + Cloud_Restart( p->pDsdMan->dd ); + pFun2 = Kit_TruthToCloud( p->pDsdMan->dd, pTruth, pCut->nLeaves ); + RetValue = Kit_CreateCloud( p->pDsdMan->dd, pFun2, p->vBddNodes ); +p->timeTruth3 += clock() - clk; +*/ +// if ( pFun1 != pFun2 ) +// printf( "Truth tables do not agree!\n" ); +// else +// printf( "Fine!\n" ); + + if ( p->pPars->fVeryVerbose ) + { +// char * pFileName; + int nSuppSize = Extra_TruthSupportSize( pTruth, pCut->nLeaves ); + printf( " C%02d: L= %2d/%2d V= %2d/%d N= %d W= %4.2f ", + i, pCut->nLeaves, nSuppSize, pCut->nNodes, pCut->nNodesDup, pCut->nLuts, pCut->Weight ); + Vec_PtrForEachEntry( p->vLeaves, pLeaf, k ) + printf( "%c=%d ", 'a'+k, Abc_ObjLevel(pLeaf) ); + printf( "\n" ); + Kit_DsdPrintFromTruth( pTruth, pCut->nLeaves ); +// pFileName = Kit_TruthDumpToFile( pTruth, pCut->nLeaves, Count++ ); +// printf( "Saved truth table in file \"%s\".\n", pFileName ); + } + if ( p->pObj->Id == 33 && i == 0 ) + { + int x = 0; + } + + // update the network + nNodesBef = Abc_NtkNodeNum(p->pNtk); +clk = clock(); + pObjNew = Lpk_Decompose( p, p->pNtk, p->vLeaves, pTruth, p->puSupps, p->pPars->nLutSize, + (int)pCut->nNodes - (int)pCut->nNodesDup - 1 + (int)(p->pPars->fZeroCost > 0), Required ); +p->timeEval += clock() - clk; + nNodesAft = Abc_NtkNodeNum(p->pNtk); + + // perform replacement + if ( pObjNew ) + { + int nGain = (int)pCut->nNodes - (int)pCut->nNodesDup - (nNodesAft - nNodesBef); + assert( nGain >= 1 - p->pPars->fZeroCost ); + assert( Abc_ObjLevel(pObjNew) <= Required ); +/* + if ( nGain <= 0 ) + { + int x = 0; + } + if ( Abc_ObjLevel(pObjNew) > Required ) + { + int x = 0; + } +*/ + p->nGainTotal += nGain; + p->nChanges++; + if ( p->pPars->fVeryVerbose ) + printf( "Performed resynthesis: Gain = %2d. Level = %2d. Req = %2d.\n", nGain, Abc_ObjLevel(pObjNew), Required ); + Abc_NtkUpdate( p->pObj, pObjNew, p->vLevels ); +//printf( "%3d : %d-%d=%d(%d) \n", p->nChanges, nNodesBef, Abc_NtkNodeNum(p->pNtk), nNodesBef-Abc_NtkNodeNum(p->pNtk), nGain ); + break; + } + } + return 1; +} + +/**Function************************************************************* + + Synopsis [Performs resynthesis for one network.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Lpk_Resynthesize( Abc_Ntk_t * pNtk, Lpk_Par_t * pPars ) +{ + ProgressBar * pProgress; + Lpk_Man_t * p; + Abc_Obj_t * pObj; + double Delta; + int i, Iter, nNodes, nNodesPrev, clk = clock(); + assert( Abc_NtkIsLogic(pNtk) ); + + // sweep dangling nodes as a preprocessing step + Abc_NtkSweep( pNtk, 0 ); + + // get the number of inputs + pPars->nLutSize = Abc_NtkGetFaninMax( pNtk ); + // adjust the number of crossbars based on LUT size + if ( pPars->nVarsShared > pPars->nLutSize - 2 ) + pPars->nVarsShared = pPars->nLutSize - 2; + // get the max number of LUTs tried + pPars->nVarsMax = pPars->nLutsMax * (pPars->nLutSize - 1) + 1; // V = N * (K-1) + 1 + while ( pPars->nVarsMax > 16 ) + { + pPars->nLutsMax--; + pPars->nVarsMax = pPars->nLutsMax * (pPars->nLutSize - 1) + 1; + + } + if ( pPars->fVerbose ) + { + printf( "Resynthesis for %d %d-LUTs with %d non-MFFC LUTs, %d crossbars, and %d-input cuts.\n", + pPars->nLutsMax, pPars->nLutSize, pPars->nLutsOver, pPars->nVarsShared, pPars->nVarsMax ); + } + + + // convert into the AIG + if ( !Abc_NtkToAig(pNtk) ) + { + fprintf( stdout, "Converting to BDD has failed.\n" ); + return 0; + } + assert( Abc_NtkHasAig(pNtk) ); + + // set the number of levels + Abc_NtkLevel( pNtk ); + Abc_NtkStartReverseLevels( pNtk, pPars->nGrowthLevel ); + + // start the manager + p = Lpk_ManStart( pPars ); + p->pNtk = pNtk; + p->nNodesTotal = Abc_NtkNodeNum(pNtk); + p->vLevels = Vec_VecStart( pNtk->LevelMax ); + if ( p->pPars->fSatur ) + p->vVisited = Vec_VecStart( 0 ); + if ( pPars->fVerbose ) + { + p->nTotalNets = Abc_NtkGetTotalFanins(pNtk); + p->nTotalNodes = Abc_NtkNodeNum(pNtk); + } + + // iterate over the network + nNodesPrev = p->nNodesTotal; + for ( Iter = 1; ; Iter++ ) + { + // expand storage for changed nodes + if ( p->pPars->fSatur ) + Vec_VecExpand( p->vVisited, Abc_NtkObjNumMax(pNtk) + 1 ); + + // consider all nodes + nNodes = Abc_NtkObjNumMax(pNtk); + if ( !pPars->fVeryVerbose ) + pProgress = Extra_ProgressBarStart( stdout, nNodes ); + Abc_NtkForEachNode( pNtk, pObj, i ) + { + // skip all except the final node + if ( pPars->fFirst ) + { + if ( !Abc_ObjIsCo(Abc_ObjFanout0(pObj)) ) + continue; + } + if ( i >= nNodes ) + break; + if ( !pPars->fVeryVerbose ) + Extra_ProgressBarUpdate( pProgress, i, NULL ); + // skip the nodes that did not change + if ( p->pPars->fSatur && !Lpk_NodeHasChanged(p, pObj->Id) ) + continue; + // resynthesize + p->pObj = pObj; + if ( p->pPars->fOldAlgo ) + Lpk_ResynthesizeNode( p ); + else + Lpk_ResynthesizeNodeNew( p ); + } + if ( !pPars->fVeryVerbose ) + Extra_ProgressBarStop( pProgress ); + + // check the increase + Delta = 100.00 * (nNodesPrev - Abc_NtkNodeNum(pNtk)) / p->nNodesTotal; + if ( Delta < 0.05 ) + break; + nNodesPrev = Abc_NtkNodeNum(pNtk); + if ( !p->pPars->fSatur ) + break; + + if ( pPars->fFirst ) + break; + } + Abc_NtkStopReverseLevels( pNtk ); + + if ( pPars->fVerbose ) + { +// Cloud_PrintInfo( p->pDsdMan->dd ); + p->nTotalNets2 = Abc_NtkGetTotalFanins(pNtk); + p->nTotalNodes2 = Abc_NtkNodeNum(pNtk); + printf( "Node gain = %5d. (%.2f %%) ", + p->nTotalNodes-p->nTotalNodes2, 100.0*(p->nTotalNodes-p->nTotalNodes2)/p->nTotalNodes ); + printf( "Edge gain = %5d. (%.2f %%) ", + p->nTotalNets-p->nTotalNets2, 100.0*(p->nTotalNets-p->nTotalNets2)/p->nTotalNets ); + printf( "Muxes = %4d. Dsds = %4d.", p->nMuxes, p->nDsds ); + printf( "\n" ); + printf( "Nodes = %5d (%3d) Cuts = %5d (%4d) Changes = %5d Iter = %2d Benefit = %d.\n", + p->nNodesTotal, p->nNodesOver, p->nCutsTotal, p->nCutsUseful, p->nChanges, Iter, p->nBenefited ); + + printf( "Non-DSD:" ); + for ( i = 3; i <= pPars->nVarsMax; i++ ) + if ( p->nBlocks[i] ) + printf( " %d=%d", i, p->nBlocks[i] ); + printf( "\n" ); + + p->timeTotal = clock() - clk; + p->timeEval = p->timeEval - p->timeMap; + p->timeOther = p->timeTotal - p->timeCuts - p->timeTruth - p->timeEval - p->timeMap; + PRTP( "Cuts ", p->timeCuts, p->timeTotal ); + PRTP( "Truth ", p->timeTruth, p->timeTotal ); + PRTP( "CSupps", p->timeSupps, p->timeTotal ); + PRTP( "Eval ", p->timeEval, p->timeTotal ); + PRTP( " MuxAn", p->timeEvalMuxAn, p->timeEval ); + PRTP( " MuxSp", p->timeEvalMuxSp, p->timeEval ); + PRTP( " DsdAn", p->timeEvalDsdAn, p->timeEval ); + PRTP( " DsdSp", p->timeEvalDsdSp, p->timeEval ); + PRTP( " Other", p->timeEval-p->timeEvalMuxAn-p->timeEvalMuxSp-p->timeEvalDsdAn-p->timeEvalDsdSp, p->timeEval ); + PRTP( "Map ", p->timeMap, p->timeTotal ); + PRTP( "Other ", p->timeOther, p->timeTotal ); + PRTP( "TOTAL ", p->timeTotal, p->timeTotal ); + } + + Lpk_ManStop( p ); + // check the resulting network + if ( !Abc_NtkCheck( pNtk ) ) + { + printf( "Lpk_Resynthesize: The network check has failed.\n" ); + return 0; + } + return 1; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/lpk/lpkCut.c b/src/opt/lpk/lpkCut.c new file mode 100644 index 00000000..b2a743bd --- /dev/null +++ b/src/opt/lpk/lpkCut.c @@ -0,0 +1,683 @@ +/**CFile**************************************************************** + + FileName [lpkCut.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Fast Boolean matching for LUT structures.] + + Synopsis [] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - April 28, 2007.] + + Revision [$Id: lpkCut.c,v 1.00 2007/04/28 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "lpkInt.h" +#include "cloud.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Computes the truth table of one cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +CloudNode * Lpk_CutTruthBdd_rec( CloudManager * dd, Hop_Man_t * pMan, Hop_Obj_t * pObj, int nVars ) +{ + CloudNode * pTruth, * pTruth0, * pTruth1; + assert( !Hop_IsComplement(pObj) ); + if ( pObj->pData ) + { + assert( ((unsigned)pObj->pData) & 0xffff0000 ); + return pObj->pData; + } + // get the plan for a new truth table + if ( Hop_ObjIsConst1(pObj) ) + pTruth = dd->one; + else + { + assert( Hop_ObjIsAnd(pObj) ); + // compute the truth tables of the fanins + pTruth0 = Lpk_CutTruthBdd_rec( dd, pMan, Hop_ObjFanin0(pObj), nVars ); + pTruth1 = Lpk_CutTruthBdd_rec( dd, pMan, Hop_ObjFanin1(pObj), nVars ); + pTruth0 = Cloud_NotCond( pTruth0, Hop_ObjFaninC0(pObj) ); + pTruth1 = Cloud_NotCond( pTruth1, Hop_ObjFaninC1(pObj) ); + // creat the truth table of the node + pTruth = Cloud_bddAnd( dd, pTruth0, pTruth1 ); + } + pObj->pData = pTruth; + return pTruth; +} + +/**Function************************************************************* + + Synopsis [Verifies that the factoring is correct.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +CloudNode * Lpk_CutTruthBdd( Lpk_Man_t * p, Lpk_Cut_t * pCut ) +{ + CloudManager * dd = p->pDsdMan->dd; + Hop_Man_t * pManHop = p->pNtk->pManFunc; + Hop_Obj_t * pObjHop; + Abc_Obj_t * pObj, * pFanin; + CloudNode * pTruth; + int i, k, iCount = 0; + +// return NULL; +// Lpk_NodePrintCut( p, pCut ); + // initialize the leaves + Lpk_CutForEachLeaf( p->pNtk, pCut, pObj, i ) + pObj->pCopy = (Abc_Obj_t *)dd->vars[pCut->nLeaves-1-i]; + + // construct truth table in the topological order + Lpk_CutForEachNodeReverse( p->pNtk, pCut, pObj, i ) + { + // get the local AIG + pObjHop = Hop_Regular(pObj->pData); + // clean the data field of the nodes in the AIG subgraph + Hop_ObjCleanData_rec( pObjHop ); + // set the initial truth tables at the fanins + Abc_ObjForEachFanin( pObj, pFanin, k ) + { + assert( ((unsigned)pFanin->pCopy) & 0xffff0000 ); + Hop_ManPi( pManHop, k )->pData = pFanin->pCopy; + } + // compute the truth table of internal nodes + pTruth = Lpk_CutTruthBdd_rec( dd, pManHop, pObjHop, pCut->nLeaves ); + if ( Hop_IsComplement(pObj->pData) ) + pTruth = Cloud_Not(pTruth); + // set the truth table at the node + pObj->pCopy = (Abc_Obj_t *)pTruth; + + } + +// Cloud_bddPrint( dd, pTruth ); +// printf( "Bdd size = %d. Total nodes = %d.\n", Cloud_DagSize( dd, pTruth ), dd->nNodesCur-dd->nVars-1 ); + return pTruth; +} + + +/**Function************************************************************* + + Synopsis [Computes the truth table of one cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned * Lpk_CutTruth_rec( Hop_Man_t * pMan, Hop_Obj_t * pObj, int nVars, Vec_Ptr_t * vTtNodes, int * piCount ) +{ + unsigned * pTruth, * pTruth0, * pTruth1; + assert( !Hop_IsComplement(pObj) ); + if ( pObj->pData ) + { + assert( ((unsigned)pObj->pData) & 0xffff0000 ); + return pObj->pData; + } + // get the plan for a new truth table + pTruth = Vec_PtrEntry( vTtNodes, (*piCount)++ ); + if ( Hop_ObjIsConst1(pObj) ) + Kit_TruthFill( pTruth, nVars ); + else + { + assert( Hop_ObjIsAnd(pObj) ); + // compute the truth tables of the fanins + pTruth0 = Lpk_CutTruth_rec( pMan, Hop_ObjFanin0(pObj), nVars, vTtNodes, piCount ); + pTruth1 = Lpk_CutTruth_rec( pMan, Hop_ObjFanin1(pObj), nVars, vTtNodes, piCount ); + // creat the truth table of the node + Kit_TruthAndPhase( pTruth, pTruth0, pTruth1, nVars, Hop_ObjFaninC0(pObj), Hop_ObjFaninC1(pObj) ); + } + pObj->pData = pTruth; + return pTruth; +} + +/**Function************************************************************* + + Synopsis [Computes the truth able of one cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned * Lpk_CutTruth( Lpk_Man_t * p, Lpk_Cut_t * pCut, int fInv ) +{ + Hop_Man_t * pManHop = p->pNtk->pManFunc; + Hop_Obj_t * pObjHop; + Abc_Obj_t * pObj, * pFanin; + unsigned * pTruth; + int i, k, iCount = 0; +// Lpk_NodePrintCut( p, pCut ); + assert( pCut->nNodes > 0 ); + + // initialize the leaves + Lpk_CutForEachLeaf( p->pNtk, pCut, pObj, i ) + pObj->pCopy = Vec_PtrEntry( p->vTtElems, fInv? pCut->nLeaves-1-i : i ); + + // construct truth table in the topological order + Lpk_CutForEachNodeReverse( p->pNtk, pCut, pObj, i ) + { + // get the local AIG + pObjHop = Hop_Regular(pObj->pData); + // clean the data field of the nodes in the AIG subgraph + Hop_ObjCleanData_rec( pObjHop ); + // set the initial truth tables at the fanins + Abc_ObjForEachFanin( pObj, pFanin, k ) + { + assert( ((unsigned)pFanin->pCopy) & 0xffff0000 ); + Hop_ManPi( pManHop, k )->pData = pFanin->pCopy; + } + // compute the truth table of internal nodes + pTruth = Lpk_CutTruth_rec( pManHop, pObjHop, pCut->nLeaves, p->vTtNodes, &iCount ); + if ( Hop_IsComplement(pObj->pData) ) + Kit_TruthNot( pTruth, pTruth, pCut->nLeaves ); + // set the truth table at the node + pObj->pCopy = (Abc_Obj_t *)pTruth; + } + + // make sure direct truth table is stored elsewhere (assuming the first call for direct truth!!!) + if ( fInv == 0 ) + { + pTruth = Vec_PtrEntry( p->vTtNodes, iCount++ ); + Kit_TruthCopy( pTruth, (unsigned *)pObj->pCopy, pCut->nLeaves ); + } + assert( iCount <= Vec_PtrSize(p->vTtNodes) ); + return pTruth; +} + + +/**Function************************************************************* + + Synopsis [Returns 1 if at least one entry has changed.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Lpk_NodeRecordImpact( Lpk_Man_t * p ) +{ + Lpk_Cut_t * pCut; + Vec_Ptr_t * vNodes = Vec_VecEntry( p->vVisited, p->pObj->Id ); + Abc_Obj_t * pNode; + int i, k; + // collect the nodes that impact the given node + Vec_PtrClear( vNodes ); + for ( i = 0; i < p->nCuts; i++ ) + { + pCut = p->pCuts + i; + for ( k = 0; k < (int)pCut->nLeaves; k++ ) + { + pNode = Abc_NtkObj( p->pNtk, pCut->pLeaves[k] ); + if ( pNode->fMarkC ) + continue; + pNode->fMarkC = 1; + Vec_PtrPush( vNodes, (void *)pNode->Id ); + Vec_PtrPush( vNodes, (void *)Abc_ObjFanoutNum(pNode) ); + } + } + // clear the marks + Vec_PtrForEachEntry( vNodes, pNode, i ) + { + pNode = Abc_NtkObj( p->pNtk, (int)pNode ); + pNode->fMarkC = 0; + i++; + } +//printf( "%d ", Vec_PtrSize(vNodes) ); +} + +/**Function************************************************************* + + Synopsis [Returns 1 if the cut has structural DSD.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Lpk_NodeCutsCheckDsd( Lpk_Man_t * p, Lpk_Cut_t * pCut ) +{ + Abc_Obj_t * pObj, * pFanin; + int i, k, nCands, fLeavesOnly, RetValue; + assert( pCut->nLeaves > 0 ); + // clear ref counters + memset( p->pRefs, 0, sizeof(int) * pCut->nLeaves ); + // mark cut leaves + Lpk_CutForEachLeaf( p->pNtk, pCut, pObj, i ) + { + assert( pObj->fMarkA == 0 ); + pObj->fMarkA = 1; + pObj->pCopy = (void *)i; + } + // ref leaves pointed from the internal nodes + nCands = 0; + Lpk_CutForEachNode( p->pNtk, pCut, pObj, i ) + { + fLeavesOnly = 1; + Abc_ObjForEachFanin( pObj, pFanin, k ) + if ( pFanin->fMarkA ) + p->pRefs[(int)pFanin->pCopy]++; + else + fLeavesOnly = 0; + if ( fLeavesOnly ) + p->pCands[nCands++] = pObj->Id; + } + // look at the nodes that only point to the leaves + RetValue = 0; + for ( i = 0; i < nCands; i++ ) + { + pObj = Abc_NtkObj( p->pNtk, p->pCands[i] ); + Abc_ObjForEachFanin( pObj, pFanin, k ) + { + assert( pFanin->fMarkA == 1 ); + if ( p->pRefs[(int)pFanin->pCopy] > 1 ) + break; + } + if ( k == Abc_ObjFaninNum(pObj) ) + { + RetValue = 1; + break; + } + } + // unmark cut leaves + Lpk_CutForEachLeaf( p->pNtk, pCut, pObj, i ) + pObj->fMarkA = 0; + return RetValue; +} + +/**Function************************************************************* + + Synopsis [Returns 1 if pDom is contained in pCut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Lpk_NodeCutsOneDominance( Lpk_Cut_t * pDom, Lpk_Cut_t * pCut ) +{ + int i, k; + for ( i = 0; i < (int)pDom->nLeaves; i++ ) + { + for ( k = 0; k < (int)pCut->nLeaves; k++ ) + if ( pDom->pLeaves[i] == pCut->pLeaves[k] ) + break; + if ( k == (int)pCut->nLeaves ) // node i in pDom is not contained in pCut + return 0; + } + // every node in pDom is contained in pCut + return 1; +} + +/**Function************************************************************* + + Synopsis [Check if the cut exists.] + + Description [Returns 1 if the cut exists.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Lpk_NodeCutsOneFilter( Lpk_Cut_t * pCuts, int nCuts, Lpk_Cut_t * pCutNew ) +{ + Lpk_Cut_t * pCut; + int i, k; + assert( pCutNew->uSign[0] || pCutNew->uSign[1] ); + // try to find the cut + for ( i = 0; i < nCuts; i++ ) + { + pCut = pCuts + i; + if ( pCut->nLeaves == 0 ) + continue; + if ( pCut->nLeaves == pCutNew->nLeaves ) + { + if ( pCut->uSign[0] == pCutNew->uSign[0] && pCut->uSign[1] == pCutNew->uSign[1] ) + { + for ( k = 0; k < (int)pCutNew->nLeaves; k++ ) + if ( pCut->pLeaves[k] != pCutNew->pLeaves[k] ) + break; + if ( k == (int)pCutNew->nLeaves ) + return 1; + } + continue; + } + if ( pCut->nLeaves < pCutNew->nLeaves ) + { + // skip the non-contained cuts + if ( (pCut->uSign[0] & pCutNew->uSign[0]) != pCut->uSign[0] ) + continue; + if ( (pCut->uSign[1] & pCutNew->uSign[1]) != pCut->uSign[1] ) + continue; + // check containment seriously + if ( Lpk_NodeCutsOneDominance( pCut, pCutNew ) ) + return 1; + continue; + } + // check potential containment of other cut + + // skip the non-contained cuts + if ( (pCut->uSign[0] & pCutNew->uSign[0]) != pCutNew->uSign[0] ) + continue; + if ( (pCut->uSign[1] & pCutNew->uSign[1]) != pCutNew->uSign[1] ) + continue; + // check containment seriously + if ( Lpk_NodeCutsOneDominance( pCutNew, pCut ) ) + pCut->nLeaves = 0; // removed + } + return 0; +} + +/**Function************************************************************* + + Synopsis [Prints the given cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Lpk_NodePrintCut( Lpk_Man_t * p, Lpk_Cut_t * pCut, int fLeavesOnly ) +{ + Abc_Obj_t * pObj; + int i; + if ( !fLeavesOnly ) + printf( "LEAVES:\n" ); + Lpk_CutForEachLeaf( p->pNtk, pCut, pObj, i ) + printf( "%d,", pObj->Id ); + if ( !fLeavesOnly ) + { + printf( "\nNODES:\n" ); + Lpk_CutForEachNode( p->pNtk, pCut, pObj, i ) + { + printf( "%d,", pObj->Id ); + assert( Abc_ObjIsNode(pObj) ); + } + printf( "\n" ); + } +} + +/**Function************************************************************* + + Synopsis [Set the cut signature.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Lpk_NodeCutSignature( Lpk_Cut_t * pCut ) +{ + unsigned i; + pCut->uSign[0] = pCut->uSign[1] = 0; + for ( i = 0; i < pCut->nLeaves; i++ ) + { + pCut->uSign[(pCut->pLeaves[i] & 32) > 0] |= (1 << (pCut->pLeaves[i] & 31)); + if ( i != pCut->nLeaves - 1 ) + assert( pCut->pLeaves[i] < pCut->pLeaves[i+1] ); + } +} + + +/**Function************************************************************* + + Synopsis [Computes the set of all cuts.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Lpk_NodeCutsOne( Lpk_Man_t * p, Lpk_Cut_t * pCut, int Node ) +{ + Lpk_Cut_t * pCutNew; + Abc_Obj_t * pObj, * pFanin; + int i, k, j, nLeavesNew; +/* + printf( "Exploring cut " ); + Lpk_NodePrintCut( p, pCut, 1 ); + printf( "with node %d\n", Node ); +*/ + // check if the cut can stand adding one more internal node + if ( pCut->nNodes == LPK_SIZE_MAX ) + return; + + // if the node is a PI, quit + pObj = Abc_NtkObj( p->pNtk, Node ); + if ( Abc_ObjIsCi(pObj) ) + return; + assert( Abc_ObjIsNode(pObj) ); + assert( Abc_ObjFaninNum(pObj) <= p->pPars->nLutSize ); + + // if the node is not in the MFFC, check the limit + if ( !Abc_NodeIsTravIdCurrent(pObj) ) + { + if ( (int)pCut->nNodesDup == p->pPars->nLutsOver ) + return; + assert( (int)pCut->nNodesDup < p->pPars->nLutsOver ); + } + + // check the possibility of adding this node using the signature + nLeavesNew = pCut->nLeaves - 1; + Abc_ObjForEachFanin( pObj, pFanin, i ) + { + if ( (pCut->uSign[(pFanin->Id & 32) > 0] & (1 << (pFanin->Id & 31))) ) + continue; + if ( ++nLeavesNew > p->pPars->nVarsMax ) + return; + } + + // initialize the set of leaves to the nodes in the cut + assert( p->nCuts < LPK_CUTS_MAX ); + pCutNew = p->pCuts + p->nCuts; + pCutNew->nLeaves = 0; + for ( i = 0; i < (int)pCut->nLeaves; i++ ) + if ( pCut->pLeaves[i] != Node ) + pCutNew->pLeaves[pCutNew->nLeaves++] = pCut->pLeaves[i]; + + // add new nodes + Abc_ObjForEachFanin( pObj, pFanin, i ) + { + // find the place where this node belongs + for ( k = 0; k < (int)pCutNew->nLeaves; k++ ) + if ( pCutNew->pLeaves[k] >= pFanin->Id ) + break; + if ( k < (int)pCutNew->nLeaves && pCutNew->pLeaves[k] == pFanin->Id ) + continue; + // check if there is room + if ( (int)pCutNew->nLeaves == p->pPars->nVarsMax ) + return; + // move all the nodes + for ( j = pCutNew->nLeaves; j > k; j-- ) + pCutNew->pLeaves[j] = pCutNew->pLeaves[j-1]; + pCutNew->pLeaves[k] = pFanin->Id; + pCutNew->nLeaves++; + assert( pCutNew->nLeaves <= LPK_SIZE_MAX ); + + } + // skip the contained cuts + Lpk_NodeCutSignature( pCutNew ); + if ( Lpk_NodeCutsOneFilter( p->pCuts, p->nCuts, pCutNew ) ) + return; + + // update the set of internal nodes + assert( pCut->nNodes < LPK_SIZE_MAX ); + memcpy( pCutNew->pNodes, pCut->pNodes, pCut->nNodes * sizeof(int) ); + pCutNew->nNodes = pCut->nNodes; + pCutNew->nNodesDup = pCut->nNodesDup; + + // check if the node is already there + // if so, move the node to be the last + for ( i = 0; i < (int)pCutNew->nNodes; i++ ) + if ( pCutNew->pNodes[i] == Node ) + { + for ( k = i; k < (int)pCutNew->nNodes - 1; k++ ) + pCutNew->pNodes[k] = pCutNew->pNodes[k+1]; + pCutNew->pNodes[k] = Node; + break; + } + if ( i == (int)pCutNew->nNodes ) // new node + { + pCutNew->pNodes[ pCutNew->nNodes++ ] = Node; + pCutNew->nNodesDup += !Abc_NodeIsTravIdCurrent(pObj); + } + // the number of nodes does not exceed MFFC plus duplications + assert( pCutNew->nNodes <= p->nMffc + pCutNew->nNodesDup ); + // add the cut to storage + assert( p->nCuts < LPK_CUTS_MAX ); + p->nCuts++; +} + +/**Function************************************************************* + + Synopsis [Computes the set of all cuts.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Lpk_NodeCuts( Lpk_Man_t * p ) +{ + Lpk_Cut_t * pCut, * pCut2; + int i, k, Temp, nMffc, fChanges; + + // mark the MFFC of the node with the current trav ID + nMffc = p->nMffc = Abc_NodeMffcLabel( p->pObj ); + assert( nMffc > 0 ); + if ( nMffc == 1 ) + return 0; + + // initialize the first cut + pCut = p->pCuts; p->nCuts = 1; + pCut->nNodes = 0; + pCut->nNodesDup = 0; + pCut->nLeaves = 1; + pCut->pLeaves[0] = p->pObj->Id; + // assign the signature + Lpk_NodeCutSignature( pCut ); + + // perform the cut computation + for ( i = 0; i < p->nCuts; i++ ) + { + pCut = p->pCuts + i; + if ( pCut->nLeaves == 0 ) + continue; + + // try to expand the fanins of this cut + for ( k = 0; k < (int)pCut->nLeaves; k++ ) + { + // create a new cut + Lpk_NodeCutsOne( p, pCut, pCut->pLeaves[k] ); + // quit if the number of cuts has exceeded the limit + if ( p->nCuts == LPK_CUTS_MAX ) + break; + } + if ( p->nCuts == LPK_CUTS_MAX ) + break; + } + if ( p->nCuts == LPK_CUTS_MAX ) + p->nNodesOver++; + + // record the impact of this node + if ( p->pPars->fSatur ) + Lpk_NodeRecordImpact( p ); + + // compress the cuts by removing empty ones, those with negative Weight, and decomposable ones + p->nEvals = 0; + for ( i = 0; i < p->nCuts; i++ ) + { + pCut = p->pCuts + i; + if ( pCut->nLeaves < 2 ) + continue; + // compute the minimum number of LUTs needed to implement this cut + // V = N * (K-1) + 1 ~~~~~ N = Ceiling[(V-1)/(K-1)] = (V-1)/(K-1) + [(V-1)%(K-1) > 0] + pCut->nLuts = Lpk_LutNumLuts( pCut->nLeaves, p->pPars->nLutSize ); +// pCut->Weight = (float)1.0 * (pCut->nNodes - pCut->nNodesDup - 1) / pCut->nLuts; //p->pPars->nLutsMax; + pCut->Weight = (float)1.0 * (pCut->nNodes - pCut->nNodesDup) / pCut->nLuts; //p->pPars->nLutsMax; + if ( pCut->Weight <= 1.001 ) +// if ( pCut->Weight <= 0.999 ) + continue; + pCut->fHasDsd = Lpk_NodeCutsCheckDsd( p, pCut ); + if ( pCut->fHasDsd ) + continue; + p->pEvals[p->nEvals++] = i; + } + if ( p->nEvals == 0 ) + return 0; + + // sort the cuts by Weight + do { + fChanges = 0; + for ( i = 0; i < p->nEvals - 1; i++ ) + { + pCut = p->pCuts + p->pEvals[i]; + pCut2 = p->pCuts + p->pEvals[i+1]; + if ( pCut->Weight >= pCut2->Weight - 0.001 ) + continue; + Temp = p->pEvals[i]; + p->pEvals[i] = p->pEvals[i+1]; + p->pEvals[i+1] = Temp; + fChanges = 1; + } + } while ( fChanges ); +/* + for ( i = 0; i < p->nEvals; i++ ) + { + pCut = p->pCuts + p->pEvals[i]; + printf( "Cut %3d : W = %5.2f.\n", i, pCut->Weight ); + } + printf( "\n" ); +*/ + return 1; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/lpk/lpkInt.h b/src/opt/lpk/lpkInt.h new file mode 100644 index 00000000..960599e4 --- /dev/null +++ b/src/opt/lpk/lpkInt.h @@ -0,0 +1,246 @@ +/**CFile**************************************************************** + + FileName [lpkInt.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Fast Boolean matching for LUT structures.] + + Synopsis [Internal declarations.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - April 28, 2007.] + + Revision [$Id: lpkInt.h,v 1.00 2007/04/28 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef __LPK_INT_H__ +#define __LPK_INT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +#include "abc.h" +#include "kit.h" +#include "if.h" +#include "lpk.h" + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// BASIC TYPES /// +//////////////////////////////////////////////////////////////////////// + +#define LPK_SIZE_MAX 24 // the largest size of the function +#define LPK_CUTS_MAX 512 // the largest number of cuts considered + +typedef struct Lpk_Man_t_ Lpk_Man_t; +typedef struct Lpk_Cut_t_ Lpk_Cut_t; + +struct Lpk_Cut_t_ +{ + unsigned nLeaves : 6; // (L) the number of leaves + unsigned nNodes : 6; // (M) the number of nodes + unsigned nNodesDup : 6; // (Q) nodes outside of MFFC + unsigned nLuts : 6; // (N) the number of LUTs to try + unsigned unused : 6; // unused + unsigned fHasDsd : 1; // set to 1 if the cut has structural DSD (and so cannot be used) + unsigned fMark : 1; // multipurpose mark + unsigned uSign[2]; // the signature + float Weight; // the weight of the cut: (M - Q)/N(V) (the larger the better) + int Gain; // the gain achieved using this cut + int pLeaves[LPK_SIZE_MAX]; // the leaves of the cut + int pNodes[LPK_SIZE_MAX]; // the nodes of the cut +}; + +struct Lpk_Man_t_ +{ + // parameters + Lpk_Par_t * pPars; // the set of parameters + // current representation + Abc_Ntk_t * pNtk; // the network + Abc_Obj_t * pObj; // the node to resynthesize + // cut representation + int nMffc; // the size of MFFC of the node + int nCuts; // the total number of cuts + int nCutsMax; // the largest possible number of cuts + int nEvals; // the number of good cuts + Lpk_Cut_t pCuts[LPK_CUTS_MAX]; // the storage for cuts + int pEvals[LPK_CUTS_MAX]; // the good cuts + // visited nodes + Vec_Vec_t * vVisited; + // mapping manager + If_Man_t * pIfMan; + Vec_Int_t * vCover; + Vec_Vec_t * vLevels; + // temporary variables + int fCofactoring; // working in the cofactoring mode + int fCalledOnce; // limits the depth of MUX cofactoring + int nCalledSRed; // the number of called to SRed + int pRefs[LPK_SIZE_MAX]; // fanin reference counters + int pCands[LPK_SIZE_MAX]; // internal nodes pointing only to the leaves + Vec_Ptr_t * vLeaves; + // truth table representation + Vec_Ptr_t * vTtElems; // elementary truth tables + Vec_Ptr_t * vTtNodes; // storage for temporary truth tables of the nodes + Vec_Int_t * vMemory; + Vec_Int_t * vBddDir; + Vec_Int_t * vBddInv; + unsigned puSupps[32]; // the supports of the cofactors + unsigned * ppTruths[5][16]; + // variable sets + Vec_Int_t * vSets[8]; + Kit_DsdMan_t* pDsdMan; + // statistics + int nNodesTotal; // total number of nodes + int nNodesOver; // nodes with cuts over the limit + int nCutsTotal; // total number of cuts + int nCutsUseful; // useful cuts + int nGainTotal; // the gain in LUTs + int nChanges; // the number of changed nodes + int nBenefited; // the number of gainful that benefited from decomposition + int nMuxes; + int nDsds; + int nTotalNets; + int nTotalNets2; + int nTotalNodes; + int nTotalNodes2; + // counter of non-DSD blocks + int nBlocks[17]; + // runtime + int timeCuts; + int timeTruth; + int timeSupps; + int timeTruth2; + int timeTruth3; + int timeEval; + int timeMap; + int timeOther; + int timeTotal; + // runtime of eval + int timeEvalMuxAn; + int timeEvalMuxSp; + int timeEvalDsdAn; + int timeEvalDsdSp; + +}; + + +// internal representation of the function to be decomposed +typedef struct Lpk_Fun_t_ Lpk_Fun_t; +struct Lpk_Fun_t_ +{ + Vec_Ptr_t * vNodes; // the array of leaves and decomposition nodes + unsigned Id : 7; // the ID of this node + unsigned nVars : 5; // the number of variables + unsigned nLutK : 4; // the number of LUT inputs + unsigned nAreaLim : 5; // the area limit (the largest allowed) + unsigned nDelayLim : 9; // the delay limit (the largest allowed) + unsigned fSupports : 1; // supports of cofactors were precomputed + unsigned fMark : 1; // marks the MUX-based dec + unsigned uSupp; // the support of this component + unsigned puSupps[32]; // the supports of the cofactors + char pDelays[16]; // the delays of the inputs + char pFanins[16]; // the fanins of this function + unsigned pTruth[0]; // the truth table (contains room for three truth tables) +}; + +// preliminary decomposition result +typedef struct Lpk_Res_t_ Lpk_Res_t; +struct Lpk_Res_t_ +{ + int nBSVars; // the number of bound set variables + unsigned BSVars; // the bound set + int nCofVars; // the number of cofactoring variables + char pCofVars[4]; // the cofactoring variables + int nSuppSizeS; // support size of the smaller (decomposed) function + int nSuppSizeL; // support size of the larger (composition) function + int DelayEst; // estimated delay of the decomposition + int AreaEst; // estimated area of the decomposition + int Variable; // variable in MUX decomposition + int Polarity; // polarity in MUX decomposition +}; + +static inline int Lpk_LutNumVars( int nLutsLim, int nLutK ) { return nLutsLim * (nLutK - 1) + 1; } +static inline int Lpk_LutNumLuts( int nVarsMax, int nLutK ) { return (nVarsMax - 1) / (nLutK - 1) + (int)((nVarsMax - 1) % (nLutK - 1) > 0); } +static inline unsigned * Lpk_FunTruth( Lpk_Fun_t * p, int Num ) { assert( Num < 3 ); return p->pTruth + Kit_TruthWordNum(p->nVars) * Num; } + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// ITERATORS /// +//////////////////////////////////////////////////////////////////////// + +#define Lpk_CutForEachLeaf( pNtk, pCut, pObj, i ) \ + for ( i = 0; (i < (int)(pCut)->nLeaves) && (((pObj) = Abc_NtkObj(pNtk, (pCut)->pLeaves[i])), 1); i++ ) +#define Lpk_CutForEachNode( pNtk, pCut, pObj, i ) \ + for ( i = 0; (i < (int)(pCut)->nNodes) && (((pObj) = Abc_NtkObj(pNtk, (pCut)->pNodes[i])), 1); i++ ) +#define Lpk_CutForEachNodeReverse( pNtk, pCut, pObj, i ) \ + for ( i = (int)(pCut)->nNodes - 1; (i >= 0) && (((pObj) = Abc_NtkObj(pNtk, (pCut)->pNodes[i])), 1); i-- ) +#define Lpk_SuppForEachVar( Supp, Var )\ + for ( Var = 0; Var < 16; Var++ )\ + if ( !(Supp & (1<nLutsMax <= 16 ); + assert( pPars->nVarsMax > 0 && pPars->nVarsMax <= 16 ); + p = ALLOC( Lpk_Man_t, 1 ); + memset( p, 0, sizeof(Lpk_Man_t) ); + p->pPars = pPars; + p->nCutsMax = LPK_CUTS_MAX; + p->vTtElems = Vec_PtrAllocTruthTables( pPars->nVarsMax ); + p->vTtNodes = Vec_PtrAllocSimInfo( 1024, Abc_TruthWordNum(pPars->nVarsMax) ); + p->vCover = Vec_IntAlloc( 1 << 12 ); + p->vLeaves = Vec_PtrAlloc( 32 ); + for ( i = 0; i < 8; i++ ) + p->vSets[i] = Vec_IntAlloc(100); + p->pDsdMan = Kit_DsdManAlloc( pPars->nVarsMax, 64 ); + p->vMemory = Vec_IntAlloc( 1024 * 32 ); + p->vBddDir = Vec_IntAlloc( 256 ); + p->vBddInv = Vec_IntAlloc( 256 ); + // allocate temporary storage for truth tables + nWords = Kit_TruthWordNum(pPars->nVarsMax); + p->ppTruths[0][0] = ALLOC( unsigned, 32 * nWords ); + p->ppTruths[1][0] = p->ppTruths[0][0] + 1 * nWords; + for ( i = 1; i < 2; i++ ) + p->ppTruths[1][i] = p->ppTruths[1][0] + i * nWords; + p->ppTruths[2][0] = p->ppTruths[1][0] + 2 * nWords; + for ( i = 1; i < 4; i++ ) + p->ppTruths[2][i] = p->ppTruths[2][0] + i * nWords; + p->ppTruths[3][0] = p->ppTruths[2][0] + 4 * nWords; + for ( i = 1; i < 8; i++ ) + p->ppTruths[3][i] = p->ppTruths[3][0] + i * nWords; + p->ppTruths[4][0] = p->ppTruths[3][0] + 8 * nWords; + for ( i = 1; i < 16; i++ ) + p->ppTruths[4][i] = p->ppTruths[4][0] + i * nWords; + return p; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Lpk_ManStop( Lpk_Man_t * p ) +{ + int i; + free( p->ppTruths[0][0] ); + Vec_IntFree( p->vBddDir ); + Vec_IntFree( p->vBddInv ); + Vec_IntFree( p->vMemory ); + Kit_DsdManFree( p->pDsdMan ); + for ( i = 0; i < 8; i++ ) + Vec_IntFree(p->vSets[i]); + if ( p->pIfMan ) + { + void * pPars = p->pIfMan->pPars; + If_ManStop( p->pIfMan ); + free( pPars ); + } + if ( p->vLevels ) + Vec_VecFree( p->vLevels ); + if ( p->vVisited ) + Vec_VecFree( p->vVisited ); + Vec_PtrFree( p->vLeaves ); + Vec_IntFree( p->vCover ); + Vec_PtrFree( p->vTtElems ); + Vec_PtrFree( p->vTtNodes ); + free( p ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/lpk/lpkMap.c b/src/opt/lpk/lpkMap.c new file mode 100644 index 00000000..698aeea1 --- /dev/null +++ b/src/opt/lpk/lpkMap.c @@ -0,0 +1,205 @@ +/**CFile**************************************************************** + + FileName [lpkMap.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Fast Boolean matching for LUT structures.] + + Synopsis [] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - April 28, 2007.] + + Revision [$Id: lpkMap.c,v 1.00 2007/04/28 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "lpkInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Transforms the decomposition graph into the AIG.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +If_Obj_t * Lpk_MapPrimeInternal( If_Man_t * pIfMan, Kit_Graph_t * pGraph ) +{ + Kit_Node_t * pNode; + If_Obj_t * pAnd0, * pAnd1; + int i; + // check for constant function + if ( Kit_GraphIsConst(pGraph) ) + return If_ManConst1(pIfMan); + // check for a literal + if ( Kit_GraphIsVar(pGraph) ) + return Kit_GraphVar(pGraph)->pFunc; + // build the AIG nodes corresponding to the AND gates of the graph + Kit_GraphForEachNode( pGraph, pNode, i ) + { + pAnd0 = Kit_GraphNode(pGraph, pNode->eEdge0.Node)->pFunc; + pAnd1 = Kit_GraphNode(pGraph, pNode->eEdge1.Node)->pFunc; + pNode->pFunc = If_ManCreateAnd( pIfMan, + If_NotCond( If_Regular(pAnd0), If_IsComplement(pAnd0) ^ pNode->eEdge0.fCompl ), + If_NotCond( If_Regular(pAnd1), If_IsComplement(pAnd1) ^ pNode->eEdge1.fCompl ) ); + } + return pNode->pFunc; +} + +/**Function************************************************************* + + Synopsis [Strashes one logic node using its SOP.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +If_Obj_t * Lpk_MapPrime( Lpk_Man_t * p, unsigned * pTruth, int nVars, If_Obj_t ** ppLeaves ) +{ + Kit_Graph_t * pGraph; + Kit_Node_t * pNode; + If_Obj_t * pRes; + int i; + // derive the factored form + pGraph = Kit_TruthToGraph( pTruth, nVars, p->vCover ); + if ( pGraph == NULL ) + return NULL; + // collect the fanins + Kit_GraphForEachLeaf( pGraph, pNode, i ) + pNode->pFunc = ppLeaves[i]; + // perform strashing + pRes = Lpk_MapPrimeInternal( p->pIfMan, pGraph ); + pRes = If_NotCond( pRes, Kit_GraphIsComplement(pGraph) ); + Kit_GraphFree( pGraph ); + return pRes; +} + +/**Function************************************************************* + + Synopsis [Prepares the mapping manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +If_Obj_t * Lpk_MapTree_rec( Lpk_Man_t * p, Kit_DsdNtk_t * pNtk, If_Obj_t ** ppLeaves, int iLit, If_Obj_t * pResult ) +{ + Kit_DsdObj_t * pObj; + If_Obj_t * pObjNew = NULL, * pObjNew2 = NULL, * pFansNew[16]; + unsigned i, iLitFanin; + + assert( iLit >= 0 ); + + // consider the case of a gate + pObj = Kit_DsdNtkObj( pNtk, Kit_DsdLit2Var(iLit) ); + if ( pObj == NULL ) + { + pObjNew = ppLeaves[Kit_DsdLit2Var(iLit)]; + return If_NotCond( pObjNew, Kit_DsdLitIsCompl(iLit) ); + } + if ( pObj->Type == KIT_DSD_CONST1 ) + { + return If_NotCond( If_ManConst1(p->pIfMan), Kit_DsdLitIsCompl(iLit) ); + } + if ( pObj->Type == KIT_DSD_VAR ) + { + pObjNew = ppLeaves[Kit_DsdLit2Var(pObj->pFans[0])]; + return If_NotCond( pObjNew, Kit_DsdLitIsCompl(iLit) ^ Kit_DsdLitIsCompl(pObj->pFans[0]) ); + } + if ( pObj->Type == KIT_DSD_AND ) + { + assert( pObj->nFans == 2 ); + pFansNew[0] = Lpk_MapTree_rec( p, pNtk, ppLeaves, pObj->pFans[0], NULL ); + pFansNew[1] = pResult? pResult : Lpk_MapTree_rec( p, pNtk, ppLeaves, pObj->pFans[1], NULL ); + if ( pFansNew[0] == NULL || pFansNew[1] == NULL ) + return NULL; + pObjNew = If_ManCreateAnd( p->pIfMan, pFansNew[0], pFansNew[1] ); + return If_NotCond( pObjNew, Kit_DsdLitIsCompl(iLit) ); + } + if ( pObj->Type == KIT_DSD_XOR ) + { + int fCompl = Kit_DsdLitIsCompl(iLit); + assert( pObj->nFans == 2 ); + pFansNew[0] = Lpk_MapTree_rec( p, pNtk, ppLeaves, pObj->pFans[0], NULL ); + pFansNew[1] = pResult? pResult : Lpk_MapTree_rec( p, pNtk, ppLeaves, pObj->pFans[1], NULL ); + if ( pFansNew[0] == NULL || pFansNew[1] == NULL ) + return NULL; + fCompl ^= If_IsComplement(pFansNew[0]) ^ If_IsComplement(pFansNew[1]); + pObjNew = If_ManCreateXor( p->pIfMan, If_Regular(pFansNew[0]), If_Regular(pFansNew[1]) ); + return If_NotCond( pObjNew, fCompl ); + } + assert( pObj->Type == KIT_DSD_PRIME ); + p->nBlocks[pObj->nFans]++; + + // solve for the inputs + Kit_DsdObjForEachFanin( pNtk, pObj, iLitFanin, i ) + { + if ( i == 0 ) + pFansNew[i] = pResult? pResult : Lpk_MapTree_rec( p, pNtk, ppLeaves, iLitFanin, NULL ); + else + pFansNew[i] = Lpk_MapTree_rec( p, pNtk, ppLeaves, iLitFanin, NULL ); + if ( pFansNew[i] == NULL ) + return NULL; + } +/* + if ( !p->fCofactoring && p->pPars->nVarsShared > 0 && (int)pObj->nFans > p->pPars->nLutSize ) + { + pObjNew = Lpk_MapTreeMulti( p, Kit_DsdObjTruth(pObj), pObj->nFans, pFansNew ); + return If_NotCond( pObjNew, Kit_DsdLitIsCompl(iLit) ); + } +*/ +/* + if ( (int)pObj->nFans > p->pPars->nLutSize ) + { + pObjNew2 = Lpk_MapTreeMux_rec( p, Kit_DsdObjTruth(pObj), pObj->nFans, pFansNew ); +// if ( pObjNew2 ) +// return If_NotCond( pObjNew2, Kit_DsdLitIsCompl(iLit) ); + } +*/ + + // find best cofactoring variable + if ( p->pPars->nVarsShared > 0 && (int)pObj->nFans > p->pPars->nLutSize ) + { + pObjNew2 = Lpk_MapSuppRedDec_rec( p, Kit_DsdObjTruth(pObj), pObj->nFans, pFansNew ); + if ( pObjNew2 ) + return If_NotCond( pObjNew2, Kit_DsdLitIsCompl(iLit) ); + } + + pObjNew = Lpk_MapPrime( p, Kit_DsdObjTruth(pObj), pObj->nFans, pFansNew ); + + // add choice + if ( pObjNew && pObjNew2 ) + { + If_ObjSetChoice( If_Regular(pObjNew), If_Regular(pObjNew2) ); + If_ManCreateChoice( p->pIfMan, If_Regular(pObjNew) ); + } + return If_NotCond( pObjNew, Kit_DsdLitIsCompl(iLit) ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/lpk/lpkMulti.c b/src/opt/lpk/lpkMulti.c new file mode 100644 index 00000000..82cf3578 --- /dev/null +++ b/src/opt/lpk/lpkMulti.c @@ -0,0 +1,495 @@ +/**CFile**************************************************************** + + FileName [lpkMulti.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Fast Boolean matching for LUT structures.] + + Synopsis [] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - April 28, 2007.] + + Revision [$Id: lpkMulti.c,v 1.00 2007/04/28 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "lpkInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Records variable order.] + + Description [Increaments Order[x][y] by 1 if x should be above y in the DSD.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Lpk_CreateVarOrder( Kit_DsdNtk_t * pNtk, char pTable[][16] ) +{ + Kit_DsdObj_t * pObj; + unsigned uSuppFanins, k; + int Above[16], Below[16]; + int nAbove, nBelow, iFaninLit, i, x, y; + // iterate through the nodes + Kit_DsdNtkForEachObj( pNtk, pObj, i ) + { + // collect fanin support of this node + nAbove = 0; + uSuppFanins = 0; + Kit_DsdObjForEachFanin( pNtk, pObj, iFaninLit, k ) + { + if ( Kit_DsdLitIsLeaf( pNtk, iFaninLit ) ) + Above[nAbove++] = Kit_DsdLit2Var(iFaninLit); + else + uSuppFanins |= Kit_DsdLitSupport( pNtk, iFaninLit ); + } + // find the below variables + nBelow = 0; + for ( y = 0; y < 16; y++ ) + if ( uSuppFanins & (1 << y) ) + Below[nBelow++] = y; + // create all pairs + for ( x = 0; x < nAbove; x++ ) + for ( y = 0; y < nBelow; y++ ) + pTable[Above[x]][Below[y]]++; + } +} + +/**Function************************************************************* + + Synopsis [Creates commmon variable order.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Lpk_CreateCommonOrder( char pTable[][16], int piCofVar[], int nCBars, int pPrios[], int nVars, int fVerbose ) +{ + int Score[16] = {0}, pPres[16]; + int i, y, x, iVarBest, ScoreMax, PrioCount; + + // mark the present variables + for ( i = 0; i < nVars; i++ ) + pPres[i] = 1; + // remove cofactored variables + for ( i = 0; i < nCBars; i++ ) + pPres[piCofVar[i]] = 0; + + // compute scores for each leaf + for ( i = 0; i < nVars; i++ ) + { + if ( pPres[i] == 0 ) + continue; + for ( y = 0; y < nVars; y++ ) + Score[i] += pTable[i][y]; + for ( x = 0; x < nVars; x++ ) + Score[i] -= pTable[x][i]; + } + + // print the scores + if ( fVerbose ) + { + printf( "Scores: " ); + for ( i = 0; i < nVars; i++ ) + printf( "%c=%d ", 'a'+i, Score[i] ); + printf( " " ); + printf( "Prios: " ); + } + + // derive variable priority + // variables with equal score receive the same priority + for ( i = 0; i < nVars; i++ ) + pPrios[i] = 16; + + // iterate until variables remain + for ( PrioCount = 1; ; PrioCount++ ) + { + // find the present variable with the highest score + iVarBest = -1; + ScoreMax = -100000; + for ( i = 0; i < nVars; i++ ) + { + if ( pPres[i] == 0 ) + continue; + if ( ScoreMax < Score[i] ) + { + ScoreMax = Score[i]; + iVarBest = i; + } + } + if ( iVarBest == -1 ) + break; + // give the next priority to all vars having this score + if ( fVerbose ) + printf( "%d=", PrioCount ); + for ( i = 0; i < nVars; i++ ) + { + if ( pPres[i] == 0 ) + continue; + if ( Score[i] == ScoreMax ) + { + pPrios[i] = PrioCount; + pPres[i] = 0; + if ( fVerbose ) + printf( "%c", 'a'+i ); + } + } + if ( fVerbose ) + printf( " " ); + } + if ( fVerbose ) + printf( "\n" ); +} + +/**Function************************************************************* + + Synopsis [Finds components with the highest priority.] + + Description [Returns the number of components selected.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Lpk_FindHighest( Kit_DsdNtk_t ** ppNtks, int * piLits, int nSize, int * pPrio, int * pDecision ) +{ + Kit_DsdObj_t * pObj; + unsigned uSupps[8], uSuppFanin, uSuppTotal, uSuppLarge; + int i, pTriv[8], PrioMin, iVarMax, nComps, fOneNonTriv; + + // find individual support and total support + uSuppTotal = 0; + for ( i = 0; i < nSize; i++ ) + { + pTriv[i] = 1; + if ( piLits[i] < 0 ) + uSupps[i] = 0; + else if ( Kit_DsdLitIsLeaf(ppNtks[i], piLits[i]) ) + uSupps[i] = Kit_DsdLitSupport( ppNtks[i], piLits[i] ); + else + { + pObj = Kit_DsdNtkObj( ppNtks[i], Kit_DsdLit2Var(piLits[i]) ); + if ( pObj->Type == KIT_DSD_PRIME ) + { + pTriv[i] = 0; + uSuppFanin = Kit_DsdLitSupport( ppNtks[i], pObj->pFans[0] ); + } + else + { + assert( pObj->nFans == 2 ); + if ( !Kit_DsdLitIsLeaf(ppNtks[i], pObj->pFans[0]) ) + pTriv[i] = 0; + uSuppFanin = Kit_DsdLitSupport( ppNtks[i], pObj->pFans[1] ); + } + uSupps[i] = Kit_DsdLitSupport( ppNtks[i], piLits[i] ) & ~uSuppFanin; + } + assert( uSupps[i] <= 0xFFFF ); + uSuppTotal |= uSupps[i]; + } + if ( uSuppTotal == 0 ) + return 0; + + // find one support variable with the highest priority + PrioMin = ABC_INFINITY; + iVarMax = -1; + for ( i = 0; i < 16; i++ ) + if ( uSuppTotal & (1 << i) ) + if ( PrioMin > pPrio[i] ) + { + PrioMin = pPrio[i]; + iVarMax = i; + } + assert( iVarMax != -1 ); + + // select components, which have this variable + nComps = 0; + fOneNonTriv = 0; + uSuppLarge = 0; + for ( i = 0; i < nSize; i++ ) + if ( uSupps[i] & (1<pIfMan) ); + + // iterate over the nodes + if ( p->pPars->fVeryVerbose ) + printf( "Decision: " ); + for ( i = 0; i < nSize; i++ ) + { + if ( pDecision[i] ) + { + if ( p->pPars->fVeryVerbose ) + printf( "%d ", i ); + assert( piLits[i] >= 0 ); + pObj = Kit_DsdNtkObj( ppNtks[i], Kit_DsdLit2Var(piLits[i]) ); + if ( pObj == NULL ) + piLitsNew[i] = -2; + else if ( pObj->Type == KIT_DSD_PRIME ) + piLitsNew[i] = pObj->pFans[0]; + else + piLitsNew[i] = pObj->pFans[1]; + } + else + piLitsNew[i] = piLits[i]; + } + if ( p->pPars->fVeryVerbose ) + printf( "\n" ); + + // call again + pResPrev = Lpk_MapTreeMulti_rec( p, ppNtks, piLitsNew, piCofVar, nCBars, ppLeaves, nLeaves, pPrio ); + + // create new set of nodes + for ( i = 0; i < nSize; i++ ) + { + if ( pDecision[i] ) + pObjsNew[nCBars][i] = Lpk_MapTree_rec( p, ppNtks[i], ppLeaves, piLits[i], pResPrev ); + else if ( piLits[i] == -1 ) + pObjsNew[nCBars][i] = If_ManConst1(p->pIfMan); + else if ( piLits[i] == -2 ) + pObjsNew[nCBars][i] = If_Not( If_ManConst1(p->pIfMan) ); + else + pObjsNew[nCBars][i] = pResPrev; + } + + // create MUX using these outputs + for ( k = nCBars; k > 0; k-- ) + { + nSize /= 2; + for ( i = 0; i < nSize; i++ ) + pObjsNew[k-1][i] = If_ManCreateMux( p->pIfMan, pObjsNew[k][2*i+0], pObjsNew[k][2*i+1], ppLeaves[piCofVar[k-1]] ); + } + assert( nSize == 1 ); + return pObjsNew[0][0]; +} + +/**Function************************************************************* + + Synopsis [Prepares the mapping manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +If_Obj_t * Lpk_MapTreeMulti( Lpk_Man_t * p, unsigned * pTruth, int nVars, If_Obj_t ** ppLeaves ) +{ + static Counter = 0; + If_Obj_t * pResult; + Kit_DsdNtk_t * ppNtks[8] = {0}, * pTemp; + Kit_DsdObj_t * pRoot; + int piCofVar[4], pPrios[16], pFreqs[16] = {0}, piLits[16]; + int i, k, nCBars, nSize, nMemSize; + unsigned * ppCofs[4][8], uSupport; + char pTable[16][16] = {0}; + int fVerbose = p->pPars->fVeryVerbose; + + Counter++; +// printf( "Run %d.\n", Counter ); + + // allocate storage for cofactors + nMemSize = Kit_TruthWordNum(nVars); + ppCofs[0][0] = ALLOC( unsigned, 32 * nMemSize ); + nSize = 0; + for ( i = 0; i < 4; i++ ) + for ( k = 0; k < 8; k++ ) + ppCofs[i][k] = ppCofs[0][0] + nMemSize * nSize++; + assert( nSize == 32 ); + + // find the best cofactoring variables + nCBars = Kit_DsdCofactoring( pTruth, nVars, piCofVar, p->pPars->nVarsShared, 0 ); +// nCBars = 2; +// piCofVar[0] = 0; +// piCofVar[1] = 1; + + + // copy the function + Kit_TruthCopy( ppCofs[0][0], pTruth, nVars ); + + // decompose w.r.t. these variables + for ( k = 0; k < nCBars; k++ ) + { + nSize = (1 << k); + for ( i = 0; i < nSize; i++ ) + { + Kit_TruthCofactor0New( ppCofs[k+1][2*i+0], ppCofs[k][i], nVars, piCofVar[k] ); + Kit_TruthCofactor1New( ppCofs[k+1][2*i+1], ppCofs[k][i], nVars, piCofVar[k] ); + } + } + nSize = (1 << nCBars); + // compute DSD networks + for ( i = 0; i < nSize; i++ ) + { + ppNtks[i] = Kit_DsdDecompose( ppCofs[nCBars][i], nVars ); + ppNtks[i] = Kit_DsdExpand( pTemp = ppNtks[i] ); + Kit_DsdNtkFree( pTemp ); + if ( fVerbose ) + { + printf( "Cof%d%d: ", nCBars, i ); + Kit_DsdPrint( stdout, ppNtks[i] ); + } + } + + // compute variable frequences + for ( i = 0; i < nSize; i++ ) + { + uSupport = Kit_TruthSupport( ppCofs[nCBars][i], nVars ); + for ( k = 0; k < nVars; k++ ) + if ( uSupport & (1<pSupps[0] <= 0xFFFF ); + // undec nodes should be rotated in such a way that the first input has as many shared inputs as possible + Kit_DsdRotate( ppNtks[i], pFreqs ); + // print the resulting networks + if ( fVerbose ) + { + printf( "Cof%d%d: ", nCBars, i ); + Kit_DsdPrint( stdout, ppNtks[i] ); + } + } + + for ( i = 0; i < nSize; i++ ) + { + // collect the roots + pRoot = Kit_DsdNtkRoot(ppNtks[i]); + if ( pRoot->Type == KIT_DSD_CONST1 ) + piLits[i] = Kit_DsdLitIsCompl(ppNtks[i]->Root)? -2: -1; + else if ( pRoot->Type == KIT_DSD_VAR ) + piLits[i] = Kit_DsdLitNotCond( pRoot->pFans[0], Kit_DsdLitIsCompl(ppNtks[i]->Root) ); + else + piLits[i] = ppNtks[i]->Root; + } + + + // recursively construct AIG for mapping + p->fCofactoring = 1; + pResult = Lpk_MapTreeMulti_rec( p, ppNtks, piLits, piCofVar, nCBars, ppLeaves, nVars, pPrios ); + p->fCofactoring = 0; + + if ( fVerbose ) + printf( "\n" ); + + // verify the transformations + nSize = (1 << nCBars); + for ( i = 0; i < nSize; i++ ) + Kit_DsdTruth( ppNtks[i], ppCofs[nCBars][i] ); + // mux the truth tables + for ( k = nCBars-1; k >= 0; k-- ) + { + nSize = (1 << k); + for ( i = 0; i < nSize; i++ ) + Kit_TruthMuxVar( ppCofs[k][i], ppCofs[k+1][2*i+0], ppCofs[k+1][2*i+1], nVars, piCofVar[k] ); + } + if ( !Extra_TruthIsEqual( pTruth, ppCofs[0][0], nVars ) ) + printf( "Verification failed.\n" ); + + + // free the networks + for ( i = 0; i < 8; i++ ) + if ( ppNtks[i] ) + Kit_DsdNtkFree( ppNtks[i] ); + free( ppCofs[0][0] ); + + return pResult; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/lpk/lpkMux.c b/src/opt/lpk/lpkMux.c new file mode 100644 index 00000000..ed046ad7 --- /dev/null +++ b/src/opt/lpk/lpkMux.c @@ -0,0 +1,247 @@ +/**CFile**************************************************************** + + FileName [lpkMux.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Fast Boolean matching for LUT structures.] + + Synopsis [] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - April 28, 2007.] + + Revision [$Id: lpkMux.c,v 1.00 2007/04/28 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "lpkInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Find the best cofactoring variable.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Lpk_MapTreeBestCofVar( Lpk_Man_t * p, unsigned * pTruth, int nVars, unsigned * pCof0, unsigned * pCof1 ) +{ + int i, iBestVar, nSuppSizeCur0, nSuppSizeCur1, nSuppSizeCur, nSuppSizeMin; + // iterate through variables + iBestVar = -1; + nSuppSizeMin = KIT_INFINITY; + for ( i = 0; i < nVars; i++ ) + { + // cofactor the functiona and get support sizes + Kit_TruthCofactor0New( pCof0, pTruth, nVars, i ); + Kit_TruthCofactor1New( pCof1, pTruth, nVars, i ); + nSuppSizeCur0 = Kit_TruthSupportSize( pCof0, nVars ); + nSuppSizeCur1 = Kit_TruthSupportSize( pCof1, nVars ); + nSuppSizeCur = nSuppSizeCur0 + nSuppSizeCur1; + // skip cofactoring that goes above the limit + if ( nSuppSizeCur0 > p->pPars->nLutSize || nSuppSizeCur1 > p->pPars->nLutSize ) + continue; + // compare this variable with other variables + if ( nSuppSizeMin > nSuppSizeCur ) + { + nSuppSizeMin = nSuppSizeCur; + iBestVar = i; + } + } + // cofactor w.r.t. this variable + if ( iBestVar != -1 ) + { + Kit_TruthCofactor0New( pCof0, pTruth, nVars, iBestVar ); + Kit_TruthCofactor1New( pCof1, pTruth, nVars, iBestVar ); + } + return iBestVar; +} + +/**Function************************************************************* + + Synopsis [Maps the function by the best cofactoring.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +If_Obj_t * Lpk_MapTreeMux_rec( Lpk_Man_t * p, unsigned * pTruth, int nVars, If_Obj_t ** ppLeaves ) +{ + unsigned * pCof0 = Vec_PtrEntry( p->vTtNodes, 0 ); + unsigned * pCof1 = Vec_PtrEntry( p->vTtNodes, 1 ); + If_Obj_t * pObj0, * pObj1; + Kit_DsdNtk_t * ppNtks[2]; + int iBestVar; + assert( nVars > 3 ); + p->fCalledOnce = 1; + // cofactor w.r.t. the best variable + iBestVar = Lpk_MapTreeBestCofVar( p, pTruth, nVars, pCof0, pCof1 ); + if ( iBestVar == -1 ) + return NULL; + // decompose the functions + ppNtks[0] = Kit_DsdDecompose( pCof0, nVars ); + ppNtks[1] = Kit_DsdDecompose( pCof1, nVars ); + if ( p->pPars->fVeryVerbose ) + { + printf( "Cofactoring w.r.t. var %c (%d -> %d+%d supp vars):\n", + 'a'+iBestVar, nVars, Kit_TruthSupportSize(pCof0, nVars), Kit_TruthSupportSize(pCof1, nVars) ); + Kit_DsdPrintExpanded( ppNtks[0] ); + Kit_DsdPrintExpanded( ppNtks[1] ); + } + // map the DSD structures + pObj0 = Lpk_MapTree_rec( p, ppNtks[0], ppLeaves, ppNtks[0]->Root, NULL ); + pObj1 = Lpk_MapTree_rec( p, ppNtks[1], ppLeaves, ppNtks[1]->Root, NULL ); + Kit_DsdNtkFree( ppNtks[0] ); + Kit_DsdNtkFree( ppNtks[1] ); + return If_ManCreateMux( p->pIfMan, pObj0, pObj1, ppLeaves[iBestVar] ); +} + + + +/**Function************************************************************* + + Synopsis [Implements support-reducing decomposition.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +If_Obj_t * Lpk_MapSuppRedDec_rec( Lpk_Man_t * p, unsigned * pTruth, int nVars, If_Obj_t ** ppLeaves ) +{ + Kit_DsdNtk_t * pNtkDec, * pNtkComp, * ppNtks[2], * pTemp; + If_Obj_t * pObjNew; + unsigned * pCof0 = Vec_PtrEntry( p->vTtNodes, 0 ); + unsigned * pCof1 = Vec_PtrEntry( p->vTtNodes, 1 ); + unsigned * pDec0 = Vec_PtrEntry( p->vTtNodes, 2 ); + unsigned * pDec1 = Vec_PtrEntry( p->vTtNodes, 3 ); + unsigned * pDec = Vec_PtrEntry( p->vTtNodes, 4 ); + unsigned * pCo00 = Vec_PtrEntry( p->vTtNodes, 5 ); + unsigned * pCo01 = Vec_PtrEntry( p->vTtNodes, 6 ); + unsigned * pCo10 = Vec_PtrEntry( p->vTtNodes, 7 ); + unsigned * pCo11 = Vec_PtrEntry( p->vTtNodes, 8 ); + unsigned * pCo0 = Vec_PtrEntry( p->vTtNodes, 9 ); + unsigned * pCo1 = Vec_PtrEntry( p->vTtNodes, 10 ); + unsigned * pCo = Vec_PtrEntry( p->vTtNodes, 11 ); + int TrueMint0, TrueMint1, FalseMint0, FalseMint1; + int uSubsets, uSubset0, uSubset1, iVar, iVarReused, i; + + // determine if supp-red decomposition exists + uSubsets = Lpk_MapSuppRedDecSelect( p, pTruth, nVars, &iVar, &iVarReused ); + if ( uSubsets == 0 ) + return NULL; + p->nCalledSRed++; + + // get the cofactors + Kit_TruthCofactor0New( pCof0, pTruth, nVars, iVar ); + Kit_TruthCofactor1New( pCof1, pTruth, nVars, iVar ); + + // get the bound sets + uSubset0 = uSubsets & 0xFFFF; + uSubset1 = uSubsets >> 16; + + // compute the decomposed functions + ppNtks[0] = Kit_DsdDecompose( pCof0, nVars ); + ppNtks[1] = Kit_DsdDecompose( pCof1, nVars ); + ppNtks[0] = Kit_DsdExpand( pTemp = ppNtks[0] ); Kit_DsdNtkFree( pTemp ); + ppNtks[1] = Kit_DsdExpand( pTemp = ppNtks[1] ); Kit_DsdNtkFree( pTemp ); + Kit_DsdTruthPartial( p->pDsdMan, ppNtks[0], pDec0, uSubset0 ); + Kit_DsdTruthPartial( p->pDsdMan, ppNtks[1], pDec1, uSubset1 ); +// Kit_DsdTruthPartialTwo( p->pDsdMan, ppNtks[0], uSubset0, iVarReused, pCo0, pDec0 ); +// Kit_DsdTruthPartialTwo( p->pDsdMan, ppNtks[1], uSubset1, iVarReused, pCo1, pDec1 ); + Kit_DsdNtkFree( ppNtks[0] ); + Kit_DsdNtkFree( ppNtks[1] ); +//Kit_DsdPrintFromTruth( pDec0, nVars ); +//Kit_DsdPrintFromTruth( pDec1, nVars ); + // get the decomposed function + Kit_TruthMuxVar( pDec, pDec0, pDec1, nVars, iVar ); + + // find any true assignments of the decomposed functions + TrueMint0 = Kit_TruthFindFirstBit( pDec0, nVars ); + TrueMint1 = Kit_TruthFindFirstBit( pDec1, nVars ); + assert( TrueMint0 >= 0 && TrueMint1 >= 0 ); + // find any false assignments of the decomposed functions + FalseMint0 = Kit_TruthFindFirstZero( pDec0, nVars ); + FalseMint1 = Kit_TruthFindFirstZero( pDec1, nVars ); + assert( FalseMint0 >= 0 && FalseMint1 >= 0 ); + + // cofactor the cofactors according to these minterms + Kit_TruthCopy( pCo00, pCof0, nVars ); + Kit_TruthCopy( pCo01, pCof0, nVars ); + for ( i = 0; i < nVars; i++ ) + if ( uSubset0 & (1 << i) ) + { + if ( FalseMint0 & (1 << i) ) + Kit_TruthCofactor1( pCo00, nVars, i ); + else + Kit_TruthCofactor0( pCo00, nVars, i ); + if ( TrueMint0 & (1 << i) ) + Kit_TruthCofactor1( pCo01, nVars, i ); + else + Kit_TruthCofactor0( pCo01, nVars, i ); + } + Kit_TruthCopy( pCo10, pCof1, nVars ); + Kit_TruthCopy( pCo11, pCof1, nVars ); + for ( i = 0; i < nVars; i++ ) + if ( uSubset1 & (1 << i) ) + { + if ( FalseMint1 & (1 << i) ) + Kit_TruthCofactor1( pCo10, nVars, i ); + else + Kit_TruthCofactor0( pCo10, nVars, i ); + if ( TrueMint1 & (1 << i) ) + Kit_TruthCofactor1( pCo11, nVars, i ); + else + Kit_TruthCofactor0( pCo11, nVars, i ); + } + + // derive the functions by composing them with the new variable (iVarReused) + Kit_TruthMuxVar( pCo0, pCo00, pCo01, nVars, iVarReused ); + Kit_TruthMuxVar( pCo1, pCo10, pCo11, nVars, iVarReused ); +//Kit_DsdPrintFromTruth( pCo0, nVars ); +//Kit_DsdPrintFromTruth( pCo1, nVars ); + + // derive the composition function + Kit_TruthMuxVar( pCo , pCo0 , pCo1 , nVars, iVar ); + + // process the decomposed function + pNtkDec = Kit_DsdDecompose( pDec, nVars ); + pNtkComp = Kit_DsdDecompose( pCo, nVars ); +//Kit_DsdPrint( stdout, pNtkDec ); +//Kit_DsdPrint( stdout, pNtkComp ); +//printf( "cofactored variable %c\n", 'a' + iVar ); +//printf( "reused variable %c\n", 'a' + iVarReused ); + + ppLeaves[iVarReused] = Lpk_MapTree_rec( p, pNtkDec, ppLeaves, pNtkDec->Root, NULL ); + pObjNew = Lpk_MapTree_rec( p, pNtkComp, ppLeaves, pNtkComp->Root, NULL ); + + Kit_DsdNtkFree( pNtkDec ); + Kit_DsdNtkFree( pNtkComp ); + return pObjNew; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/lpk/lpkSets.c b/src/opt/lpk/lpkSets.c new file mode 100644 index 00000000..90e46863 --- /dev/null +++ b/src/opt/lpk/lpkSets.c @@ -0,0 +1,440 @@ +/**CFile**************************************************************** + + FileName [lpkSets.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Fast Boolean matching for LUT structures.] + + Synopsis [] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - April 28, 2007.] + + Revision [$Id: lpkSets.c,v 1.00 2007/04/28 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "lpkInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Lpk_Set_t_ Lpk_Set_t; +struct Lpk_Set_t_ +{ + char iVar; // the cofactoring variable + char Over; // the overlap in supports + char SRed; // the support reduction + char Size; // the size of the boundset + unsigned uSubset0; // the first subset (with removed) + unsigned uSubset1; // the second subset (with removed) +}; + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Recursively computes decomposable subsets.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned Lpk_ComputeSets_rec( Kit_DsdNtk_t * p, int iLit, Vec_Int_t * vSets ) +{ + unsigned i, iLitFanin, uSupport, uSuppCur; + Kit_DsdObj_t * pObj; + // consider the case of simple gate + pObj = Kit_DsdNtkObj( p, Kit_DsdLit2Var(iLit) ); + if ( pObj == NULL ) + return (1 << Kit_DsdLit2Var(iLit)); + if ( pObj->Type == KIT_DSD_AND || pObj->Type == KIT_DSD_XOR ) + { + unsigned uSupps[16], Limit, s; + uSupport = 0; + Kit_DsdObjForEachFanin( p, pObj, iLitFanin, i ) + { + uSupps[i] = Lpk_ComputeSets_rec( p, iLitFanin, vSets ); + uSupport |= uSupps[i]; + } + // create all subsets, except empty and full + Limit = (1 << pObj->nFans) - 1; + for ( s = 1; s < Limit; s++ ) + { + uSuppCur = 0; + for ( i = 0; i < pObj->nFans; i++ ) + if ( s & (1 << i) ) + uSuppCur |= uSupps[i]; + Vec_IntPush( vSets, uSuppCur ); + } + return uSupport; + } + assert( pObj->Type == KIT_DSD_PRIME ); + // get the cumulative support of all fanins + uSupport = 0; + Kit_DsdObjForEachFanin( p, pObj, iLitFanin, i ) + { + uSuppCur = Lpk_ComputeSets_rec( p, iLitFanin, vSets ); + uSupport |= uSuppCur; + Vec_IntPush( vSets, uSuppCur ); + } + return uSupport; +} + +/**Function************************************************************* + + Synopsis [Computes the set of subsets of decomposable variables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned Lpk_ComputeSets( Kit_DsdNtk_t * p, Vec_Int_t * vSets ) +{ + unsigned uSupport, Entry; + int Number, i; + assert( p->nVars <= 16 ); + Vec_IntClear( vSets ); + Vec_IntPush( vSets, 0 ); + if ( Kit_DsdNtkRoot(p)->Type == KIT_DSD_CONST1 ) + return 0; + if ( Kit_DsdNtkRoot(p)->Type == KIT_DSD_VAR ) + { + uSupport = ( 1 << Kit_DsdLit2Var(Kit_DsdNtkRoot(p)->pFans[0]) ); + Vec_IntPush( vSets, uSupport ); + return uSupport; + } + uSupport = Lpk_ComputeSets_rec( p, p->Root, vSets ); + assert( (uSupport & 0xFFFF0000) == 0 ); + Vec_IntPush( vSets, uSupport ); + // set the remaining variables + Vec_IntForEachEntry( vSets, Number, i ) + { + Entry = Number; + Vec_IntWriteEntry( vSets, i, Entry | ((uSupport & ~Entry) << 16) ); + } + return uSupport; +} + +/**Function************************************************************* + + Synopsis [Prints the sets of subsets.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static void Lpk_PrintSetOne( int uSupport ) +{ + unsigned k; + for ( k = 0; k < 16; k++ ) + if ( uSupport & (1<> 16) ); + // get the support reduction + nSuppRed = nSuppSize - 1 - nSuppOver; + // only consider support-reducing subsets + if ( nSuppRed <= 0 ) + continue; + // check if this support is already used + if ( TravId[uSupp] < nTravId ) + { + Used[nUsed++] = uSupp; + + TravId[uSupp] = nTravId; + SRed[uSupp] = nSuppRed; + Over[uSupp] = nSuppOver; + Parents[uSupp] = (k << 16) | i; + } + else if ( TravId[uSupp] == nTravId && SRed[uSupp] < nSuppRed ) + { + TravId[uSupp] = nTravId; + SRed[uSupp] = nSuppRed; + Over[uSupp] = nSuppOver; + Parents[uSupp] = (k << 16) | i; + } + } + + // find the minimum overlap + nMinOver = 1000; + for ( s = 0; s < nUsed; s++ ) + if ( nMinOver > Over[Used[s]] ) + nMinOver = Over[Used[s]]; + + + // collect the accumulated ones + for ( s = 0; s < nUsed; s++ ) + if ( Over[Used[s]] == nMinOver ) + { + // save the entry + if ( *pSize == nSizeLimit ) + return; + pEntry = pStore + (*pSize)++; + + i = Parents[Used[s]] & 0xFFFF; + k = Parents[Used[s]] >> 16; + + pEntry->uSubset0 = Vec_IntEntry(vSets0, i); + pEntry->uSubset1 = Vec_IntEntry(vSets1, k); + Entry = pEntry->uSubset0 | pEntry->uSubset1; + + // record the cofactoring variable + pEntry->iVar = iCofVar; + // set the bound set size + pEntry->Size = Kit_WordCountOnes( Entry & 0xFFFF ); + // get the number of overlapping vars + pEntry->Over = Kit_WordCountOnes( Entry & (Entry >> 16) ); + // get the support reduction + pEntry->SRed = pEntry->Size - 1 - pEntry->Over; + assert( pEntry->SRed > 0 ); + } +} + +/**Function************************************************************* + + Synopsis [Prints one set.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Lpk_MapSuppPrintSet( Lpk_Set_t * pSet, int i ) +{ + unsigned Entry; + Entry = pSet->uSubset0 | pSet->uSubset1; + printf( "%2d : ", i ); + printf( "Var = %c ", 'a' + pSet->iVar ); + printf( "Size = %2d ", pSet->Size ); + printf( "Over = %2d ", pSet->Over ); + printf( "SRed = %2d ", pSet->SRed ); + Lpk_PrintSetOne( Entry ); + printf( " " ); + Lpk_PrintSetOne( Entry >> 16 ); + printf( "\n" ); +} + +/**Function************************************************************* + + Synopsis [Evaluates the cofactors.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned Lpk_MapSuppRedDecSelect( Lpk_Man_t * p, unsigned * pTruth, int nVars, int * piVar, int * piVarReused ) +{ + static int nStoreSize = 256; + static Lpk_Set_t pStore[256], * pSet, * pSetBest; + Kit_DsdNtk_t * ppNtks[2], * pTemp; + Vec_Int_t * vSets0 = p->vSets[0]; + Vec_Int_t * vSets1 = p->vSets[1]; + unsigned * pCof0 = Vec_PtrEntry( p->vTtNodes, 0 ); + unsigned * pCof1 = Vec_PtrEntry( p->vTtNodes, 1 ); + int nSets, i, SizeMax;//, SRedMax; + unsigned Entry; + int fVerbose = p->pPars->fVeryVerbose; +// int fVerbose = 0; + + // collect decomposable subsets for each pair of cofactors + if ( fVerbose ) + { + printf( "\nExploring support-reducing bound-sets of function:\n" ); + Kit_DsdPrintFromTruth( pTruth, nVars ); + } + nSets = 0; + for ( i = 0; i < nVars; i++ ) + { + if ( fVerbose ) + printf( "Evaluating variable %c:\n", 'a'+i ); + // evaluate the cofactor pair + Kit_TruthCofactor0New( pCof0, pTruth, nVars, i ); + Kit_TruthCofactor1New( pCof1, pTruth, nVars, i ); + // decompose and expand + ppNtks[0] = Kit_DsdDecompose( pCof0, nVars ); + ppNtks[1] = Kit_DsdDecompose( pCof1, nVars ); + ppNtks[0] = Kit_DsdExpand( pTemp = ppNtks[0] ); Kit_DsdNtkFree( pTemp ); + ppNtks[1] = Kit_DsdExpand( pTemp = ppNtks[1] ); Kit_DsdNtkFree( pTemp ); + if ( fVerbose ) + Kit_DsdPrint( stdout, ppNtks[0] ); + if ( fVerbose ) + Kit_DsdPrint( stdout, ppNtks[1] ); + // compute subsets + Lpk_ComputeSets( ppNtks[0], vSets0 ); + Lpk_ComputeSets( ppNtks[1], vSets1 ); + // print subsets + if ( fVerbose ) + Lpk_PrintSets( vSets0 ); + if ( fVerbose ) + Lpk_PrintSets( vSets1 ); + // free the networks + Kit_DsdNtkFree( ppNtks[0] ); + Kit_DsdNtkFree( ppNtks[1] ); + // evaluate the pair + Lpk_ComposeSets( vSets0, vSets1, nVars, i, pStore, &nSets, nStoreSize ); + } + + // print the results + if ( fVerbose ) + printf( "\n" ); + if ( fVerbose ) + for ( i = 0; i < nSets; i++ ) + Lpk_MapSuppPrintSet( pStore + i, i ); + + // choose the best subset + SizeMax = 0; + pSetBest = NULL; + for ( i = 0; i < nSets; i++ ) + { + pSet = pStore + i; + if ( pSet->Size > p->pPars->nLutSize - 1 ) + continue; + if ( SizeMax < pSet->Size ) + { + pSetBest = pSet; + SizeMax = pSet->Size; + } + } +/* + // if the best is not choosen, select the one with largest reduction + SRedMax = 0; + if ( pSetBest == NULL ) + { + for ( i = 0; i < nSets; i++ ) + { + pSet = pStore + i; + if ( SRedMax < pSet->SRed ) + { + pSetBest = pSet; + SRedMax = pSet->SRed; + } + } + } +*/ + if ( pSetBest == NULL ) + { + if ( fVerbose ) + printf( "Could not select a subset.\n" ); + return 0; + } + else + { + if ( fVerbose ) + printf( "Selected the following subset:\n" ); + if ( fVerbose ) + Lpk_MapSuppPrintSet( pSetBest, pSetBest - pStore ); + } + + // prepare the return result + // get the remaining variables + Entry = ((pSetBest->uSubset0 >> 16) | (pSetBest->uSubset1 >> 16)); + // get the variables to be removed + Entry = Kit_BitMask(nVars) & ~(1<iVar) & ~Entry; + // make sure there are some - otherwise it is not supp-red + assert( Entry ); + // remember the first such variable + *piVarReused = Kit_WordFindFirstBit( Entry ); + *piVar = pSetBest->iVar; + return (pSetBest->uSubset1 << 16) | (pSetBest->uSubset0 & 0xFFFF); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/lpk/lpk_.c b/src/opt/lpk/lpk_.c new file mode 100644 index 00000000..d8555e08 --- /dev/null +++ b/src/opt/lpk/lpk_.c @@ -0,0 +1,48 @@ +/**CFile**************************************************************** + + FileName [lpk_.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Fast Boolean matching for LUT structures.] + + Synopsis [] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - April 28, 2007.] + + Revision [$Id: lpk_.c,v 1.00 2007/04/28 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "lpkInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/lpk/module.make b/src/opt/lpk/module.make new file mode 100644 index 00000000..26a54894 --- /dev/null +++ b/src/opt/lpk/module.make @@ -0,0 +1,11 @@ +SRC += src/opt/lpk/lpkCore.c \ + src/opt/lpk/lpkAbcDec.c \ + src/opt/lpk/lpkAbcMux.c \ + src/opt/lpk/lpkAbcDsd.c \ + src/opt/lpk/lpkAbcUtil.c \ + src/opt/lpk/lpkCut.c \ + src/opt/lpk/lpkMan.c \ + src/opt/lpk/lpkMap.c \ + src/opt/lpk/lpkMulti.c \ + src/opt/lpk/lpkMux.c \ + src/opt/lpk/lpkSets.c diff --git a/src/opt/res/module.make b/src/opt/res/module.make new file mode 100644 index 00000000..52d8a315 --- /dev/null +++ b/src/opt/res/module.make @@ -0,0 +1,7 @@ +SRC += src/opt/res/resCore.c \ + src/opt/res/resDivs.c \ + src/opt/res/resFilter.c \ + src/opt/res/resSat.c \ + src/opt/res/resSim.c \ + src/opt/res/resStrash.c \ + src/opt/res/resWin.c diff --git a/src/opt/res/res.h b/src/opt/res/res.h new file mode 100644 index 00000000..3c3431bf --- /dev/null +++ b/src/opt/res/res.h @@ -0,0 +1,75 @@ +/**CFile**************************************************************** + + FileName [res.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Resynthesis package.] + + Synopsis [External declarations.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - January 15, 2007.] + + Revision [$Id: res.h,v 1.00 2007/01/15 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef __RES_H__ +#define __RES_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// BASIC TYPES /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Res_Par_t_ Res_Par_t; +struct Res_Par_t_ +{ + // general parameters + int nWindow; // window size + int nGrowthLevel; // the maximum allowed growth in level after one iteration of resynthesis + int nSimWords; // the number of simulation words + int nCands; // the number of candidates to try + int fArea; // performs optimization for area + int fDelay; // performs optimization for delay + int fVerbose; // enable basic stats + int fVeryVerbose; // enable detailed stats +}; + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +/*=== resCore.c ==========================================================*/ +extern int Abc_NtkResynthesize( Abc_Ntk_t * pNtk, Res_Par_t * pPars ); + + +#ifdef __cplusplus +} +#endif + +#endif + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + diff --git a/src/opt/res/resCore.c b/src/opt/res/resCore.c new file mode 100644 index 00000000..27e9b3ea --- /dev/null +++ b/src/opt/res/resCore.c @@ -0,0 +1,415 @@ +/**CFile**************************************************************** + + FileName [resCore.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Resynthesis package.] + + Synopsis [Top-level resynthesis procedure.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - January 15, 2007.] + + Revision [$Id: resCore.c,v 1.00 2007/01/15 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "resInt.h" +#include "kit.h" +#include "satStore.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Res_Man_t_ Res_Man_t; +struct Res_Man_t_ +{ + // general parameters + Res_Par_t * pPars; + // specialized manager + Res_Win_t * pWin; // windowing manager + Abc_Ntk_t * pAig; // the strashed window + Res_Sim_t * pSim; // simulation manager + Sto_Man_t * pCnf; // the CNF of the SAT problem + Int_Man_t * pMan; // interpolation manager; + Vec_Int_t * vMem; // memory for intermediate SOPs + Vec_Vec_t * vResubs; // resubstitution candidates of the AIG + Vec_Vec_t * vResubsW; // resubstitution candidates of the window + Vec_Vec_t * vLevels; // levelized structure for updating + // statistics + int nWins; // the number of windows tried + int nWinNodes; // the total number of window nodes + int nDivNodes; // the total number of divisors + int nWinsTriv; // the total number of trivial windows + int nWinsUsed; // the total number of useful windows (with at least one candidate) + int nConstsUsed; // the total number of constant nodes under ODC + int nCandSets; // the total number of candidates + int nProvedSets; // the total number of proved groups + int nSimEmpty; // the empty simulation info + int nTotalNets; // the total number of nets + int nTotalNodes; // the total number of nodess + int nTotalNets2; // the total number of nets + int nTotalNodes2; // the total number of nodess + // runtime + int timeWin; // windowing + int timeDiv; // divisors + int timeAig; // strashing + int timeSim; // simulation + int timeCand; // resubstitution candidates + int timeSatTotal; // SAT solving total + int timeSatSat; // SAT solving (sat calls) + int timeSatUnsat; // SAT solving (unsat calls) + int timeSatSim; // SAT solving (simulation) + int timeInt; // interpolation + int timeUpd; // updating + int timeTotal; // total runtime +}; + +extern Hop_Obj_t * Kit_GraphToHop( Hop_Man_t * pMan, Kit_Graph_t * pGraph ); + +extern int s_ResynTime; + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Allocate resynthesis manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Res_Man_t * Res_ManAlloc( Res_Par_t * pPars ) +{ + Res_Man_t * p; + p = ALLOC( Res_Man_t, 1 ); + memset( p, 0, sizeof(Res_Man_t) ); + assert( pPars->nWindow > 0 && pPars->nWindow < 100 ); + assert( pPars->nCands > 0 && pPars->nCands < 100 ); + p->pPars = pPars; + p->pWin = Res_WinAlloc(); + p->pSim = Res_SimAlloc( pPars->nSimWords ); + p->pMan = Int_ManAlloc( 512 ); + p->vMem = Vec_IntAlloc( 0 ); + p->vResubs = Vec_VecStart( pPars->nCands ); + p->vResubsW = Vec_VecStart( pPars->nCands ); + p->vLevels = Vec_VecStart( 32 ); + return p; +} + +/**Function************************************************************* + + Synopsis [Deallocate resynthesis manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_ManFree( Res_Man_t * p ) +{ + if ( p->pPars->fVerbose ) + { + printf( "Reduction in nodes = %5d. (%.2f %%) ", + p->nTotalNodes-p->nTotalNodes2, + 100.0*(p->nTotalNodes-p->nTotalNodes2)/p->nTotalNodes ); + printf( "Reduction in edges = %5d. (%.2f %%) ", + p->nTotalNets-p->nTotalNets2, + 100.0*(p->nTotalNets-p->nTotalNets2)/p->nTotalNets ); + printf( "\n" ); + + printf( "Winds = %d. ", p->nWins ); + printf( "Nodes = %d. (Ave = %5.1f) ", p->nWinNodes, 1.0*p->nWinNodes/p->nWins ); + printf( "Divs = %d. (Ave = %5.1f) ", p->nDivNodes, 1.0*p->nDivNodes/p->nWins ); + printf( "\n" ); + printf( "WinsTriv = %d. ", p->nWinsTriv ); + printf( "SimsEmpt = %d. ", p->nSimEmpty ); + printf( "Const = %d. ", p->nConstsUsed ); + printf( "WindUsed = %d. ", p->nWinsUsed ); + printf( "Cands = %d. ", p->nCandSets ); + printf( "Proved = %d.", p->nProvedSets ); + printf( "\n" ); + + PRTP( "Windowing ", p->timeWin, p->timeTotal ); + PRTP( "Divisors ", p->timeDiv, p->timeTotal ); + PRTP( "Strashing ", p->timeAig, p->timeTotal ); + PRTP( "Simulation ", p->timeSim, p->timeTotal ); + PRTP( "Candidates ", p->timeCand, p->timeTotal ); + PRTP( "SAT solver ", p->timeSatTotal, p->timeTotal ); + PRTP( " sat ", p->timeSatSat, p->timeTotal ); + PRTP( " unsat ", p->timeSatUnsat, p->timeTotal ); + PRTP( " simul ", p->timeSatSim, p->timeTotal ); + PRTP( "Interpol ", p->timeInt, p->timeTotal ); + PRTP( "Undating ", p->timeUpd, p->timeTotal ); + PRTP( "TOTAL ", p->timeTotal, p->timeTotal ); + } + Res_WinFree( p->pWin ); + if ( p->pAig ) Abc_NtkDelete( p->pAig ); + Res_SimFree( p->pSim ); + if ( p->pCnf ) Sto_ManFree( p->pCnf ); + Int_ManFree( p->pMan ); + Vec_IntFree( p->vMem ); + Vec_VecFree( p->vResubs ); + Vec_VecFree( p->vResubsW ); + Vec_VecFree( p->vLevels ); + free( p ); +} + +/**Function************************************************************* + + Synopsis [Incrementally updates level of the nodes.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_UpdateNetwork( Abc_Obj_t * pObj, Vec_Ptr_t * vFanins, Hop_Obj_t * pFunc, Vec_Vec_t * vLevels ) +{ + Abc_Obj_t * pObjNew, * pFanin; + int k; + // create the new node + pObjNew = Abc_NtkCreateNode( pObj->pNtk ); + pObjNew->pData = pFunc; + Vec_PtrForEachEntry( vFanins, pFanin, k ) + Abc_ObjAddFanin( pObjNew, pFanin ); + // replace the old node by the new node + // update the level of the node + Abc_NtkUpdate( pObj, pObjNew, vLevels ); +} + +/**Function************************************************************* + + Synopsis [Entrace into the resynthesis package.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkResynthesize( Abc_Ntk_t * pNtk, Res_Par_t * pPars ) +{ + ProgressBar * pProgress; + Res_Man_t * p; + Abc_Obj_t * pObj; + Hop_Obj_t * pFunc; + Kit_Graph_t * pGraph; + Vec_Ptr_t * vFanins; + unsigned * puTruth; + int i, k, RetValue, nNodesOld, nFanins, nFaninsMax; + int clk, clkTotal = clock(); + + // start the manager + p = Res_ManAlloc( pPars ); + p->nTotalNets = Abc_NtkGetTotalFanins(pNtk); + p->nTotalNodes = Abc_NtkNodeNum(pNtk); + nFaninsMax = Abc_NtkGetFaninMax(pNtk); + + // perform the network sweep + Abc_NtkSweep( pNtk, 0 ); + + // convert into the AIG + if ( !Abc_NtkToAig(pNtk) ) + { + fprintf( stdout, "Converting to BDD has failed.\n" ); + Res_ManFree( p ); + return 0; + } + assert( Abc_NtkHasAig(pNtk) ); + + // set the number of levels + Abc_NtkLevel( pNtk ); + Abc_NtkStartReverseLevels( pNtk, pPars->nGrowthLevel ); + + // try resynthesizing nodes in the topological order + nNodesOld = Abc_NtkObjNumMax(pNtk); + pProgress = Extra_ProgressBarStart( stdout, nNodesOld ); + Abc_NtkForEachObj( pNtk, pObj, i ) + { + Extra_ProgressBarUpdate( pProgress, i, NULL ); + if ( !Abc_ObjIsNode(pObj) ) + continue; + if ( pObj->Id > nNodesOld ) + break; + + // create the window for this node +clk = clock(); + RetValue = Res_WinCompute( pObj, p->pPars->nWindow/10, p->pPars->nWindow%10, p->pWin ); +p->timeWin += clock() - clk; + if ( !RetValue ) + continue; + p->nWinsTriv += Res_WinIsTrivial( p->pWin ); + + if ( p->pPars->fVeryVerbose ) + { + printf( "%5d (lev=%2d) : ", pObj->Id, pObj->Level ); + printf( "Win = %3d/%3d/%4d/%3d ", + Vec_PtrSize(p->pWin->vLeaves), + Vec_PtrSize(p->pWin->vBranches), + Vec_PtrSize(p->pWin->vNodes), + Vec_PtrSize(p->pWin->vRoots) ); + } + + // collect the divisors +clk = clock(); + Res_WinDivisors( p->pWin, Abc_ObjRequiredLevel(pObj) - 1 ); +p->timeDiv += clock() - clk; + + p->nWins++; + p->nWinNodes += Vec_PtrSize(p->pWin->vNodes); + p->nDivNodes += Vec_PtrSize( p->pWin->vDivs); + + if ( p->pPars->fVeryVerbose ) + { + printf( "D = %3d ", Vec_PtrSize(p->pWin->vDivs) ); + printf( "D+ = %3d ", p->pWin->nDivsPlus ); + } + + // create the AIG for the window +clk = clock(); + if ( p->pAig ) Abc_NtkDelete( p->pAig ); + p->pAig = Res_WndStrash( p->pWin ); +p->timeAig += clock() - clk; + + if ( p->pPars->fVeryVerbose ) + { + printf( "AIG = %4d ", Abc_NtkNodeNum(p->pAig) ); + printf( "\n" ); + } + + // prepare simulation info +clk = clock(); + RetValue = Res_SimPrepare( p->pSim, p->pAig, Vec_PtrSize(p->pWin->vLeaves), 0 ); //p->pPars->fVerbose ); +p->timeSim += clock() - clk; + if ( !RetValue ) + { + p->nSimEmpty++; + continue; + } + + // consider the case of constant node + if ( p->pSim->fConst0 || p->pSim->fConst1 ) + { + p->nConstsUsed++; + + pFunc = p->pSim->fConst1? Hop_ManConst1(pNtk->pManFunc) : Hop_ManConst0(pNtk->pManFunc); + vFanins = Vec_VecEntry( p->vResubsW, 0 ); + Vec_PtrClear( vFanins ); + Res_UpdateNetwork( pObj, vFanins, pFunc, p->vLevels ); + continue; + } + +// printf( " " ); + + // find resub candidates for the node +clk = clock(); + if ( p->pPars->fArea ) + RetValue = Res_FilterCandidates( p->pWin, p->pAig, p->pSim, p->vResubs, p->vResubsW, nFaninsMax, 1 ); + else + RetValue = Res_FilterCandidates( p->pWin, p->pAig, p->pSim, p->vResubs, p->vResubsW, nFaninsMax, 0 ); +p->timeCand += clock() - clk; + p->nCandSets += RetValue; + if ( RetValue == 0 ) + continue; + +// printf( "%d(%d) ", Vec_PtrSize(p->pWin->vDivs), RetValue ); + + p->nWinsUsed++; + + // iterate through candidate resubstitutions + Vec_VecForEachLevel( p->vResubs, vFanins, k ) + { + if ( Vec_PtrSize(vFanins) == 0 ) + break; + + // solve the SAT problem and get clauses +clk = clock(); + if ( p->pCnf ) Sto_ManFree( p->pCnf ); + p->pCnf = Res_SatProveUnsat( p->pAig, vFanins ); + if ( p->pCnf == NULL ) + { +p->timeSatSat += clock() - clk; +// printf( " Sat\n" ); +// printf( "-" ); + continue; + } +p->timeSatUnsat += clock() - clk; +// printf( "+" ); + + p->nProvedSets++; +// printf( " Unsat\n" ); +// continue; +// printf( "Proved %d.\n", k ); + + // write it into a file +// Sto_ManDumpClauses( p->pCnf, "trace.cnf" ); + + // interpolate the problem if it was UNSAT +clk = clock(); + nFanins = Int_ManInterpolate( p->pMan, p->pCnf, 0, &puTruth ); +p->timeInt += clock() - clk; + if ( nFanins != Vec_PtrSize(vFanins) - 2 ) + continue; + assert( puTruth ); +// Extra_PrintBinary( stdout, puTruth, 1 << nFanins ); printf( "\n" ); + + // transform interpolant into the AIG + pGraph = Kit_TruthToGraph( puTruth, nFanins, p->vMem ); + + // derive the AIG for the decomposition tree + pFunc = Kit_GraphToHop( pNtk->pManFunc, pGraph ); + Kit_GraphFree( pGraph ); + + // update the network +clk = clock(); + Res_UpdateNetwork( pObj, Vec_VecEntry(p->vResubsW, k), pFunc, p->vLevels ); +p->timeUpd += clock() - clk; + break; + } +// printf( "\n" ); + } + Extra_ProgressBarStop( pProgress ); + Abc_NtkStopReverseLevels( pNtk ); + +p->timeSatSim += p->pSim->timeSat; +p->timeSatTotal = p->timeSatSat + p->timeSatUnsat + p->timeSatSim; + + p->nTotalNets2 = Abc_NtkGetTotalFanins(pNtk); + p->nTotalNodes2 = Abc_NtkNodeNum(pNtk); + + // quit resubstitution manager +p->timeTotal = clock() - clkTotal; + Res_ManFree( p ); + +s_ResynTime += clock() - clkTotal; + // check the resulting network + if ( !Abc_NtkCheck( pNtk ) ) + { + fprintf( stdout, "Abc_NtkResynthesize(): Network check has failed.\n" ); + return 0; + } + return 1; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/res/resDivs.c b/src/opt/res/resDivs.c new file mode 100644 index 00000000..cc75b90f --- /dev/null +++ b/src/opt/res/resDivs.c @@ -0,0 +1,285 @@ +/**CFile**************************************************************** + + FileName [resDivs.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Resynthesis package.] + + Synopsis [Collect divisors for the given window.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - January 15, 2007.] + + Revision [$Id: resDivs.c,v 1.00 2007/01/15 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "resInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static void Res_WinMarkTfi( Res_Win_t * p ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Adds candidate divisors of the node to its window.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_WinDivisors( Res_Win_t * p, int nLevDivMax ) +{ + Abc_Obj_t * pObj, * pFanout, * pFanin; + int k, f, m; + + // set the maximum level of the divisors + p->nLevDivMax = nLevDivMax; + + // mark the TFI with the current trav ID + Abc_NtkIncrementTravId( p->pNode->pNtk ); + Res_WinMarkTfi( p ); + + // mark with the current trav ID those nodes that should not be divisors: + // (1) the node and its TFO + // (2) the MFFC of the node + // (3) the node's fanins (these are treated as a special case) + Abc_NtkIncrementTravId( p->pNode->pNtk ); + Res_WinSweepLeafTfo_rec( p->pNode, p->nLevDivMax ); + Res_WinVisitMffc( p->pNode ); + Abc_ObjForEachFanin( p->pNode, pObj, k ) + Abc_NodeSetTravIdCurrent( pObj ); + + // at this point the nodes are marked with two trav IDs: + // nodes to be collected as divisors are marked with previous trav ID + // nodes to be avoided as divisors are marked with current trav ID + + // start collecting the divisors + Vec_PtrClear( p->vDivs ); + Vec_PtrForEachEntry( p->vLeaves, pObj, k ) + { + assert( (int)pObj->Level >= p->nLevLeafMin ); + if ( !Abc_NodeIsTravIdPrevious(pObj) ) + continue; + if ( (int)pObj->Level > p->nLevDivMax ) + continue; + Vec_PtrPush( p->vDivs, pObj ); + } + // add the internal nodes to the data structure + Vec_PtrForEachEntry( p->vNodes, pObj, k ) + { + if ( !Abc_NodeIsTravIdPrevious(pObj) ) + continue; + if ( (int)pObj->Level > p->nLevDivMax ) + continue; + Vec_PtrPush( p->vDivs, pObj ); + } + + // explore the fanouts of already collected divisors + p->nDivsPlus = 0; + Vec_PtrForEachEntry( p->vDivs, pObj, k ) + { + // consider fanouts of this node + Abc_ObjForEachFanout( pObj, pFanout, f ) + { + // stop if there are too many fanouts + if ( f > 20 ) + break; + // skip nodes that are already added + if ( Abc_NodeIsTravIdPrevious(pFanout) ) + continue; + // skip nodes in the TFO or in the MFFC of node + if ( Abc_NodeIsTravIdCurrent(pFanout) ) + continue; + // skip COs + if ( !Abc_ObjIsNode(pFanout) ) + continue; + // skip nodes with large level + if ( (int)pFanout->Level >= p->nLevDivMax ) + continue; + // skip nodes whose fanins are not divisors + Abc_ObjForEachFanin( pFanout, pFanin, m ) + if ( !Abc_NodeIsTravIdPrevious(pFanin) ) + break; + if ( m < Abc_ObjFaninNum(pFanout) ) + continue; + // add the node to the divisors + Vec_PtrPush( p->vDivs, pFanout ); + Vec_PtrPush( p->vNodes, pFanout ); + Abc_NodeSetTravIdPrevious( pFanout ); + p->nDivsPlus++; + } + } +/* + printf( "Node level = %d. ", Abc_ObjLevel(p->pNode) ); + Vec_PtrForEachEntryStart( p->vDivs, pObj, k, Vec_PtrSize(p->vDivs)-p->nDivsPlus ) + printf( "%d ", Abc_ObjLevel(pObj) ); + printf( "\n" ); +*/ +//printf( "%d ", p->nDivsPlus ); +} + +/**Function************************************************************* + + Synopsis [Marks the TFI cone of the node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_WinMarkTfi_rec( Res_Win_t * p, Abc_Obj_t * pObj ) +{ + Abc_Obj_t * pFanin; + int i; + if ( Abc_NodeIsTravIdCurrent(pObj) ) + return; + Abc_NodeSetTravIdCurrent( pObj ); + assert( Abc_ObjIsNode(pObj) ); + // visit the fanins of the node + Abc_ObjForEachFanin( pObj, pFanin, i ) + Res_WinMarkTfi_rec( p, pFanin ); +} + +/**Function************************************************************* + + Synopsis [Marks the TFI cone of the node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_WinMarkTfi( Res_Win_t * p ) +{ + Abc_Obj_t * pObj; + int i; + // mark the leaves + Vec_PtrForEachEntry( p->vLeaves, pObj, i ) + Abc_NodeSetTravIdCurrent( pObj ); + // start from the node + Res_WinMarkTfi_rec( p, p->pNode ); +} + +/**Function************************************************************* + + Synopsis [Marks the TFO of the collected nodes up to the given level.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_WinSweepLeafTfo_rec( Abc_Obj_t * pObj, int nLevelLimit ) +{ + Abc_Obj_t * pFanout; + int i; + if ( Abc_ObjIsCo(pObj) || (int)pObj->Level > nLevelLimit ) + return; + if ( Abc_NodeIsTravIdCurrent(pObj) ) + return; + Abc_NodeSetTravIdCurrent( pObj ); + Abc_ObjForEachFanout( pObj, pFanout, i ) + Res_WinSweepLeafTfo_rec( pFanout, nLevelLimit ); +} + +/**Function************************************************************* + + Synopsis [Dereferences the node's MFFC.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Res_NodeDeref_rec( Abc_Obj_t * pNode ) +{ + Abc_Obj_t * pFanin; + int i, Counter = 1; + if ( Abc_ObjIsCi(pNode) ) + return 0; + Abc_NodeSetTravIdCurrent( pNode ); + Abc_ObjForEachFanin( pNode, pFanin, i ) + { + assert( pFanin->vFanouts.nSize > 0 ); + if ( --pFanin->vFanouts.nSize == 0 ) + Counter += Res_NodeDeref_rec( pFanin ); + } + return Counter; +} + +/**Function************************************************************* + + Synopsis [References the node's MFFC.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Res_NodeRef_rec( Abc_Obj_t * pNode ) +{ + Abc_Obj_t * pFanin; + int i, Counter = 1; + if ( Abc_ObjIsCi(pNode) ) + return 0; + Abc_ObjForEachFanin( pNode, pFanin, i ) + { + if ( pFanin->vFanouts.nSize++ == 0 ) + Counter += Res_NodeRef_rec( pFanin ); + } + return Counter; +} + +/**Function************************************************************* + + Synopsis [Labels MFFC of the node with the current trav ID.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Res_WinVisitMffc( Abc_Obj_t * pNode ) +{ + int Count1, Count2; + assert( Abc_ObjIsNode(pNode) ); + // dereference the node (mark with the current trav ID) + Count1 = Res_NodeDeref_rec( pNode ); + // reference it back + Count2 = Res_NodeRef_rec( pNode ); + assert( Count1 == Count2 ); + return Count1; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/res/resFilter.c b/src/opt/res/resFilter.c new file mode 100644 index 00000000..f2ca41d3 --- /dev/null +++ b/src/opt/res/resFilter.c @@ -0,0 +1,434 @@ +/**CFile**************************************************************** + + FileName [resFilter.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Resynthesis package.] + + Synopsis [Filtering resubstitution candidates.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - January 15, 2007.] + + Revision [$Id: resFilter.c,v 1.00 2007/01/15 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "resInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static unsigned * Res_FilterCollectFaninInfo( Res_Win_t * pWin, Res_Sim_t * pSim, unsigned uMask ); +static int Res_FilterCriticalFanin( Abc_Obj_t * pNode ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Finds sets of feasible candidates.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Res_FilterCandidates( Res_Win_t * pWin, Abc_Ntk_t * pAig, Res_Sim_t * pSim, Vec_Vec_t * vResubs, Vec_Vec_t * vResubsW, int nFaninsMax, int fArea ) +{ + Abc_Obj_t * pFanin, * pFanin2, * pFaninTemp; + unsigned * pInfo, * pInfoDiv, * pInfoDiv2; + int Counter, RetValue, i, i2, d, d2, iDiv, iDiv2, k; + + // check that the info the node is one + pInfo = Vec_PtrEntry( pSim->vOuts, 1 ); + RetValue = Abc_InfoIsOne( pInfo, pSim->nWordsOut ); + if ( RetValue == 0 ) + { +// printf( "Failed 1!\n" ); + return 0; + } + + // collect the fanin info + pInfo = Res_FilterCollectFaninInfo( pWin, pSim, ~0 ); + RetValue = Abc_InfoIsOne( pInfo, pSim->nWordsOut ); + if ( RetValue == 0 ) + { +// printf( "Failed 2!\n" ); + return 0; + } + + // try removing each fanin +// printf( "Fanins: " ); + Counter = 0; + Vec_VecClear( vResubs ); + Vec_VecClear( vResubsW ); + Abc_ObjForEachFanin( pWin->pNode, pFanin, i ) + { + if ( fArea && Abc_ObjFanoutNum(pFanin) > 1 ) + continue; + // get simulation info without this fanin + pInfo = Res_FilterCollectFaninInfo( pWin, pSim, ~(1 << i) ); + RetValue = Abc_InfoIsOne( pInfo, pSim->nWordsOut ); + if ( RetValue ) + { +// printf( "Node %4d. Candidate fanin %4d.\n", pWin->pNode->Id, pFanin->Id ); + // collect the nodes + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,0) ); + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,1) ); + Abc_ObjForEachFanin( pWin->pNode, pFaninTemp, k ) + { + if ( k != i ) + { + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,2+k) ); + Vec_VecPush( vResubsW, Counter, pFaninTemp ); + } + } + Counter++; + if ( Counter == Vec_VecSize(vResubs) ) + return Counter; + } + } + + // try replacing each critical fanin by a non-critical fanin + Abc_ObjForEachFanin( pWin->pNode, pFanin, i ) + { + if ( Abc_ObjFanoutNum(pFanin) > 1 ) + continue; + // get simulation info without this fanin + pInfo = Res_FilterCollectFaninInfo( pWin, pSim, ~(1 << i) ); + // go over the set of divisors + for ( d = Abc_ObjFaninNum(pWin->pNode) + 2; d < Abc_NtkPoNum(pAig); d++ ) + { + pInfoDiv = Vec_PtrEntry( pSim->vOuts, d ); + iDiv = d - (Abc_ObjFaninNum(pWin->pNode) + 2); + if ( !Abc_InfoIsOrOne( pInfo, pInfoDiv, pSim->nWordsOut ) ) + continue; + // collect the nodes + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,0) ); + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,1) ); + // collect the remaning fanins and the divisor + Abc_ObjForEachFanin( pWin->pNode, pFaninTemp, k ) + { + if ( k != i ) + { + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,2+k) ); + Vec_VecPush( vResubsW, Counter, pFaninTemp ); + } + } + // collect the divisor + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,d) ); + Vec_VecPush( vResubsW, Counter, Vec_PtrEntry(pWin->vDivs, iDiv) ); + Counter++; + if ( Counter == Vec_VecSize(vResubs) ) + return Counter; + } + } + + // consider the case when two fanins can be added instead of one + if ( Abc_ObjFaninNum(pWin->pNode) < nFaninsMax ) + { + // try to replace each critical fanin by two non-critical fanins + Abc_ObjForEachFanin( pWin->pNode, pFanin, i ) + { + if ( Abc_ObjFanoutNum(pFanin) > 1 ) + continue; + // get simulation info without this fanin + pInfo = Res_FilterCollectFaninInfo( pWin, pSim, ~(1 << i) ); + // go over the set of divisors + for ( d = Abc_ObjFaninNum(pWin->pNode) + 2; d < Abc_NtkPoNum(pAig); d++ ) + { + pInfoDiv = Vec_PtrEntry( pSim->vOuts, d ); + iDiv = d - (Abc_ObjFaninNum(pWin->pNode) + 2); + // go through the second divisor + for ( d2 = d + 1; d2 < Abc_NtkPoNum(pAig); d2++ ) + { + pInfoDiv2 = Vec_PtrEntry( pSim->vOuts, d2 ); + iDiv2 = d2 - (Abc_ObjFaninNum(pWin->pNode) + 2); + if ( !Abc_InfoIsOrOne3( pInfo, pInfoDiv, pInfoDiv2, pSim->nWordsOut ) ) + continue; + // collect the nodes + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,0) ); + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,1) ); + // collect the remaning fanins and the divisor + Abc_ObjForEachFanin( pWin->pNode, pFaninTemp, k ) + { + if ( k != i ) + { + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,2+k) ); + Vec_VecPush( vResubsW, Counter, pFaninTemp ); + } + } + // collect the divisor + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,d) ); + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,d2) ); + Vec_VecPush( vResubsW, Counter, Vec_PtrEntry(pWin->vDivs, iDiv) ); + Vec_VecPush( vResubsW, Counter, Vec_PtrEntry(pWin->vDivs, iDiv2) ); + Counter++; + if ( Counter == Vec_VecSize(vResubs) ) + return Counter; + } + } + } + } + + // try to replace two nets by one + if ( !fArea ) + { + Abc_ObjForEachFanin( pWin->pNode, pFanin, i ) + { + for ( i2 = i + 1; i2 < Abc_ObjFaninNum(pWin->pNode); i2++ ) + { + pFanin2 = Abc_ObjFanin(pWin->pNode, i2); + // get simulation info without these fanins + pInfo = Res_FilterCollectFaninInfo( pWin, pSim, (~(1 << i)) & (~(1 << i2)) ); + // go over the set of divisors + for ( d = Abc_ObjFaninNum(pWin->pNode) + 2; d < Abc_NtkPoNum(pAig); d++ ) + { + pInfoDiv = Vec_PtrEntry( pSim->vOuts, d ); + iDiv = d - (Abc_ObjFaninNum(pWin->pNode) + 2); + if ( !Abc_InfoIsOrOne( pInfo, pInfoDiv, pSim->nWordsOut ) ) + continue; + // collect the nodes + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,0) ); + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,1) ); + // collect the remaning fanins and the divisor + Abc_ObjForEachFanin( pWin->pNode, pFaninTemp, k ) + { + if ( k != i && k != i2 ) + { + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,2+k) ); + Vec_VecPush( vResubsW, Counter, pFaninTemp ); + } + } + // collect the divisor + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,d) ); + Vec_VecPush( vResubsW, Counter, Vec_PtrEntry(pWin->vDivs, iDiv) ); + Counter++; + if ( Counter == Vec_VecSize(vResubs) ) + return Counter; + } + } + } + } + return Counter; +} + + +/**Function************************************************************* + + Synopsis [Finds sets of feasible candidates.] + + Description [This procedure is a special case of the above.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Res_FilterCandidatesArea( Res_Win_t * pWin, Abc_Ntk_t * pAig, Res_Sim_t * pSim, Vec_Vec_t * vResubs, Vec_Vec_t * vResubsW, int nFaninsMax ) +{ + Abc_Obj_t * pFanin; + unsigned * pInfo, * pInfoDiv, * pInfoDiv2; + int Counter, RetValue, d, d2, k, iDiv, iDiv2, iBest; + + // check that the info the node is one + pInfo = Vec_PtrEntry( pSim->vOuts, 1 ); + RetValue = Abc_InfoIsOne( pInfo, pSim->nWordsOut ); + if ( RetValue == 0 ) + { +// printf( "Failed 1!\n" ); + return 0; + } + + // collect the fanin info + pInfo = Res_FilterCollectFaninInfo( pWin, pSim, ~0 ); + RetValue = Abc_InfoIsOne( pInfo, pSim->nWordsOut ); + if ( RetValue == 0 ) + { +// printf( "Failed 2!\n" ); + return 0; + } + + // try removing fanins +// printf( "Fanins: " ); + Counter = 0; + Vec_VecClear( vResubs ); + Vec_VecClear( vResubsW ); + // get the best fanins + iBest = Res_FilterCriticalFanin( pWin->pNode ); + if ( iBest == -1 ) + return 0; + + // get the info without the critical fanin + pInfo = Res_FilterCollectFaninInfo( pWin, pSim, ~(1 << iBest) ); + RetValue = Abc_InfoIsOne( pInfo, pSim->nWordsOut ); + if ( RetValue ) + { +// printf( "Can be done without one!\n" ); + // collect the nodes + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,0) ); + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,1) ); + Abc_ObjForEachFanin( pWin->pNode, pFanin, k ) + { + if ( k != iBest ) + { + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,2+k) ); + Vec_VecPush( vResubsW, Counter, pFanin ); + } + } + Counter++; +// printf( "*" ); + return Counter; + } + + // go through the divisors + for ( d = Abc_ObjFaninNum(pWin->pNode) + 2; d < Abc_NtkPoNum(pAig); d++ ) + { + pInfoDiv = Vec_PtrEntry( pSim->vOuts, d ); + iDiv = d - (Abc_ObjFaninNum(pWin->pNode) + 2); + if ( !Abc_InfoIsOrOne( pInfo, pInfoDiv, pSim->nWordsOut ) ) + continue; +//if ( Abc_ObjLevel(pWin->pNode) <= Abc_ObjLevel( Vec_PtrEntry(pWin->vDivs, iDiv) ) ) +// printf( "Node level = %d. Divisor level = %d.\n", Abc_ObjLevel(pWin->pNode), Abc_ObjLevel( Vec_PtrEntry(pWin->vDivs, iDiv) ) ); + // collect the nodes + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,0) ); + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,1) ); + // collect the remaning fanins and the divisor + Abc_ObjForEachFanin( pWin->pNode, pFanin, k ) + { + if ( k != iBest ) + { + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,2+k) ); + Vec_VecPush( vResubsW, Counter, pFanin ); + } + } + // collect the divisor + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,d) ); + Vec_VecPush( vResubsW, Counter, Vec_PtrEntry(pWin->vDivs, iDiv) ); + Counter++; + + if ( Counter == Vec_VecSize(vResubs) ) + break; + } + + if ( Counter > 0 || Abc_ObjFaninNum(pWin->pNode) >= nFaninsMax ) + return Counter; + + // try to find the node pairs + for ( d = Abc_ObjFaninNum(pWin->pNode) + 2; d < Abc_NtkPoNum(pAig); d++ ) + { + pInfoDiv = Vec_PtrEntry( pSim->vOuts, d ); + iDiv = d - (Abc_ObjFaninNum(pWin->pNode) + 2); + // go through the second divisor + for ( d2 = d + 1; d2 < Abc_NtkPoNum(pAig); d2++ ) + { + pInfoDiv2 = Vec_PtrEntry( pSim->vOuts, d2 ); + iDiv2 = d2 - (Abc_ObjFaninNum(pWin->pNode) + 2); + + if ( !Abc_InfoIsOrOne3( pInfo, pInfoDiv, pInfoDiv2, pSim->nWordsOut ) ) + continue; + // collect the nodes + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,0) ); + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,1) ); + // collect the remaning fanins and the divisor + Abc_ObjForEachFanin( pWin->pNode, pFanin, k ) + { + if ( k != iBest ) + { + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,2+k) ); + Vec_VecPush( vResubsW, Counter, pFanin ); + } + } + // collect the divisor + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,d) ); + Vec_VecPush( vResubs, Counter, Abc_NtkPo(pAig,d2) ); + Vec_VecPush( vResubsW, Counter, Vec_PtrEntry(pWin->vDivs, iDiv) ); + Vec_VecPush( vResubsW, Counter, Vec_PtrEntry(pWin->vDivs, iDiv2) ); + Counter++; + + if ( Counter == Vec_VecSize(vResubs) ) + break; + } + if ( Counter == Vec_VecSize(vResubs) ) + break; + } + return Counter; +} + + +/**Function************************************************************* + + Synopsis [Finds sets of feasible candidates.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned * Res_FilterCollectFaninInfo( Res_Win_t * pWin, Res_Sim_t * pSim, unsigned uMask ) +{ + Abc_Obj_t * pFanin; + unsigned * pInfo; + int i; + pInfo = Vec_PtrEntry( pSim->vOuts, 0 ); + Abc_InfoClear( pInfo, pSim->nWordsOut ); + Abc_ObjForEachFanin( pWin->pNode, pFanin, i ) + { + if ( uMask & (1 << i) ) + Abc_InfoOr( pInfo, Vec_PtrEntry(pSim->vOuts, 2+i), pSim->nWordsOut ); + } + return pInfo; +} + + +/**Function************************************************************* + + Synopsis [Returns the index of the most critical fanin.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Res_FilterCriticalFanin( Abc_Obj_t * pNode ) +{ + Abc_Obj_t * pFanin; + int i, iBest = -1, CostMax = 0, CostCur; + Abc_ObjForEachFanin( pNode, pFanin, i ) + { + if ( !Abc_ObjIsNode(pFanin) ) + continue; + if ( Abc_ObjFanoutNum(pFanin) > 1 ) + continue; + CostCur = Res_WinVisitMffc( pFanin ); + if ( CostMax < CostCur ) + { + CostMax = CostCur; + iBest = i; + } + } +// if ( CostMax > 0 ) +// printf( "<%d>", CostMax ); + return iBest; +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/res/resInt.h b/src/opt/res/resInt.h new file mode 100644 index 00000000..5aae46cc --- /dev/null +++ b/src/opt/res/resInt.h @@ -0,0 +1,137 @@ +/**CFile**************************************************************** + + FileName [resInt.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Resynthesis package.] + + Synopsis [Internal declarations.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - January 15, 2007.] + + Revision [$Id: resInt.h,v 1.00 2007/01/15 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef __RES_INT_H__ +#define __RES_INT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +#include "res.h" + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// BASIC TYPES /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Res_Win_t_ Res_Win_t; +struct Res_Win_t_ +{ + // windowing parameters + Abc_Obj_t * pNode; // the node in the center + int nWinTfiMax; // the fanin levels + int nWinTfoMax; // the fanout levels + int nLevDivMax; // the maximum divisor level + // internal windowing parameters + int nFanoutLimit; // the limit on the fanout count of a TFO node (if more, the node is treated as a root) + int nLevTfiMinus; // the number of additional levels to search from TFO below the level of leaves + // derived windowing parameters + int nLevLeafMin; // the minimum level of a leaf + int nLevTravMin; // the minimum level to search from TFO + int nDivsPlus; // the number of additional divisors + // the window data + Vec_Ptr_t * vRoots; // outputs of the window + Vec_Ptr_t * vLeaves; // inputs of the window + Vec_Ptr_t * vBranches; // side nodes of the window + Vec_Ptr_t * vNodes; // internal nodes of the window + Vec_Ptr_t * vDivs; // candidate divisors of the node + // temporary data + Vec_Vec_t * vMatrix; // TFI nodes below the given node +}; + +typedef struct Res_Sim_t_ Res_Sim_t; +struct Res_Sim_t_ +{ + Abc_Ntk_t * pAig; // AIG for simulation + int nTruePis; // the number of true PIs of the window + int fConst0; // the node can be replaced by constant 0 + int fConst1; // the node can be replaced by constant 0 + // simulation parameters + int nWords; // the number of simulation words + int nPats; // the number of patterns + int nWordsIn; // the number of simulation words in the input patterns + int nPatsIn; // the number of patterns in the input patterns + int nBytesIn; // the number of bytes in the input patterns + int nWordsOut; // the number of simulation words in the output patterns + int nPatsOut; // the number of patterns in the output patterns + // simulation info + Vec_Ptr_t * vPats; // input simulation patterns + Vec_Ptr_t * vPats0; // input simulation patterns + Vec_Ptr_t * vPats1; // input simulation patterns + Vec_Ptr_t * vOuts; // output simulation info + int nPats0; // the number of 0-patterns accumulated + int nPats1; // the number of 1-patterns accumulated + // resub candidates + Vec_Vec_t * vCands; // resubstitution candidates + // statistics + int timeSat; +}; + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +/*=== resDivs.c ==========================================================*/ +extern void Res_WinDivisors( Res_Win_t * p, int nLevDivMax ); +extern void Res_WinSweepLeafTfo_rec( Abc_Obj_t * pObj, int nLevelLimit ); +extern int Res_WinVisitMffc( Abc_Obj_t * pNode ); +/*=== resFilter.c ==========================================================*/ +extern int Res_FilterCandidates( Res_Win_t * pWin, Abc_Ntk_t * pAig, Res_Sim_t * pSim, Vec_Vec_t * vResubs, Vec_Vec_t * vResubsW, int nFaninsMax, int fArea ); +extern int Res_FilterCandidatesArea( Res_Win_t * pWin, Abc_Ntk_t * pAig, Res_Sim_t * pSim, Vec_Vec_t * vResubs, Vec_Vec_t * vResubsW, int nFaninsMax ); +/*=== resSat.c ==========================================================*/ +extern void * Res_SatProveUnsat( Abc_Ntk_t * pAig, Vec_Ptr_t * vFanins ); +extern int Res_SatSimulate( Res_Sim_t * p, int nPats, int fOnSet ); +/*=== resSim.c ==========================================================*/ +extern Res_Sim_t * Res_SimAlloc( int nWords ); +extern void Res_SimFree( Res_Sim_t * p ); +extern int Res_SimPrepare( Res_Sim_t * p, Abc_Ntk_t * pAig, int nTruePis, int fVerbose ); +/*=== resStrash.c ==========================================================*/ +extern Abc_Ntk_t * Res_WndStrash( Res_Win_t * p ); +/*=== resWnd.c ==========================================================*/ +extern void Res_UpdateNetwork( Abc_Obj_t * pObj, Vec_Ptr_t * vFanins, Hop_Obj_t * pFunc, Vec_Vec_t * vLevels ); +/*=== resWnd.c ==========================================================*/ +extern Res_Win_t * Res_WinAlloc(); +extern void Res_WinFree( Res_Win_t * p ); +extern int Res_WinIsTrivial( Res_Win_t * p ); +extern int Res_WinCompute( Abc_Obj_t * pNode, int nWinTfiMax, int nWinTfoMax, Res_Win_t * p ); + + +#ifdef __cplusplus +} +#endif + +#endif + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + diff --git a/src/opt/res/resSat.c b/src/opt/res/resSat.c new file mode 100644 index 00000000..dd0e7a23 --- /dev/null +++ b/src/opt/res/resSat.c @@ -0,0 +1,407 @@ +/**CFile**************************************************************** + + FileName [resSat.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Resynthesis package.] + + Synopsis [Interface with the SAT solver.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - January 15, 2007.] + + Revision [$Id: resSat.c,v 1.00 2007/01/15 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "resInt.h" +#include "hop.h" +#include "satSolver.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +extern int Res_SatAddConst1( sat_solver * pSat, int iVar, int fCompl ); +extern int Res_SatAddEqual( sat_solver * pSat, int iVar0, int iVar1, int fCompl ); +extern int Res_SatAddAnd( sat_solver * pSat, int iVar, int iVar0, int iVar1, int fCompl0, int fCompl1 ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Loads AIG into the SAT solver for checking resubstitution.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void * Res_SatProveUnsat( Abc_Ntk_t * pAig, Vec_Ptr_t * vFanins ) +{ + void * pCnf = NULL; + sat_solver * pSat; + Vec_Ptr_t * vNodes; + Abc_Obj_t * pObj; + int i, nNodes, status; + + // make sure fanins contain POs of the AIG + pObj = Vec_PtrEntry( vFanins, 0 ); + assert( pObj->pNtk == pAig && Abc_ObjIsPo(pObj) ); + + // collect reachable nodes + vNodes = Abc_NtkDfsNodes( pAig, (Abc_Obj_t **)vFanins->pArray, vFanins->nSize ); + + // assign unique numbers to each node + nNodes = 0; + Abc_AigConst1(pAig)->pCopy = (void *)nNodes++; + Abc_NtkForEachPi( pAig, pObj, i ) + pObj->pCopy = (void *)nNodes++; + Vec_PtrForEachEntry( vNodes, pObj, i ) + pObj->pCopy = (void *)nNodes++; + Vec_PtrForEachEntry( vFanins, pObj, i ) // useful POs + pObj->pCopy = (void *)nNodes++; + + // start the solver + pSat = sat_solver_new(); + sat_solver_store_alloc( pSat ); + + // add clause for the constant node + Res_SatAddConst1( pSat, (int)Abc_AigConst1(pAig)->pCopy, 0 ); + // add clauses for AND gates + Vec_PtrForEachEntry( vNodes, pObj, i ) + Res_SatAddAnd( pSat, (int)pObj->pCopy, + (int)Abc_ObjFanin0(pObj)->pCopy, (int)Abc_ObjFanin1(pObj)->pCopy, Abc_ObjFaninC0(pObj), Abc_ObjFaninC1(pObj) ); + Vec_PtrFree( vNodes ); + // add clauses for POs + Vec_PtrForEachEntry( vFanins, pObj, i ) + Res_SatAddEqual( pSat, (int)pObj->pCopy, + (int)Abc_ObjFanin0(pObj)->pCopy, Abc_ObjFaninC0(pObj) ); + // add trivial clauses + pObj = Vec_PtrEntry(vFanins, 0); + Res_SatAddConst1( pSat, (int)pObj->pCopy, 0 ); // care-set + pObj = Vec_PtrEntry(vFanins, 1); + Res_SatAddConst1( pSat, (int)pObj->pCopy, 0 ); // on-set + + // bookmark the clauses of A + sat_solver_store_mark_clauses_a( pSat ); + + // duplicate the clauses + pObj = Vec_PtrEntry(vFanins, 1); + Sat_SolverDoubleClauses( pSat, (int)pObj->pCopy ); + // add the equality constraints + Vec_PtrForEachEntryStart( vFanins, pObj, i, 2 ) + Res_SatAddEqual( pSat, (int)pObj->pCopy, ((int)pObj->pCopy) + nNodes, 0 ); + + // bookmark the roots + sat_solver_store_mark_roots( pSat ); + + // solve the problem + status = sat_solver_solve( pSat, NULL, NULL, (sint64)10000, (sint64)0, (sint64)0, (sint64)0 ); + if ( status == l_False ) + { + pCnf = sat_solver_store_release( pSat ); +// printf( "unsat\n" ); + } + else if ( status == l_True ) + { +// printf( "sat\n" ); + } + else + { +// printf( "undef\n" ); + } + sat_solver_delete( pSat ); + return pCnf; +} + +/**Function************************************************************* + + Synopsis [Loads AIG into the SAT solver for constrained simulation.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void * Res_SatSimulateConstr( Abc_Ntk_t * pAig, int fOnSet ) +{ + sat_solver * pSat; + Vec_Ptr_t * vFanins; + Vec_Ptr_t * vNodes; + Abc_Obj_t * pObj; + int i, nNodes; + + // start the array + vFanins = Vec_PtrAlloc( 2 ); + pObj = Abc_NtkPo( pAig, 0 ); + Vec_PtrPush( vFanins, pObj ); + pObj = Abc_NtkPo( pAig, 1 ); + Vec_PtrPush( vFanins, pObj ); + + // collect reachable nodes + vNodes = Abc_NtkDfsNodes( pAig, (Abc_Obj_t **)vFanins->pArray, vFanins->nSize ); + + // assign unique numbers to each node + nNodes = 0; + Abc_AigConst1(pAig)->pCopy = (void *)nNodes++; + Abc_NtkForEachPi( pAig, pObj, i ) + pObj->pCopy = (void *)nNodes++; + Vec_PtrForEachEntry( vNodes, pObj, i ) + pObj->pCopy = (void *)nNodes++; + Vec_PtrForEachEntry( vFanins, pObj, i ) // useful POs + pObj->pCopy = (void *)nNodes++; + + // start the solver + pSat = sat_solver_new(); + + // add clause for the constant node + Res_SatAddConst1( pSat, (int)Abc_AigConst1(pAig)->pCopy, 0 ); + // add clauses for AND gates + Vec_PtrForEachEntry( vNodes, pObj, i ) + Res_SatAddAnd( pSat, (int)pObj->pCopy, + (int)Abc_ObjFanin0(pObj)->pCopy, (int)Abc_ObjFanin1(pObj)->pCopy, Abc_ObjFaninC0(pObj), Abc_ObjFaninC1(pObj) ); + Vec_PtrFree( vNodes ); + // add clauses for the first PO + pObj = Abc_NtkPo( pAig, 0 ); + Res_SatAddEqual( pSat, (int)pObj->pCopy, + (int)Abc_ObjFanin0(pObj)->pCopy, Abc_ObjFaninC0(pObj) ); + // add clauses for the second PO + pObj = Abc_NtkPo( pAig, 1 ); + Res_SatAddEqual( pSat, (int)pObj->pCopy, + (int)Abc_ObjFanin0(pObj)->pCopy, Abc_ObjFaninC0(pObj) ); + + // add trivial clauses + pObj = Abc_NtkPo( pAig, 0 ); + Res_SatAddConst1( pSat, (int)pObj->pCopy, 0 ); // care-set + + pObj = Abc_NtkPo( pAig, 1 ); + Res_SatAddConst1( pSat, (int)pObj->pCopy, !fOnSet ); // on-set + + Vec_PtrFree( vFanins ); + return pSat; +} + +/**Function************************************************************* + + Synopsis [Loads AIG into the SAT solver for constrained simulation.] + + Description [Returns 1 if the required number of patterns are found. + Returns 0 if the solver ran out of time or proved a constant. + In the latter, case one of the flags, fConst0 or fConst1, are set to 1.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Res_SatSimulate( Res_Sim_t * p, int nPatsLimit, int fOnSet ) +{ + Vec_Int_t * vLits; + Vec_Ptr_t * vPats; + sat_solver * pSat; + int RetValue, i, k, value, status, Lit, Var, iPat; + int clk = clock(); + +//printf( "Looking for %s: ", fOnSet? "onset " : "offset" ); + + // decide what problem should be solved + Lit = toLitCond( (int)Abc_NtkPo(p->pAig,1)->pCopy, !fOnSet ); + if ( fOnSet ) + { + iPat = p->nPats1; + vPats = p->vPats1; + } + else + { + iPat = p->nPats0; + vPats = p->vPats0; + } + assert( iPat < nPatsLimit ); + + // derive the SAT solver + pSat = Res_SatSimulateConstr( p->pAig, fOnSet ); + pSat->fSkipSimplify = 1; + status = sat_solver_simplify( pSat ); + if ( status == 0 ) + { + if ( iPat == 0 ) + { +// if ( fOnSet ) +// p->fConst0 = 1; +// else +// p->fConst1 = 1; + RetValue = 0; + } + goto finish; + } + + // enumerate through the SAT assignments + RetValue = 1; + vLits = Vec_IntAlloc( 32 ); + for ( k = iPat; k < nPatsLimit; k++ ) + { + // solve with the assumption +// status = sat_solver_solve( pSat, &Lit, &Lit + 1, (sint64)10000, (sint64)0, (sint64)0, (sint64)0 ); + status = sat_solver_solve( pSat, NULL, NULL, (sint64)10000, (sint64)0, (sint64)0, (sint64)0 ); + if ( status == l_False ) + { +//printf( "Const %d\n", !fOnSet ); + if ( k == 0 ) + { + if ( fOnSet ) + p->fConst0 = 1; + else + p->fConst1 = 1; + RetValue = 0; + } + break; + } + else if ( status == l_True ) + { + // save the pattern + Vec_IntClear( vLits ); + for ( i = 0; i < p->nTruePis; i++ ) + { + Var = (int)Abc_NtkPi(p->pAig,i)->pCopy; + value = (int)(pSat->model.ptr[Var] == l_True); + if ( value ) + Abc_InfoSetBit( Vec_PtrEntry(vPats, i), k ); + Lit = toLitCond( Var, value ); + Vec_IntPush( vLits, Lit ); +// printf( "%d", value ); + } +// printf( "\n" ); + + status = sat_solver_addclause( pSat, Vec_IntArray(vLits), Vec_IntArray(vLits) + Vec_IntSize(vLits) ); + if ( status == 0 ) + { + k++; + RetValue = 1; + break; + } + } + else + { +//printf( "Undecided\n" ); + if ( k == 0 ) + RetValue = 0; + else + RetValue = 1; + break; + } + } + Vec_IntFree( vLits ); +//printf( "Found %d patterns\n", k - iPat ); + + // set the new number of patterns + if ( fOnSet ) + p->nPats1 = k; + else + p->nPats0 = k; + +finish: + + sat_solver_delete( pSat ); +p->timeSat += clock() - clk; + return RetValue; +} + + +/**Function************************************************************* + + Synopsis [Asserts equality of the variable to a constant.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Res_SatAddConst1( sat_solver * pSat, int iVar, int fCompl ) +{ + lit Lit = toLitCond( iVar, fCompl ); + if ( !sat_solver_addclause( pSat, &Lit, &Lit + 1 ) ) + return 0; + return 1; +} + +/**Function************************************************************* + + Synopsis [Asserts equality of two variables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Res_SatAddEqual( sat_solver * pSat, int iVar0, int iVar1, int fCompl ) +{ + lit Lits[2]; + + Lits[0] = toLitCond( iVar0, 0 ); + Lits[1] = toLitCond( iVar1, !fCompl ); + if ( !sat_solver_addclause( pSat, Lits, Lits + 2 ) ) + return 0; + + Lits[0] = toLitCond( iVar0, 1 ); + Lits[1] = toLitCond( iVar1, fCompl ); + if ( !sat_solver_addclause( pSat, Lits, Lits + 2 ) ) + return 0; + + return 1; +} + +/**Function************************************************************* + + Synopsis [Adds constraints for the two-input AND-gate.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Res_SatAddAnd( sat_solver * pSat, int iVar, int iVar0, int iVar1, int fCompl0, int fCompl1 ) +{ + lit Lits[3]; + + Lits[0] = toLitCond( iVar, 1 ); + Lits[1] = toLitCond( iVar0, fCompl0 ); + if ( !sat_solver_addclause( pSat, Lits, Lits + 2 ) ) + return 0; + + Lits[0] = toLitCond( iVar, 1 ); + Lits[1] = toLitCond( iVar1, fCompl1 ); + if ( !sat_solver_addclause( pSat, Lits, Lits + 2 ) ) + return 0; + + Lits[0] = toLitCond( iVar, 0 ); + Lits[1] = toLitCond( iVar0, !fCompl0 ); + Lits[2] = toLitCond( iVar1, !fCompl1 ); + if ( !sat_solver_addclause( pSat, Lits, Lits + 3 ) ) + return 0; + + return 1; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/res/resSim.c b/src/opt/res/resSim.c new file mode 100644 index 00000000..5c1dd2b6 --- /dev/null +++ b/src/opt/res/resSim.c @@ -0,0 +1,790 @@ +/**CFile**************************************************************** + + FileName [resSim.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Resynthesis package.] + + Synopsis [Simulation engine.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - January 15, 2007.] + + Revision [$Id: resSim.c,v 1.00 2007/01/15 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "resInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Allocate simulation engine.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Res_Sim_t * Res_SimAlloc( int nWords ) +{ + Res_Sim_t * p; + p = ALLOC( Res_Sim_t, 1 ); + memset( p, 0, sizeof(Res_Sim_t) ); + // simulation parameters + p->nWords = nWords; + p->nPats = p->nWords * 8 * sizeof(unsigned); + p->nWordsIn = p->nPats; + p->nBytesIn = p->nPats * sizeof(unsigned); + p->nPatsIn = p->nPats * 8 * sizeof(unsigned); + p->nWordsOut = p->nPats * p->nWords; + p->nPatsOut = p->nPats * p->nPats; + // simulation info + p->vPats = Vec_PtrAllocSimInfo( 1024, p->nWordsIn ); + p->vPats0 = Vec_PtrAllocSimInfo( 128, p->nWords ); + p->vPats1 = Vec_PtrAllocSimInfo( 128, p->nWords ); + p->vOuts = Vec_PtrAllocSimInfo( 128, p->nWordsOut ); + // resub candidates + p->vCands = Vec_VecStart( 16 ); + return p; +} + +/**Function************************************************************* + + Synopsis [Allocate simulation engine.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimAdjust( Res_Sim_t * p, Abc_Ntk_t * pAig, int nTruePis ) +{ + srand( 0xABC ); + + assert( Abc_NtkIsStrash(pAig) ); + p->pAig = pAig; + p->nTruePis = nTruePis; + if ( Vec_PtrSize(p->vPats) < Abc_NtkObjNumMax(pAig)+1 ) + { + Vec_PtrFree( p->vPats ); + p->vPats = Vec_PtrAllocSimInfo( Abc_NtkObjNumMax(pAig)+1, p->nWordsIn ); + } + if ( Vec_PtrSize(p->vPats0) < nTruePis ) + { + Vec_PtrFree( p->vPats0 ); + p->vPats0 = Vec_PtrAllocSimInfo( nTruePis, p->nWords ); + } + if ( Vec_PtrSize(p->vPats1) < nTruePis ) + { + Vec_PtrFree( p->vPats1 ); + p->vPats1 = Vec_PtrAllocSimInfo( nTruePis, p->nWords ); + } + if ( Vec_PtrSize(p->vOuts) < Abc_NtkPoNum(pAig) ) + { + Vec_PtrFree( p->vOuts ); + p->vOuts = Vec_PtrAllocSimInfo( Abc_NtkPoNum(pAig), p->nWordsOut ); + } + // clean storage info for patterns + Abc_InfoClear( Vec_PtrEntry(p->vPats0,0), p->nWords * nTruePis ); + Abc_InfoClear( Vec_PtrEntry(p->vPats1,0), p->nWords * nTruePis ); + p->nPats0 = 0; + p->nPats1 = 0; + p->fConst0 = 0; + p->fConst1 = 0; +} + +/**Function************************************************************* + + Synopsis [Free simulation engine.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimFree( Res_Sim_t * p ) +{ + Vec_PtrFree( p->vPats ); + Vec_PtrFree( p->vPats0 ); + Vec_PtrFree( p->vPats1 ); + Vec_PtrFree( p->vOuts ); + Vec_VecFree( p->vCands ); + free( p ); +} + + +/**Function************************************************************* + + Synopsis [Sets random PI simulation info.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_InfoRandomBytes( unsigned * p, int nWords ) +{ + int i, Num; + for ( i = nWords - 1; i >= 0; i-- ) + { + Num = rand(); + p[i] = (Num & 1)? 0xff : 0; + p[i] = (p[i] << 8) | ((Num & 2)? 0xff : 0); + p[i] = (p[i] << 8) | ((Num & 4)? 0xff : 0); + p[i] = (p[i] << 8) | ((Num & 8)? 0xff : 0); + } +// Extra_PrintBinary( stdout, p, 32 ); printf( "\n" ); +} + +/**Function************************************************************* + + Synopsis [Sets random PI simulation info.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimSetRandomBytes( Res_Sim_t * p ) +{ + Abc_Obj_t * pObj; + unsigned * pInfo; + int i; + Abc_NtkForEachPi( p->pAig, pObj, i ) + { + pInfo = Vec_PtrEntry( p->vPats, pObj->Id ); + if ( i < p->nTruePis ) + Abc_InfoRandomBytes( pInfo, p->nWordsIn ); + else + Abc_InfoRandom( pInfo, p->nWordsIn ); + } +/* + // double-check that all are byte-patterns + Abc_NtkForEachPi( p->pAig, pObj, i ) + { + if ( i == p->nTruePis ) + break; + pInfoC = (unsigned char *)Vec_PtrEntry( p->vPats, pObj->Id ); + for ( k = 0; k < p->nBytesIn; k++ ) + assert( pInfoC[k] == 0 || pInfoC[k] == 0xff ); + } +*/ +} + +/**Function************************************************************* + + Synopsis [Sets random PI simulation info.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimSetDerivedBytes( Res_Sim_t * p, int fUseWalk ) +{ + Vec_Ptr_t * vPatsSource[2]; + int nPatsSource[2]; + Abc_Obj_t * pObj; + unsigned char * pInfo; + int i, k, z, s, nPats; + + // set several random patterns + assert( p->nBytesIn % 32 == 0 ); + nPats = p->nBytesIn/8; + Abc_NtkForEachPi( p->pAig, pObj, i ) + { + if ( i == p->nTruePis ) + break; + Abc_InfoRandomBytes( Vec_PtrEntry(p->vPats, pObj->Id), nPats/4 ); + } + + // set special patterns + if ( fUseWalk ) + { + for ( z = 0; z < 2; z++ ) + { + // set the zero pattern + Abc_NtkForEachPi( p->pAig, pObj, i ) + { + if ( i == p->nTruePis ) + break; + pInfo = (unsigned char *)Vec_PtrEntry( p->vPats, pObj->Id ); + pInfo[nPats] = z ? 0xff : 0; + } + if ( ++nPats == p->nBytesIn ) + return; + // set the walking zero pattern + for ( k = 0; k < p->nTruePis; k++ ) + { + Abc_NtkForEachPi( p->pAig, pObj, i ) + { + if ( i == p->nTruePis ) + break; + pInfo = (unsigned char *)Vec_PtrEntry( p->vPats, pObj->Id ); + pInfo[nPats] = ((i == k) ^ z) ? 0xff : 0; + } + if ( ++nPats == p->nBytesIn ) + return; + } + } + } + + // decide what patterns to set first + if ( p->nPats0 < p->nPats1 ) + { + nPatsSource[0] = p->nPats0; + vPatsSource[0] = p->vPats0; + nPatsSource[1] = p->nPats1; + vPatsSource[1] = p->vPats1; + } + else + { + nPatsSource[0] = p->nPats1; + vPatsSource[0] = p->vPats1; + nPatsSource[1] = p->nPats0; + vPatsSource[1] = p->vPats0; + } + for ( z = 0; z < 2; z++ ) + { + for ( s = nPatsSource[z] - 1; s >= 0; s-- ) + { +// if ( s == 0 ) +// printf( "Patterns:\n" ); + // set the given source pattern + for ( k = 0; k < p->nTruePis; k++ ) + { + Abc_NtkForEachPi( p->pAig, pObj, i ) + { + if ( i == p->nTruePis ) + break; + pInfo = (unsigned char *)Vec_PtrEntry( p->vPats, pObj->Id ); + if ( (i == k) ^ Abc_InfoHasBit( Vec_PtrEntry(vPatsSource[z], i), s ) ) + { + pInfo[nPats] = 0xff; +// if ( s == 0 ) +// printf( "1" ); + } + else + { + pInfo[nPats] = 0; +// if ( s == 0 ) +// printf( "0" ); + } + } +// if ( s == 0 ) +// printf( "\n" ); + if ( ++nPats == p->nBytesIn ) + return; + } + } + } + // clean the rest + for ( z = nPats; z < p->nBytesIn; z++ ) + { + Abc_NtkForEachPi( p->pAig, pObj, i ) + { + if ( i == p->nTruePis ) + break; + pInfo = (unsigned char *)Vec_PtrEntry( p->vPats, pObj->Id ); + memset( pInfo + nPats, 0, p->nBytesIn - nPats ); + } + } +/* + // double-check that all are byte-patterns + Abc_NtkForEachPi( p->pAig, pObj, i ) + { + if ( i == p->nTruePis ) + break; + pInfo = (unsigned char *)Vec_PtrEntry( p->vPats, pObj->Id ); + for ( k = 0; k < p->nBytesIn; k++ ) + assert( pInfo[k] == 0 || pInfo[k] == 0xff ); + } +*/ +} + +/**Function************************************************************* + + Synopsis [Sets given PI simulation info.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimSetGiven( Res_Sim_t * p, Vec_Ptr_t * vInfo ) +{ + Abc_Obj_t * pObj; + unsigned * pInfo, * pInfo2; + int i, w; + Abc_NtkForEachPi( p->pAig, pObj, i ) + { + if ( i == p->nTruePis ) + break; + pInfo = Vec_PtrEntry( p->vPats, pObj->Id ); + pInfo2 = Vec_PtrEntry( vInfo, i ); + for ( w = 0; w < p->nWords; w++ ) + pInfo[w] = pInfo2[w]; + } +} + +/**Function************************************************************* + + Synopsis [Simulates one node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimPerformOne( Abc_Obj_t * pNode, Vec_Ptr_t * vSimInfo, int nSimWords ) +{ + unsigned * pInfo, * pInfo1, * pInfo2; + int k, fComp1, fComp2; + // simulate the internal nodes + assert( Abc_ObjIsNode(pNode) ); + pInfo = Vec_PtrEntry(vSimInfo, pNode->Id); + pInfo1 = Vec_PtrEntry(vSimInfo, Abc_ObjFaninId0(pNode)); + pInfo2 = Vec_PtrEntry(vSimInfo, Abc_ObjFaninId1(pNode)); + fComp1 = Abc_ObjFaninC0(pNode); + fComp2 = Abc_ObjFaninC1(pNode); + if ( fComp1 && fComp2 ) + for ( k = 0; k < nSimWords; k++ ) + pInfo[k] = ~pInfo1[k] & ~pInfo2[k]; + else if ( fComp1 && !fComp2 ) + for ( k = 0; k < nSimWords; k++ ) + pInfo[k] = ~pInfo1[k] & pInfo2[k]; + else if ( !fComp1 && fComp2 ) + for ( k = 0; k < nSimWords; k++ ) + pInfo[k] = pInfo1[k] & ~pInfo2[k]; + else // if ( fComp1 && fComp2 ) + for ( k = 0; k < nSimWords; k++ ) + pInfo[k] = pInfo1[k] & pInfo2[k]; +} + +/**Function************************************************************* + + Synopsis [Simulates one CO node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimTransferOne( Abc_Obj_t * pNode, Vec_Ptr_t * vSimInfo, int nSimWords ) +{ + unsigned * pInfo, * pInfo1; + int k, fComp1; + // simulate the internal nodes + assert( Abc_ObjIsCo(pNode) ); + pInfo = Vec_PtrEntry(vSimInfo, pNode->Id); + pInfo1 = Vec_PtrEntry(vSimInfo, Abc_ObjFaninId0(pNode)); + fComp1 = Abc_ObjFaninC0(pNode); + if ( fComp1 ) + for ( k = 0; k < nSimWords; k++ ) + pInfo[k] = ~pInfo1[k]; + else + for ( k = 0; k < nSimWords; k++ ) + pInfo[k] = pInfo1[k]; +} + +/**Function************************************************************* + + Synopsis [Performs one round of simulation.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimPerformRound( Res_Sim_t * p, int nWords ) +{ + Abc_Obj_t * pObj; + int i; + Abc_InfoFill( Vec_PtrEntry(p->vPats,0), nWords ); + Abc_AigForEachAnd( p->pAig, pObj, i ) + Res_SimPerformOne( pObj, p->vPats, nWords ); + Abc_NtkForEachPo( p->pAig, pObj, i ) + Res_SimTransferOne( pObj, p->vPats, nWords ); +} + + +/**Function************************************************************* + + Synopsis [Pads the extra space with duplicated simulation info.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimPadSimInfo( Vec_Ptr_t * vPats, int nPats, int nWords ) +{ + unsigned * pInfo; + int i, w, iWords; + assert( nPats > 0 && nPats < nWords * 8 * (int) sizeof(unsigned) ); + // pad the first word + if ( nPats < 8 * sizeof(unsigned) ) + { + Vec_PtrForEachEntry( vPats, pInfo, i ) + if ( pInfo[0] & 1 ) + pInfo[0] |= ((~0) << nPats); + nPats = 8 * sizeof(unsigned); + } + // pad the empty words + iWords = nPats / (8 * sizeof(unsigned)); + Vec_PtrForEachEntry( vPats, pInfo, i ) + { + for ( w = iWords; w < nWords; w++ ) + pInfo[w] = pInfo[0]; + } +} + +/**Function************************************************************* + + Synopsis [Duplicates the simulation info to fill the space.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimDeriveInfoReplicate( Res_Sim_t * p ) +{ + unsigned * pInfo, * pInfo2; + Abc_Obj_t * pObj; + int i, j, w; + Abc_NtkForEachPo( p->pAig, pObj, i ) + { + pInfo = Vec_PtrEntry( p->vPats, pObj->Id ); + pInfo2 = Vec_PtrEntry( p->vOuts, i ); + for ( j = 0; j < p->nPats; j++ ) + for ( w = 0; w < p->nWords; w++ ) + *pInfo2++ = pInfo[w]; + } +} + +/**Function************************************************************* + + Synopsis [Complement the simulation info if necessary.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimDeriveInfoComplement( Res_Sim_t * p ) +{ + unsigned * pInfo, * pInfo2; + Abc_Obj_t * pObj; + int i, j, w; + Abc_NtkForEachPo( p->pAig, pObj, i ) + { + pInfo = Vec_PtrEntry( p->vPats, pObj->Id ); + pInfo2 = Vec_PtrEntry( p->vOuts, i ); + for ( j = 0; j < p->nPats; j++, pInfo2 += p->nWords ) + if ( Abc_InfoHasBit( pInfo, j ) ) + for ( w = 0; w < p->nWords; w++ ) + pInfo2[w] = ~pInfo2[w]; + } +} + +/**Function************************************************************* + + Synopsis [Prints output patterns.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimPrintOutPatterns( Res_Sim_t * p, Abc_Ntk_t * pAig ) +{ + Abc_Obj_t * pObj; + unsigned * pInfo2; + int i; + Abc_NtkForEachPo( pAig, pObj, i ) + { + pInfo2 = Vec_PtrEntry( p->vOuts, i ); + Extra_PrintBinary( stdout, pInfo2, p->nPatsOut ); + printf( "\n" ); + } +} + +/**Function************************************************************* + + Synopsis [Prints output patterns.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimPrintNodePatterns( Res_Sim_t * p, Abc_Ntk_t * pAig ) +{ + unsigned * pInfo; + pInfo = Vec_PtrEntry( p->vPats, Abc_NtkPo(p->pAig, 1)->Id ); + Extra_PrintBinary( stdout, pInfo, p->nPats ); + printf( "\n" ); +} + +/**Function************************************************************* + + Synopsis [Counts the number of patters of different type.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimCountResults( Res_Sim_t * p, int * pnDcs, int * pnOnes, int * pnZeros, int fVerbose ) +{ + unsigned char * pInfoCare, * pInfoNode; + int i, nTotal = 0; + pInfoCare = (unsigned char *)Vec_PtrEntry( p->vPats, Abc_NtkPo(p->pAig, 0)->Id ); + pInfoNode = (unsigned char *)Vec_PtrEntry( p->vPats, Abc_NtkPo(p->pAig, 1)->Id ); + for ( i = 0; i < p->nBytesIn; i++ ) + { + if ( !pInfoCare[i] ) + (*pnDcs)++; + else if ( !pInfoNode[i] ) + (*pnZeros)++; + else + (*pnOnes)++; + } + nTotal += *pnDcs; + nTotal += *pnZeros; + nTotal += *pnOnes; + if ( fVerbose ) + { + printf( "Dc = %7.2f %% ", 100.0*(*pnDcs) /nTotal ); + printf( "On = %7.2f %% ", 100.0*(*pnOnes) /nTotal ); + printf( "Off = %7.2f %% ", 100.0*(*pnZeros)/nTotal ); + } +} + +/**Function************************************************************* + + Synopsis [Counts the number of patters of different type.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimCollectPatterns( Res_Sim_t * p, int fVerbose ) +{ + Abc_Obj_t * pObj; + unsigned char * pInfoCare, * pInfoNode, * pInfo; + int i, j; + pInfoCare = (unsigned char *)Vec_PtrEntry( p->vPats, Abc_NtkPo(p->pAig, 0)->Id ); + pInfoNode = (unsigned char *)Vec_PtrEntry( p->vPats, Abc_NtkPo(p->pAig, 1)->Id ); + for ( i = 0; i < p->nBytesIn; i++ ) + { + // skip don't-care patterns + if ( !pInfoCare[i] ) + continue; + // separate offset and onset patterns + assert( pInfoNode[i] == 0 || pInfoNode[i] == 0xff ); + if ( !pInfoNode[i] ) + { + if ( p->nPats0 >= p->nPats ) + continue; + Abc_NtkForEachPi( p->pAig, pObj, j ) + { + if ( j == p->nTruePis ) + break; + pInfo = (unsigned char *)Vec_PtrEntry( p->vPats, pObj->Id ); + assert( pInfo[i] == 0 || pInfo[i] == 0xff ); + if ( pInfo[i] ) + Abc_InfoSetBit( Vec_PtrEntry(p->vPats0, j), p->nPats0 ); + } + p->nPats0++; + } + else + { + if ( p->nPats1 >= p->nPats ) + continue; + Abc_NtkForEachPi( p->pAig, pObj, j ) + { + if ( j == p->nTruePis ) + break; + pInfo = (unsigned char *)Vec_PtrEntry( p->vPats, pObj->Id ); + assert( pInfo[i] == 0 || pInfo[i] == 0xff ); + if ( pInfo[i] ) + Abc_InfoSetBit( Vec_PtrEntry(p->vPats1, j), p->nPats1 ); + } + p->nPats1++; + } + if ( p->nPats0 >= p->nPats && p->nPats1 >= p->nPats ) + break; + } + if ( fVerbose ) + { + printf( "| " ); + printf( "On = %3d ", p->nPats1 ); + printf( "Off = %3d ", p->nPats0 ); + printf( "\n" ); + } +} + +/**Function************************************************************* + + Synopsis [Verifies the last pattern.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Res_SimVerifyValue( Res_Sim_t * p, int fOnSet ) +{ + Abc_Obj_t * pObj; + unsigned * pInfo, * pInfo2; + int i, value; + Abc_NtkForEachPi( p->pAig, pObj, i ) + { + if ( i == p->nTruePis ) + break; + if ( fOnSet ) + { + pInfo2 = Vec_PtrEntry( p->vPats1, i ); + value = Abc_InfoHasBit( pInfo2, p->nPats1 - 1 ); + } + else + { + pInfo2 = Vec_PtrEntry( p->vPats0, i ); + value = Abc_InfoHasBit( pInfo2, p->nPats0 - 1 ); + } + pInfo = Vec_PtrEntry( p->vPats, pObj->Id ); + pInfo[0] = value ? ~0 : 0; + } + Res_SimPerformRound( p, 1 ); + pObj = Abc_NtkPo( p->pAig, 1 ); + pInfo = Vec_PtrEntry( p->vPats, pObj->Id ); + assert( pInfo[0] == 0 || pInfo[0] == ~0 ); + return pInfo[0] > 0; +} + +/**Function************************************************************* + + Synopsis [Prepares simulation info for candidate filtering.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Res_SimPrepare( Res_Sim_t * p, Abc_Ntk_t * pAig, int nTruePis, int fVerbose ) +{ + int i, nOnes = 0, nZeros = 0, nDcs = 0; + if ( fVerbose ) + printf( "\n" ); + // prepare the manager + Res_SimAdjust( p, pAig, nTruePis ); + // estimate the number of patterns + Res_SimSetRandomBytes( p ); + Res_SimPerformRound( p, p->nWordsIn ); + Res_SimCountResults( p, &nDcs, &nOnes, &nZeros, fVerbose ); + // collect the patterns + Res_SimCollectPatterns( p, fVerbose ); + // add more patterns using constraint simulation + if ( p->nPats0 < 8 ) + { + if ( !Res_SatSimulate( p, 16, 0 ) ) + return p->fConst0 || p->fConst1; +// return 0; +// printf( "Value0 = %d\n", Res_SimVerifyValue( p, 0 ) ); + } + if ( p->nPats1 < 8 ) + { + if ( !Res_SatSimulate( p, 16, 1 ) ) + return p->fConst0 || p->fConst1; +// return 0; +// printf( "Value1 = %d\n", Res_SimVerifyValue( p, 1 ) ); + } + // generate additional patterns + for ( i = 0; i < 2; i++ ) + { + if ( p->nPats0 > p->nPats*7/8 && p->nPats1 > p->nPats*7/8 ) + break; + Res_SimSetDerivedBytes( p, i==0 ); + Res_SimPerformRound( p, p->nWordsIn ); + Res_SimCountResults( p, &nDcs, &nOnes, &nZeros, fVerbose ); + Res_SimCollectPatterns( p, fVerbose ); + } + // create bit-matrix info + if ( p->nPats0 < p->nPats ) + Res_SimPadSimInfo( p->vPats0, p->nPats0, p->nWords ); + if ( p->nPats1 < p->nPats ) + Res_SimPadSimInfo( p->vPats1, p->nPats1, p->nWords ); + // resimulate 0-patterns + Res_SimSetGiven( p, p->vPats0 ); + Res_SimPerformRound( p, p->nWords ); +//Res_SimPrintNodePatterns( p, pAig ); + Res_SimDeriveInfoReplicate( p ); + // resimulate 1-patterns + Res_SimSetGiven( p, p->vPats1 ); + Res_SimPerformRound( p, p->nWords ); +//Res_SimPrintNodePatterns( p, pAig ); + Res_SimDeriveInfoComplement( p ); + // print output patterns +// Res_SimPrintOutPatterns( p, pAig ); + return 1; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/res/resSim_old.c b/src/opt/res/resSim_old.c new file mode 100644 index 00000000..23ce29e4 --- /dev/null +++ b/src/opt/res/resSim_old.c @@ -0,0 +1,521 @@ +/**CFile**************************************************************** + + FileName [resSim.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Resynthesis package.] + + Synopsis [Simulation engine.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - January 15, 2007.] + + Revision [$Id: resSim.c,v 1.00 2007/01/15 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "resInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Allocate simulation engine.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Res_Sim_t * Res_SimAlloc( int nWords ) +{ + Res_Sim_t * p; + p = ALLOC( Res_Sim_t, 1 ); + memset( p, 0, sizeof(Res_Sim_t) ); + // simulation parameters + p->nWords = nWords; + p->nPats = 8 * sizeof(unsigned) * p->nWords; + p->nWordsOut = p->nPats * p->nWords; + p->nPatsOut = p->nPats * p->nPats; + // simulation info + p->vPats = Vec_PtrAllocSimInfo( 1024, p->nWords ); + p->vPats0 = Vec_PtrAllocSimInfo( 128, p->nWords ); + p->vPats1 = Vec_PtrAllocSimInfo( 128, p->nWords ); + p->vOuts = Vec_PtrAllocSimInfo( 128, p->nWordsOut ); + // resub candidates + p->vCands = Vec_VecStart( 16 ); + return p; +} + +/**Function************************************************************* + + Synopsis [Allocate simulation engine.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimAdjust( Res_Sim_t * p, Abc_Ntk_t * pAig ) +{ + srand( 0xABC ); + + assert( Abc_NtkIsStrash(pAig) ); + p->pAig = pAig; + if ( Vec_PtrSize(p->vPats) < Abc_NtkObjNumMax(pAig)+1 ) + { + Vec_PtrFree( p->vPats ); + p->vPats = Vec_PtrAllocSimInfo( Abc_NtkObjNumMax(pAig)+1, p->nWords ); + } + if ( Vec_PtrSize(p->vPats0) < Abc_NtkPiNum(pAig) ) + { + Vec_PtrFree( p->vPats0 ); + p->vPats0 = Vec_PtrAllocSimInfo( Abc_NtkPiNum(pAig), p->nWords ); + } + if ( Vec_PtrSize(p->vPats1) < Abc_NtkPiNum(pAig) ) + { + Vec_PtrFree( p->vPats1 ); + p->vPats1 = Vec_PtrAllocSimInfo( Abc_NtkPiNum(pAig), p->nWords ); + } + if ( Vec_PtrSize(p->vOuts) < Abc_NtkPoNum(pAig) ) + { + Vec_PtrFree( p->vOuts ); + p->vOuts = Vec_PtrAllocSimInfo( Abc_NtkPoNum(pAig), p->nWordsOut ); + } + // clean storage info for patterns + Abc_InfoClear( Vec_PtrEntry(p->vPats0,0), p->nWords * Abc_NtkPiNum(pAig) ); + Abc_InfoClear( Vec_PtrEntry(p->vPats1,0), p->nWords * Abc_NtkPiNum(pAig) ); + p->nPats0 = 0; + p->nPats1 = 0; +} + +/**Function************************************************************* + + Synopsis [Free simulation engine.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimFree( Res_Sim_t * p ) +{ + Vec_PtrFree( p->vPats ); + Vec_PtrFree( p->vPats0 ); + Vec_PtrFree( p->vPats1 ); + Vec_PtrFree( p->vOuts ); + Vec_VecFree( p->vCands ); + free( p ); +} + + +/**Function************************************************************* + + Synopsis [Sets random PI simulation info.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimSetRandom( Res_Sim_t * p ) +{ + Abc_Obj_t * pObj; + unsigned * pInfo; + int i; + Abc_NtkForEachPi( p->pAig, pObj, i ) + { + pInfo = Vec_PtrEntry( p->vPats, pObj->Id ); + Abc_InfoRandom( pInfo, p->nWords ); + } +} + +/**Function************************************************************* + + Synopsis [Sets given PI simulation info.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimSetGiven( Res_Sim_t * p, Vec_Ptr_t * vInfo ) +{ + Abc_Obj_t * pObj; + unsigned * pInfo, * pInfo2; + int i, w; + Abc_NtkForEachPi( p->pAig, pObj, i ) + { + pInfo = Vec_PtrEntry( p->vPats, pObj->Id ); + pInfo2 = Vec_PtrEntry( vInfo, i ); + for ( w = 0; w < p->nWords; w++ ) + pInfo[w] = pInfo2[w]; + } +} + +/**Function************************************************************* + + Synopsis [Simulates one node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimPerformOne( Abc_Obj_t * pNode, Vec_Ptr_t * vSimInfo, int nSimWords ) +{ + unsigned * pInfo, * pInfo1, * pInfo2; + int k, fComp1, fComp2; + // simulate the internal nodes + assert( Abc_ObjIsNode(pNode) ); + pInfo = Vec_PtrEntry(vSimInfo, pNode->Id); + pInfo1 = Vec_PtrEntry(vSimInfo, Abc_ObjFaninId0(pNode)); + pInfo2 = Vec_PtrEntry(vSimInfo, Abc_ObjFaninId1(pNode)); + fComp1 = Abc_ObjFaninC0(pNode); + fComp2 = Abc_ObjFaninC1(pNode); + if ( fComp1 && fComp2 ) + for ( k = 0; k < nSimWords; k++ ) + pInfo[k] = ~pInfo1[k] & ~pInfo2[k]; + else if ( fComp1 && !fComp2 ) + for ( k = 0; k < nSimWords; k++ ) + pInfo[k] = ~pInfo1[k] & pInfo2[k]; + else if ( !fComp1 && fComp2 ) + for ( k = 0; k < nSimWords; k++ ) + pInfo[k] = pInfo1[k] & ~pInfo2[k]; + else // if ( fComp1 && fComp2 ) + for ( k = 0; k < nSimWords; k++ ) + pInfo[k] = pInfo1[k] & pInfo2[k]; +} + +/**Function************************************************************* + + Synopsis [Simulates one CO node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimTransferOne( Abc_Obj_t * pNode, Vec_Ptr_t * vSimInfo, int nSimWords ) +{ + unsigned * pInfo, * pInfo1; + int k, fComp1; + // simulate the internal nodes + assert( Abc_ObjIsCo(pNode) ); + pInfo = Vec_PtrEntry(vSimInfo, pNode->Id); + pInfo1 = Vec_PtrEntry(vSimInfo, Abc_ObjFaninId0(pNode)); + fComp1 = Abc_ObjFaninC0(pNode); + if ( fComp1 ) + for ( k = 0; k < nSimWords; k++ ) + pInfo[k] = ~pInfo1[k]; + else + for ( k = 0; k < nSimWords; k++ ) + pInfo[k] = pInfo1[k]; +} + +/**Function************************************************************* + + Synopsis [Performs one round of simulation.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimPerformRound( Res_Sim_t * p ) +{ + Abc_Obj_t * pObj; + int i; + Abc_InfoFill( Vec_PtrEntry(p->vPats,0), p->nWords ); + Abc_AigForEachAnd( p->pAig, pObj, i ) + Res_SimPerformOne( pObj, p->vPats, p->nWords ); + Abc_NtkForEachPo( p->pAig, pObj, i ) + Res_SimTransferOne( pObj, p->vPats, p->nWords ); +} + +/**Function************************************************************* + + Synopsis [Processes simulation patterns.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimProcessPats( Res_Sim_t * p ) +{ + Abc_Obj_t * pObj; + unsigned * pInfoCare, * pInfoNode; + int i, j, nDcs = 0; + pInfoCare = Vec_PtrEntry( p->vPats, Abc_NtkPo(p->pAig, 0)->Id ); + pInfoNode = Vec_PtrEntry( p->vPats, Abc_NtkPo(p->pAig, 1)->Id ); + for ( i = 0; i < p->nPats; i++ ) + { + // skip don't-care patterns + if ( !Abc_InfoHasBit(pInfoCare, i) ) + { + nDcs++; + continue; + } + // separate offset and onset patterns + if ( !Abc_InfoHasBit(pInfoNode, i) ) + { + if ( p->nPats0 >= p->nPats ) + continue; + Abc_NtkForEachPi( p->pAig, pObj, j ) + if ( Abc_InfoHasBit( Vec_PtrEntry(p->vPats, pObj->Id), i ) ) + Abc_InfoSetBit( Vec_PtrEntry(p->vPats0, j), p->nPats0 ); + p->nPats0++; + } + else + { + if ( p->nPats1 >= p->nPats ) + continue; + Abc_NtkForEachPi( p->pAig, pObj, j ) + if ( Abc_InfoHasBit( Vec_PtrEntry(p->vPats, pObj->Id), i ) ) + Abc_InfoSetBit( Vec_PtrEntry(p->vPats1, j), p->nPats1 ); + p->nPats1++; + } + } +} + +/**Function************************************************************* + + Synopsis [Pads the extra space with duplicated simulation info.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimPadSimInfo( Vec_Ptr_t * vPats, int nPats, int nWords ) +{ + unsigned * pInfo; + int i, w, iWords; + assert( nPats > 0 && nPats < nWords * 8 * (int) sizeof(unsigned) ); + // pad the first word + if ( nPats < 8 * sizeof(unsigned) ) + { + Vec_PtrForEachEntry( vPats, pInfo, i ) + if ( pInfo[0] & 1 ) + pInfo[0] |= ((~0) << nPats); + nPats = 8 * sizeof(unsigned); + } + // pad the empty words + iWords = nPats / (8 * sizeof(unsigned)); + Vec_PtrForEachEntry( vPats, pInfo, i ) + { + for ( w = iWords; w < nWords; w++ ) + pInfo[w] = pInfo[0]; + } +} + +/**Function************************************************************* + + Synopsis [Duplicates the simulation info to fill the space.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimDeriveInfoReplicate( Res_Sim_t * p ) +{ + unsigned * pInfo, * pInfo2; + Abc_Obj_t * pObj; + int i, j, w; + Abc_NtkForEachPo( p->pAig, pObj, i ) + { + pInfo = Vec_PtrEntry( p->vPats, pObj->Id ); + pInfo2 = Vec_PtrEntry( p->vOuts, i ); + for ( j = 0; j < p->nPats; j++ ) + for ( w = 0; w < p->nWords; w++ ) + *pInfo2++ = pInfo[w]; + } +} + +/**Function************************************************************* + + Synopsis [Complement the simulation info if necessary.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimDeriveInfoComplement( Res_Sim_t * p ) +{ + unsigned * pInfo, * pInfo2; + Abc_Obj_t * pObj; + int i, j, w; + Abc_NtkForEachPo( p->pAig, pObj, i ) + { + pInfo = Vec_PtrEntry( p->vPats, pObj->Id ); + pInfo2 = Vec_PtrEntry( p->vOuts, i ); + for ( j = 0; j < p->nPats; j++, pInfo2 += p->nWords ) + if ( Abc_InfoHasBit( pInfo, j ) ) + for ( w = 0; w < p->nWords; w++ ) + pInfo2[w] = ~pInfo2[w]; + } +} + +/**Function************************************************************* + + Synopsis [Free simulation engine.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimReportOne( Res_Sim_t * p ) +{ + unsigned * pInfoCare, * pInfoNode; + int i, nDcs, nOnes, nZeros; + pInfoCare = Vec_PtrEntry( p->vPats, Abc_NtkPo(p->pAig, 0)->Id ); + pInfoNode = Vec_PtrEntry( p->vPats, Abc_NtkPo(p->pAig, 1)->Id ); + nDcs = nOnes = nZeros = 0; + for ( i = 0; i < p->nPats; i++ ) + { + // skip don't-care patterns + if ( !Abc_InfoHasBit(pInfoCare, i) ) + { + nDcs++; + continue; + } + // separate offset and onset patterns + if ( !Abc_InfoHasBit(pInfoNode, i) ) + nZeros++; + else + nOnes++; + } + printf( "On = %3d (%7.2f %%) ", nOnes, 100.0*nOnes/p->nPats ); + printf( "Off = %3d (%7.2f %%) ", nZeros, 100.0*nZeros/p->nPats ); + printf( "Dc = %3d (%7.2f %%) ", nDcs, 100.0*nDcs/p->nPats ); + printf( "P0 = %3d ", p->nPats0 ); + printf( "P1 = %3d ", p->nPats1 ); + if ( p->nPats0 < 4 || p->nPats1 < 4 ) + printf( "*" ); + printf( "\n" ); +} + +/**Function************************************************************* + + Synopsis [Prints output patterns.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_SimPrintOutPatterns( Res_Sim_t * p, Abc_Ntk_t * pAig ) +{ + Abc_Obj_t * pObj; + unsigned * pInfo2; + int i; + Abc_NtkForEachPo( pAig, pObj, i ) + { + pInfo2 = Vec_PtrEntry( p->vOuts, i ); + Extra_PrintBinary( stdout, pInfo2, p->nPatsOut ); + printf( "\n" ); + } +} + +/**Function************************************************************* + + Synopsis [Prepares simulation info for candidate filtering.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Res_SimPrepare( Res_Sim_t * p, Abc_Ntk_t * pAig, int nTruePis, int fVerbose ) +{ + int Limit; + // prepare the manager + Res_SimAdjust( p, pAig ); + // collect 0/1 simulation info + for ( Limit = 0; Limit < 10; Limit++ ) + { + Res_SimSetRandom( p ); + Res_SimPerformRound( p ); + Res_SimProcessPats( p ); + if ( !(p->nPats0 < p->nPats || p->nPats1 < p->nPats) ) + break; + } +// printf( "%d ", Limit ); + // report the last set of patterns +// Res_SimReportOne( p ); +// printf( "\n" ); + // quit if there is not enough +// if ( p->nPats0 < 4 || p->nPats1 < 4 ) + if ( p->nPats0 < 4 || p->nPats1 < 4 ) + { +// Res_SimReportOne( p ); + return 0; + } + // create bit-matrix info + if ( p->nPats0 < p->nPats ) + Res_SimPadSimInfo( p->vPats0, p->nPats0, p->nWords ); + if ( p->nPats1 < p->nPats ) + Res_SimPadSimInfo( p->vPats1, p->nPats1, p->nWords ); + // resimulate 0-patterns + Res_SimSetGiven( p, p->vPats0 ); + Res_SimPerformRound( p ); + Res_SimDeriveInfoReplicate( p ); + // resimulate 1-patterns + Res_SimSetGiven( p, p->vPats1 ); + Res_SimPerformRound( p ); + Res_SimDeriveInfoComplement( p ); + // print output patterns +// Res_SimPrintOutPatterns( p, pAig ); + return 1; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/res/resStrash.c b/src/opt/res/resStrash.c new file mode 100644 index 00000000..fde842a4 --- /dev/null +++ b/src/opt/res/resStrash.c @@ -0,0 +1,117 @@ +/**CFile**************************************************************** + + FileName [resStrash.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Resynthesis package.] + + Synopsis [Structural hashing of the nodes in the window.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - January 15, 2007.] + + Revision [$Id: resStrash.c,v 1.00 2007/01/15 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "resInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +extern Abc_Obj_t * Abc_ConvertAigToAig( Abc_Ntk_t * pAig, Abc_Obj_t * pObjOld ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Structurally hashes the given window.] + + Description [The first PO is the observability condition. The second + is the node's function. The remaining POs are the candidate divisors.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Abc_Ntk_t * Res_WndStrash( Res_Win_t * p ) +{ + Vec_Ptr_t * vPairs; + Abc_Ntk_t * pAig; + Abc_Obj_t * pObj, * pMiter; + int i; + assert( Abc_NtkHasAig(p->pNode->pNtk) ); +// Abc_NtkCleanCopy( p->pNode->pNtk ); + // create the network + pAig = Abc_NtkAlloc( ABC_NTK_STRASH, ABC_FUNC_AIG, 1 ); + pAig->pName = Extra_UtilStrsav( "window" ); + // create the inputs + Vec_PtrForEachEntry( p->vLeaves, pObj, i ) + pObj->pCopy = Abc_NtkCreatePi( pAig ); + Vec_PtrForEachEntry( p->vBranches, pObj, i ) + pObj->pCopy = Abc_NtkCreatePi( pAig ); + // go through the nodes in the topological order + Vec_PtrForEachEntry( p->vNodes, pObj, i ) + { + pObj->pCopy = Abc_ConvertAigToAig( pAig, pObj ); + if ( pObj == p->pNode ) + pObj->pCopy = Abc_ObjNot( pObj->pCopy ); + } + // collect the POs + vPairs = Vec_PtrAlloc( 2 * Vec_PtrSize(p->vRoots) ); + Vec_PtrForEachEntry( p->vRoots, pObj, i ) + { + Vec_PtrPush( vPairs, pObj->pCopy ); + Vec_PtrPush( vPairs, NULL ); + } + // mark the TFO of the node + Abc_NtkIncrementTravId( p->pNode->pNtk ); + Res_WinSweepLeafTfo_rec( p->pNode, (int)p->pNode->Level + p->nWinTfoMax ); + // update strashing of the node + p->pNode->pCopy = Abc_ObjNot( p->pNode->pCopy ); + Abc_NodeSetTravIdPrevious( p->pNode ); + // redo strashing in the TFO + Vec_PtrForEachEntry( p->vNodes, pObj, i ) + { + if ( Abc_NodeIsTravIdCurrent(pObj) ) + pObj->pCopy = Abc_ConvertAigToAig( pAig, pObj ); + } + // collect the POs + Vec_PtrForEachEntry( p->vRoots, pObj, i ) + Vec_PtrWriteEntry( vPairs, 2 * i + 1, pObj->pCopy ); + // add the miter + pMiter = Abc_AigMiter( pAig->pManFunc, vPairs ); + Abc_ObjAddFanin( Abc_NtkCreatePo(pAig), pMiter ); + Vec_PtrFree( vPairs ); + // add the node + Abc_ObjAddFanin( Abc_NtkCreatePo(pAig), p->pNode->pCopy ); + // add the fanins + Abc_ObjForEachFanin( p->pNode, pObj, i ) + Abc_ObjAddFanin( Abc_NtkCreatePo(pAig), pObj->pCopy ); + // add the divisors + Vec_PtrForEachEntry( p->vDivs, pObj, i ) + Abc_ObjAddFanin( Abc_NtkCreatePo(pAig), pObj->pCopy ); + // add the names + Abc_NtkAddDummyPiNames( pAig ); + Abc_NtkAddDummyPoNames( pAig ); + // check the resulting network + if ( !Abc_NtkCheck( pAig ) ) + fprintf( stdout, "Res_WndStrash(): Network check has failed.\n" ); + return pAig; +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/res/resWin.c b/src/opt/res/resWin.c new file mode 100644 index 00000000..a3648925 --- /dev/null +++ b/src/opt/res/resWin.c @@ -0,0 +1,485 @@ +/**CFile**************************************************************** + + FileName [resWin.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Resynthesis package.] + + Synopsis [Windowing algorithm.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - January 15, 2007.] + + Revision [$Id: resWin.c,v 1.00 2007/01/15 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "resInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Allocates the window.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Res_Win_t * Res_WinAlloc() +{ + Res_Win_t * p; + // start the manager + p = ALLOC( Res_Win_t, 1 ); + memset( p, 0, sizeof(Res_Win_t) ); + // set internal parameters + p->nFanoutLimit = 10; + p->nLevTfiMinus = 3; + // allocate storage + p->vRoots = Vec_PtrAlloc( 256 ); + p->vLeaves = Vec_PtrAlloc( 256 ); + p->vBranches = Vec_PtrAlloc( 256 ); + p->vNodes = Vec_PtrAlloc( 256 ); + p->vDivs = Vec_PtrAlloc( 256 ); + p->vMatrix = Vec_VecStart( 128 ); + return p; +} + +/**Function************************************************************* + + Synopsis [Frees the window.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_WinFree( Res_Win_t * p ) +{ + Vec_PtrFree( p->vRoots ); + Vec_PtrFree( p->vLeaves ); + Vec_PtrFree( p->vBranches ); + Vec_PtrFree( p->vNodes ); + Vec_PtrFree( p->vDivs ); + Vec_VecFree( p->vMatrix ); + free( p ); +} + + + +/**Function************************************************************* + + Synopsis [Collect the limited TFI cone of the node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Res_WinCollectLeavesAndNodes( Res_Win_t * p ) +{ + Vec_Ptr_t * vFront; + Abc_Obj_t * pObj, * pTemp; + int i, k, m; + + assert( p->nWinTfiMax > 0 ); + assert( Vec_VecSize(p->vMatrix) > p->nWinTfiMax ); + + // start matrix with the node + Vec_VecClear( p->vMatrix ); + Vec_VecPush( p->vMatrix, 0, p->pNode ); + Abc_NtkIncrementTravId( p->pNode->pNtk ); + Abc_NodeSetTravIdCurrent( p->pNode ); + + // collect the leaves (nodes pTemp such that "p->pNode->Level - pTemp->Level > p->nWinTfiMax") + Vec_PtrClear( p->vLeaves ); + Vec_VecForEachLevelStartStop( p->vMatrix, vFront, i, 0, p->nWinTfiMax ) + { + Vec_PtrForEachEntry( vFront, pObj, k ) + { + Abc_ObjForEachFanin( pObj, pTemp, m ) + { + if ( Abc_NodeIsTravIdCurrent( pTemp ) ) + continue; + Abc_NodeSetTravIdCurrent( pTemp ); + if ( Abc_ObjIsCi(pTemp) || (int)(p->pNode->Level - pTemp->Level) > p->nWinTfiMax ) + Vec_PtrPush( p->vLeaves, pTemp ); + else + Vec_VecPush( p->vMatrix, p->pNode->Level - pTemp->Level, pTemp ); + } + } + } + if ( Vec_PtrSize(p->vLeaves) == 0 ) + return 0; + + // collect the nodes in the reverse order + Vec_PtrClear( p->vNodes ); + Vec_VecForEachLevelReverseStartStop( p->vMatrix, vFront, i, p->nWinTfiMax, 0 ) + { + Vec_PtrForEachEntry( vFront, pObj, k ) + Vec_PtrPush( p->vNodes, pObj ); + Vec_PtrClear( vFront ); + } + + // get the lowest leaf level + p->nLevLeafMin = ABC_INFINITY; + Vec_PtrForEachEntry( p->vLeaves, pObj, k ) + p->nLevLeafMin = ABC_MIN( p->nLevLeafMin, (int)pObj->Level ); + + // set minimum traversal level + p->nLevTravMin = ABC_MAX( ((int)p->pNode->Level) - p->nWinTfiMax - p->nLevTfiMinus, p->nLevLeafMin ); + assert( p->nLevTravMin >= 0 ); + return 1; +} + + + +/**Function************************************************************* + + Synopsis [Returns 1 if the node should be a root.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Res_WinComputeRootsCheck( Abc_Obj_t * pNode, int nLevelMax, int nFanoutLimit ) +{ + Abc_Obj_t * pFanout; + int i; + // the node is the root if one of the following is true: + // (1) the node has more than fanouts than the limit + if ( Abc_ObjFanoutNum(pNode) > nFanoutLimit ) + return 1; + // (2) the node has CO fanouts + // (3) the node has fanouts above the cutoff level + Abc_ObjForEachFanout( pNode, pFanout, i ) + if ( Abc_ObjIsCo(pFanout) || (int)pFanout->Level > nLevelMax ) + return 1; + return 0; +} + +/**Function************************************************************* + + Synopsis [Recursively collects the root candidates.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_WinComputeRoots_rec( Abc_Obj_t * pNode, int nLevelMax, int nFanoutLimit, Vec_Ptr_t * vRoots ) +{ + Abc_Obj_t * pFanout; + int i; + assert( Abc_ObjIsNode(pNode) ); + if ( Abc_NodeIsTravIdCurrent(pNode) ) + return; + Abc_NodeSetTravIdCurrent( pNode ); + // check if the node should be the root + if ( Res_WinComputeRootsCheck( pNode, nLevelMax, nFanoutLimit ) ) + Vec_PtrPush( vRoots, pNode ); + else // if not, explore its fanouts + Abc_ObjForEachFanout( pNode, pFanout, i ) + Res_WinComputeRoots_rec( pFanout, nLevelMax, nFanoutLimit, vRoots ); +} + +/**Function************************************************************* + + Synopsis [Recursively collects the root candidates.] + + Description [Returns 1 if the only root is this node.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Res_WinComputeRoots( Res_Win_t * p ) +{ + Vec_PtrClear( p->vRoots ); + Abc_NtkIncrementTravId( p->pNode->pNtk ); + Res_WinComputeRoots_rec( p->pNode, p->pNode->Level + p->nWinTfoMax, p->nFanoutLimit, p->vRoots ); + assert( Vec_PtrSize(p->vRoots) > 0 ); + if ( Vec_PtrSize(p->vRoots) == 1 && Vec_PtrEntry(p->vRoots, 0) == p->pNode ) + return 0; + return 1; +} + + + +/**Function************************************************************* + + Synopsis [Marks the paths from the roots to the leaves.] + + Description [Returns 1 if the the node can reach a leaf.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Res_WinMarkPaths_rec( Abc_Obj_t * pNode, Abc_Obj_t * pPivot, int nLevelMin ) +{ + Abc_Obj_t * pFanin; + int i, RetValue; + // skip visited nodes + if ( Abc_NodeIsTravIdCurrent(pNode) ) + return 1; + if ( Abc_NodeIsTravIdPrevious(pNode) ) + return 0; + // assume that the node does not have access to the leaves + Abc_NodeSetTravIdPrevious( pNode ); + // skip nodes below the given level + if ( pNode == pPivot || (int)pNode->Level <= nLevelMin ) + return 0; + assert( Abc_ObjIsNode(pNode) ); + // check if the fanins have access to the leaves + RetValue = 0; + Abc_ObjForEachFanin( pNode, pFanin, i ) + RetValue |= Res_WinMarkPaths_rec( pFanin, pPivot, nLevelMin ); + // relabel the node if it has access to the leaves + if ( RetValue ) + Abc_NodeSetTravIdCurrent( pNode ); + return RetValue; +} + +/**Function************************************************************* + + Synopsis [Marks the paths from the roots to the leaves.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_WinMarkPaths( Res_Win_t * p ) +{ + Abc_Obj_t * pObj; + int i; + // mark the leaves + Abc_NtkIncrementTravId( p->pNode->pNtk ); + Abc_NtkIncrementTravId( p->pNode->pNtk ); + Vec_PtrForEachEntry( p->vLeaves, pObj, i ) + Abc_NodeSetTravIdCurrent( pObj ); + // traverse from the roots and mark the nodes that can reach leaves + // the nodes that do not reach leaves have previous trav ID + // the nodes that reach leaves have current trav ID + Vec_PtrForEachEntry( p->vRoots, pObj, i ) + Res_WinMarkPaths_rec( pObj, p->pNode, p->nLevTravMin ); +} + + + + +/**Function************************************************************* + + Synopsis [Recursively collects the roots.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_WinFinalizeRoots_rec( Abc_Obj_t * pObj, Vec_Ptr_t * vRoots ) +{ + Abc_Obj_t * pFanout; + int i; + assert( Abc_ObjIsNode(pObj) ); + assert( Abc_NodeIsTravIdCurrent(pObj) ); + // check if the node has all fanouts marked + Abc_ObjForEachFanout( pObj, pFanout, i ) + if ( !Abc_NodeIsTravIdCurrent(pFanout) ) + break; + // if some of the fanouts are unmarked, add the node to the roots + if ( i < Abc_ObjFanoutNum(pObj) ) + Vec_PtrPushUnique( vRoots, pObj ); + else // otherwise, call recursively + Abc_ObjForEachFanout( pObj, pFanout, i ) + Res_WinFinalizeRoots_rec( pFanout, vRoots ); +} + +/**Function************************************************************* + + Synopsis [Finalizes the roots of the window.] + + Description [Roots of the window are the nodes that have at least + one fanout that it not in the TFO of the leaves.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Res_WinFinalizeRoots( Res_Win_t * p ) +{ + assert( !Abc_NodeIsTravIdCurrent(p->pNode) ); + // mark the node with the old traversal ID + Abc_NodeSetTravIdCurrent( p->pNode ); + // recollect the roots + Vec_PtrClear( p->vRoots ); + Res_WinFinalizeRoots_rec( p->pNode, p->vRoots ); + assert( Vec_PtrSize(p->vRoots) > 0 ); + if ( Vec_PtrSize(p->vRoots) == 1 && Vec_PtrEntry(p->vRoots, 0) == p->pNode ) + return 0; + return 1; +} + + +/**Function************************************************************* + + Synopsis [Recursively adds missing nodes and leaves.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_WinAddMissing_rec( Res_Win_t * p, Abc_Obj_t * pObj, int nLevTravMin ) +{ + Abc_Obj_t * pFanin; + int i; + // skip the already collected leaves, nodes, and branches + if ( Abc_NodeIsTravIdCurrent(pObj) ) + return; + // if this is not an internal node - make it a new branch + if ( !Abc_NodeIsTravIdPrevious(pObj) ) + { + assert( Vec_PtrFind(p->vLeaves, pObj) == -1 ); + Abc_NodeSetTravIdCurrent( pObj ); + Vec_PtrPush( p->vBranches, pObj ); + return; + } + assert( Abc_ObjIsNode(pObj) ); // if this is a CI, then the window is incorrect! + Abc_NodeSetTravIdCurrent( pObj ); + // visit the fanins of the node + Abc_ObjForEachFanin( pObj, pFanin, i ) + Res_WinAddMissing_rec( p, pFanin, nLevTravMin ); + // collect the node + Vec_PtrPush( p->vNodes, pObj ); +} + +/**Function************************************************************* + + Synopsis [Adds to the window nodes and leaves in the TFI of the roots.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Res_WinAddMissing( Res_Win_t * p ) +{ + Abc_Obj_t * pObj; + int i; + // mark the leaves + Abc_NtkIncrementTravId( p->pNode->pNtk ); + Vec_PtrForEachEntry( p->vLeaves, pObj, i ) + Abc_NodeSetTravIdCurrent( pObj ); + // mark the already collected nodes + Vec_PtrForEachEntry( p->vNodes, pObj, i ) + Abc_NodeSetTravIdCurrent( pObj ); + // explore from the roots + Vec_PtrClear( p->vBranches ); + Vec_PtrForEachEntry( p->vRoots, pObj, i ) + Res_WinAddMissing_rec( p, pObj, p->nLevTravMin ); +} + + + + +/**Function************************************************************* + + Synopsis [Returns 1 if the window is trivial (without TFO).] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Res_WinIsTrivial( Res_Win_t * p ) +{ + return Vec_PtrSize(p->vRoots) == 1 && Vec_PtrEntry(p->vRoots, 0) == p->pNode; +} + +/**Function************************************************************* + + Synopsis [Computes the window.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Res_WinCompute( Abc_Obj_t * pNode, int nWinTfiMax, int nWinTfoMax, Res_Win_t * p ) +{ + assert( Abc_ObjIsNode(pNode) ); + assert( nWinTfiMax > 0 && nWinTfiMax < 10 ); + assert( nWinTfoMax >= 0 && nWinTfoMax < 10 ); + + // initialize the window + p->pNode = pNode; + p->nWinTfiMax = nWinTfiMax; + p->nWinTfoMax = nWinTfoMax; + + Vec_PtrClear( p->vBranches ); + Vec_PtrClear( p->vDivs ); + Vec_PtrClear( p->vRoots ); + Vec_PtrPush( p->vRoots, pNode ); + + // compute the leaves + if ( !Res_WinCollectLeavesAndNodes( p ) ) + return 0; + + // compute the candidate roots + if ( p->nWinTfoMax > 0 && Res_WinComputeRoots(p) ) + { + // mark the paths from the roots to the leaves + Res_WinMarkPaths( p ); + // refine the roots and add branches and missing nodes + if ( Res_WinFinalizeRoots( p ) ) + Res_WinAddMissing( p ); + } + + return 1; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/res/res_.c b/src/opt/res/res_.c new file mode 100644 index 00000000..a50affd7 --- /dev/null +++ b/src/opt/res/res_.c @@ -0,0 +1,50 @@ +/**CFile**************************************************************** + + FileName [res_.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Resynthesis package.] + + Synopsis [] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - January 15, 2007.] + + Revision [$Id: res_.c,v 1.00 2007/01/15 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "res.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ + + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/ret/module.make b/src/opt/ret/module.make new file mode 100644 index 00000000..4b14365e --- /dev/null +++ b/src/opt/ret/module.make @@ -0,0 +1,8 @@ +SRC += src/opt/ret/retArea.c \ + src/opt/ret/retCore.c \ + src/opt/ret/retDelay.c \ + src/opt/ret/retFlow.c \ + src/opt/ret/retIncrem.c \ + src/opt/ret/retInit.c \ + src/opt/ret/retLvalue.c + diff --git a/src/opt/ret/retArea.c b/src/opt/ret/retArea.c new file mode 100644 index 00000000..5eec8e80 --- /dev/null +++ b/src/opt/ret/retArea.c @@ -0,0 +1,540 @@ +/**CFile**************************************************************** + + FileName [retArea.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Retiming package.] + + Synopsis [Min-area retiming.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - Oct 31, 2006.] + + Revision [$Id: retArea.c,v 1.00 2006/10/31 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "retInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static Abc_Ntk_t * Abc_NtkRetimeMinAreaOne( Abc_Ntk_t * pNtk, int fForward, int fVerbose ); +static void Abc_NtkRetimeMinAreaPrepare( Abc_Ntk_t * pNtk, int fForward ); +static void Abc_NtkRetimeMinAreaInitValues( Abc_Ntk_t * pNtk, Vec_Ptr_t * vMinCut ); +static Abc_Ntk_t * Abc_NtkRetimeMinAreaConstructNtk( Abc_Ntk_t * pNtk, Vec_Ptr_t * vMinCut ); +static void Abc_NtkRetimeMinAreaUpdateLatches( Abc_Ntk_t * pNtk, Vec_Ptr_t * vMinCut, int fForward ); + +extern Abc_Ntk_t * Abc_NtkAttachBottom( Abc_Ntk_t * pNtkTop, Abc_Ntk_t * pNtkBottom ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Performs min-area retiming.] + + Description [Returns the number of latches reduced.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkRetimeMinArea( Abc_Ntk_t * pNtk, int fForwardOnly, int fBackwardOnly, int fVerbose ) +{ + Abc_Ntk_t * pNtkTotal = NULL, * pNtkBottom; + Vec_Int_t * vValuesNew = NULL, * vValues; + int nLatches = Abc_NtkLatchNum(pNtk); + int fOneFrame = 0; + assert( !fForwardOnly || !fBackwardOnly ); + // there should not be black boxes + assert( Abc_NtkIsSopLogic(pNtk) ); + assert( Abc_NtkLatchNum(pNtk) == Vec_PtrSize(pNtk->vBoxes) ); + // reorder CI/CO/latch inputs + Abc_NtkOrderCisCos( pNtk ); + // perform forward retiming + if ( !fBackwardOnly ) + { + if ( fOneFrame ) + Abc_NtkRetimeMinAreaOne( pNtk, 1, fVerbose ); + else + while ( Abc_NtkRetimeMinAreaOne( pNtk, 1, fVerbose ) ); + } + // remember initial values + vValues = Abc_NtkCollectLatchValues( pNtk ); + // perform backward retiming + if ( !fForwardOnly ) + { + if ( fOneFrame ) + pNtkTotal = Abc_NtkRetimeMinAreaOne( pNtk, 0, fVerbose ); + else + while ( pNtkBottom = Abc_NtkRetimeMinAreaOne( pNtk, 0, fVerbose ) ) + pNtkTotal = Abc_NtkAttachBottom( pNtkTotal, pNtkBottom ); + } + // compute initial values + vValuesNew = Abc_NtkRetimeInitialValues( pNtkTotal, vValues, fVerbose ); + if ( pNtkTotal ) Abc_NtkDelete( pNtkTotal ); + // insert new initial values + Abc_NtkInsertLatchValues( pNtk, vValuesNew ); + if ( vValuesNew ) Vec_IntFree( vValuesNew ); + if ( vValues ) Vec_IntFree( vValues ); + // fix the COs (this changes the circuit structure) +// Abc_NtkLogicMakeSimpleCos( pNtk, 0 ); + // check for correctness + if ( !Abc_NtkCheck( pNtk ) ) + fprintf( stdout, "Abc_NtkRetimeMinArea(): Network check has failed.\n" ); + // return the number of latches saved + return nLatches - Abc_NtkLatchNum(pNtk); +} + +/**Function************************************************************* + + Synopsis [Performs min-area retiming backward.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Abc_Ntk_t * Abc_NtkRetimeMinAreaOne( Abc_Ntk_t * pNtk, int fForward, int fVerbose ) +{ + Abc_Ntk_t * pNtkNew = NULL; + Vec_Ptr_t * vMinCut; + int nLatches = Abc_NtkLatchNum(pNtk); + // mark current latches and TFI(POs) + Abc_NtkRetimeMinAreaPrepare( pNtk, fForward ); + // run the maximum forward flow + vMinCut = Abc_NtkMaxFlow( pNtk, fForward, fVerbose ); +// assert( Vec_PtrSize(vMinCut) <= Abc_NtkLatchNum(pNtk) ); + // create new latch boundary if there is improvement + if ( Vec_PtrSize(vMinCut) < Abc_NtkLatchNum(pNtk) ) + { + pNtkNew = (Abc_Ntk_t *)1; + if ( fForward ) + Abc_NtkRetimeMinAreaInitValues( pNtk, vMinCut ); + else + pNtkNew = Abc_NtkRetimeMinAreaConstructNtk( pNtk, vMinCut ); + Abc_NtkRetimeMinAreaUpdateLatches( pNtk, vMinCut, fForward ); + } + // clean up + Vec_PtrFree( vMinCut ); + Abc_NtkCleanMarkA( pNtk ); + return pNtkNew; +} + +/**Function************************************************************* + + Synopsis [Marks the cone with MarkA.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NtkMarkCone_rec( Abc_Obj_t * pObj, int fForward ) +{ + Abc_Obj_t * pNext; + int i; + if ( pObj->fMarkA ) + return; + pObj->fMarkA = 1; + if ( fForward ) + { + Abc_ObjForEachFanout( pObj, pNext, i ) + Abc_NtkMarkCone_rec( pNext, fForward ); + } + else + { + Abc_ObjForEachFanin( pObj, pNext, i ) + Abc_NtkMarkCone_rec( pNext, fForward ); + } +} + +/**Function************************************************************* + + Synopsis [Marks the cone with MarkA.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NtkUnmarkCone_rec( Abc_Obj_t * pObj, int fForward ) +{ + Abc_Obj_t * pNext; + int i; + if ( !pObj->fMarkA || Abc_ObjIsLatch(pObj) ) + return; + pObj->fMarkA = 0; + if ( fForward ) + { + Abc_ObjForEachFanout( pObj, pNext, i ) + Abc_NtkUnmarkCone_rec( pNext, fForward ); + } + else + { + Abc_ObjForEachFanin( pObj, pNext, i ) + Abc_NtkUnmarkCone_rec( pNext, fForward ); + } +} + +/**Function************************************************************* + + Synopsis [Prepares the network for running MaxFlow.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NtkRetimeMinAreaPrepare( Abc_Ntk_t * pNtk, int fForward ) +{ + Vec_Ptr_t * vNodes; + Abc_Obj_t * pObj, * pFanin; + int i, k; + if ( fForward ) + { + // mark the frontier + Abc_NtkForEachPo( pNtk, pObj, i ) + pObj->fMarkA = 1; + Abc_NtkForEachLatch( pNtk, pObj, i ) + { + pObj->fMarkA = 1; + Abc_ObjFanin0(pObj)->fMarkA = 1; + } + // mark the nodes reachable from the PIs + Abc_NtkForEachPi( pNtk, pObj, i ) + Abc_NtkMarkCone_rec( pObj, fForward ); + // collect the unmarked fanins of the marked nodes + vNodes = Vec_PtrAlloc( 100 ); + Abc_NtkForEachObj( pNtk, pObj, i ) + if ( pObj->fMarkA ) + Abc_ObjForEachFanin( pObj, pFanin, k ) + if ( !pFanin->fMarkA ) + Vec_PtrPush( vNodes, pFanin ); + // mark these nodes + Vec_PtrForEachEntry( vNodes, pObj, i ) + pObj->fMarkA = 1; + Vec_PtrFree( vNodes ); + } + else + { + // mark the frontier + Abc_NtkForEachPi( pNtk, pObj, i ) + pObj->fMarkA = 1; + Abc_NtkForEachLatch( pNtk, pObj, i ) + { + pObj->fMarkA = 1; + Abc_ObjFanout0(pObj)->fMarkA = 1; + } + // mark the nodes reachable from the POs + Abc_NtkForEachPo( pNtk, pObj, i ) + Abc_NtkMarkCone_rec( pObj, fForward ); + } +} + +/**Function************************************************************* + + Synopsis [Compute initial values.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkRetimeMinAreaInitValues_rec( Abc_Obj_t * pObj ) +{ + Abc_Obj_t * pFanin; + int i; + // skip visited nodes + if ( Abc_NodeIsTravIdCurrent(pObj) ) + return (int)pObj->pCopy; + Abc_NodeSetTravIdCurrent(pObj); + // consider the case of a latch output + if ( Abc_ObjIsBo(pObj) ) + { + assert( Abc_ObjIsLatch(Abc_ObjFanin0(pObj)) ); + pObj->pCopy = (void *)Abc_NtkRetimeMinAreaInitValues_rec( Abc_ObjFanin0(pObj) ); + return (int)pObj->pCopy; + } + assert( Abc_ObjIsNode(pObj) ); + // visit the fanins + Abc_ObjForEachFanin( pObj, pFanin, i ) + Abc_NtkRetimeMinAreaInitValues_rec( pFanin ); + // compute the value of the node + pObj->pCopy = (void *)Abc_ObjSopSimulate(pObj); + return (int)pObj->pCopy; +} + +/**Function************************************************************* + + Synopsis [Compute initial values.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NtkRetimeMinAreaInitValues( Abc_Ntk_t * pNtk, Vec_Ptr_t * vMinCut ) +{ + Abc_Obj_t * pObj; + int i; + // transfer initial values to pCopy and mark the latches + Abc_NtkIncrementTravId(pNtk); + Abc_NtkForEachLatch( pNtk, pObj, i ) + { + pObj->pCopy = (void *)Abc_LatchIsInit1(pObj); + Abc_NodeSetTravIdCurrent( pObj ); + } + // propagate initial values + Vec_PtrForEachEntry( vMinCut, pObj, i ) + Abc_NtkRetimeMinAreaInitValues_rec( pObj ); + // unmark the latches + Abc_NtkForEachLatch( pNtk, pObj, i ) + Abc_NodeSetTravIdPrevious( pObj ); +} + +/**Function************************************************************* + + Synopsis [Performs min-area retiming backward.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Abc_Obj_t * Abc_NtkRetimeMinAreaConstructNtk_rec( Abc_Ntk_t * pNtkNew, Abc_Obj_t * pObj ) +{ + Abc_Obj_t * pFanin; + int i; + // skip visited nodes + if ( Abc_NodeIsTravIdCurrent(pObj) ) + return pObj->pCopy; + Abc_NodeSetTravIdCurrent(pObj); + // consider the case of a latch output + if ( Abc_ObjIsBi(pObj) ) + { + pObj->pCopy = Abc_NtkRetimeMinAreaConstructNtk_rec( pNtkNew, Abc_ObjFanin0(pObj) ); + return pObj->pCopy; + } + assert( Abc_ObjIsNode(pObj) ); + // visit the fanins + Abc_ObjForEachFanin( pObj, pFanin, i ) + Abc_NtkRetimeMinAreaConstructNtk_rec( pNtkNew, pFanin ); + // compute the value of the node + Abc_NtkDupObj( pNtkNew, pObj, 0 ); + Abc_ObjForEachFanin( pObj, pFanin, i ) + Abc_ObjAddFanin( pObj->pCopy, pFanin->pCopy ); + return pObj->pCopy; +} + +/**Function************************************************************* + + Synopsis [Creates the network from computing initial state.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Abc_Ntk_t * Abc_NtkRetimeMinAreaConstructNtk( Abc_Ntk_t * pNtk, Vec_Ptr_t * vMinCut ) +{ + Abc_Ntk_t * pNtkNew; + Abc_Obj_t * pObj, * pObjNew; + int i; + // create new network + pNtkNew = Abc_NtkAlloc( ABC_NTK_LOGIC, ABC_FUNC_SOP, 1 ); + // map new latches into PIs of the new network + Abc_NtkIncrementTravId(pNtk); + Vec_PtrForEachEntry( vMinCut, pObj, i ) + { + pObj->pCopy = Abc_NtkCreatePi(pNtkNew); + Abc_NodeSetTravIdCurrent( pObj ); + } + // construct the network recursively + Abc_NtkForEachLatch( pNtk, pObj, i ) + { + pObjNew = Abc_NtkRetimeMinAreaConstructNtk_rec( pNtkNew, Abc_ObjFanin0(pObj) ); + Abc_ObjAddFanin( Abc_NtkCreatePo(pNtkNew), pObjNew ); + } + // unmark the nodes in the cut + Vec_PtrForEachEntry( vMinCut, pObj, i ) + Abc_NodeSetTravIdPrevious( pObj ); + // unmark the latches + Abc_NtkForEachLatch( pNtk, pObj, i ) + Abc_NodeSetTravIdPrevious( pObj ); + // assign dummy node names + Abc_NtkAddDummyPiNames( pNtkNew ); + Abc_NtkAddDummyPoNames( pNtkNew ); + if ( !Abc_NtkCheck( pNtkNew ) ) + fprintf( stdout, "Abc_NtkRetimeMinAreaConstructNtk(): Network check has failed.\n" ); + return pNtkNew; +} + +/**Function************************************************************* + + Synopsis [Updates the network after backward retiming.] + + Description [Assumes that fMarkA denotes all nodes reachabe from + the latches toward the cut.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NtkRetimeMinAreaUpdateLatches( Abc_Ntk_t * pNtk, Vec_Ptr_t * vMinCut, int fForward ) +{ + Vec_Ptr_t * vCis, * vCos, * vBoxes, * vBoxesNew, * vNodes, * vBuffers; + Abc_Obj_t * pObj, * pLatch, * pLatchIn, * pLatchOut, * pNext, * pBuffer; + int i, k; + // create new latches + Vec_PtrShrink( pNtk->vCis, Abc_NtkCiNum(pNtk) - Abc_NtkLatchNum(pNtk) ); + Vec_PtrShrink( pNtk->vCos, Abc_NtkCoNum(pNtk) - Abc_NtkLatchNum(pNtk) ); + vCis = pNtk->vCis; pNtk->vCis = NULL; + vCos = pNtk->vCos; pNtk->vCos = NULL; + vBoxes = pNtk->vBoxes; pNtk->vBoxes = NULL; + // transfer boxes + vBoxesNew = Vec_PtrAlloc(100); + Vec_PtrForEachEntry( vBoxes, pObj, i ) + if ( !Abc_ObjIsLatch(pObj) ) + Vec_PtrPush( vBoxesNew, pObj ); + // create or reuse latches + vNodes = Vec_PtrAlloc( 100 ); + vBuffers = Vec_PtrAlloc( 100 ); + Vec_PtrForEachEntry( vMinCut, pObj, i ) + { + if ( Abc_ObjIsCi(pObj) && fForward ) + { + pLatchOut = pObj; + pLatch = Abc_ObjFanin0(pLatchOut); + pLatchIn = Abc_ObjFanin0(pLatch); + assert( Abc_ObjIsBo(pLatchOut) && Abc_ObjIsLatch(pLatch) && Abc_ObjIsBi(pLatchIn) ); + // mark the latch as reused + Abc_NodeSetTravIdCurrent( pLatch ); + + // check if there are marked fanouts + // (these are fanouts to be connected to the latch input) + Abc_ObjForEachFanout( pObj, pNext, k ) + if ( pNext->fMarkA ) + break; + if ( k < Abc_ObjFanoutNum(pObj) ) + { + // add the buffer + pBuffer = Abc_NtkCreateNodeBuf( pNtk, Abc_ObjFanin0(pLatchIn) ); + Abc_ObjPatchFanin( pLatchIn, Abc_ObjFanin0(pLatchIn), pBuffer ); + Vec_PtrPush( vBuffers, pBuffer ); + // redirect edges to the unvisited fanouts of the node + Abc_NodeCollectFanouts( pObj, vNodes ); + Vec_PtrForEachEntry( vNodes, pNext, k ) + if ( pNext->fMarkA ) + Abc_ObjPatchFanin( pNext, pObj, pBuffer ); + } + assert( Abc_ObjFanoutNum(pObj) > 0 ); +// if ( Abc_ObjFanoutNum(pObj) == 0 ) +// Abc_NtkDeleteObj_rec( pObj, 0 ); + } + else if ( Abc_ObjIsCo(pObj) && !fForward ) + { + pLatchIn = pObj; + pLatch = Abc_ObjFanout0(pLatchIn); + pLatchOut = Abc_ObjFanout0(pLatch); + assert( Abc_ObjIsBo(pLatchOut) && Abc_ObjIsLatch(pLatch) && Abc_ObjIsBi(pLatchIn) ); + // mark the latch as reused + Abc_NodeSetTravIdCurrent( pLatch ); + assert( !Abc_ObjFanin0(pLatchIn)->fMarkA ); + } + else + { + pLatchOut = Abc_NtkCreateBo(pNtk); + pLatch = Abc_NtkCreateLatch(pNtk); + pLatchIn = Abc_NtkCreateBi(pNtk); + Abc_ObjAssignName( pLatchOut, Abc_ObjName(pLatch), "_out" ); + Abc_ObjAssignName( pLatchIn, Abc_ObjName(pLatch), "_in" ); + // connect + Abc_ObjAddFanin( pLatchOut, pLatch ); + Abc_ObjAddFanin( pLatch, pLatchIn ); + if ( fForward ) + { + pLatch->pData = (void *)(pObj->pCopy? ABC_INIT_ONE : ABC_INIT_ZERO); + // redirect edges to the unvisited fanouts of the node + Abc_NodeCollectFanouts( pObj, vNodes ); + Vec_PtrForEachEntry( vNodes, pNext, k ) + if ( !pNext->fMarkA ) + Abc_ObjPatchFanin( pNext, pObj, pLatchOut ); + } + else + { + // redirect edges to the visited fanouts of the node + Abc_NodeCollectFanouts( pObj, vNodes ); + Vec_PtrForEachEntry( vNodes, pNext, k ) + if ( pNext->fMarkA ) + Abc_ObjPatchFanin( pNext, pObj, pLatchOut ); + } + // connect latch to the node + Abc_ObjAddFanin( pLatchIn, pObj ); + } + Vec_PtrPush( vCis, pLatchOut ); + Vec_PtrPush( vBoxesNew, pLatch ); + Vec_PtrPush( vCos, pLatchIn ); + } + Vec_PtrFree( vNodes ); + // remove buffers + Vec_PtrForEachEntry( vBuffers, pObj, i ) + { + Abc_ObjTransferFanout( pObj, Abc_ObjFanin0(pObj) ); + Abc_NtkDeleteObj( pObj ); + } + Vec_PtrFree( vBuffers ); + // remove useless latches + Vec_PtrForEachEntry( vBoxes, pObj, i ) + { + if ( !Abc_ObjIsLatch(pObj) ) + continue; + if ( Abc_NodeIsTravIdCurrent(pObj) ) + continue; + pLatchOut = Abc_ObjFanout0(pObj); + pLatch = pObj; + pLatchIn = Abc_ObjFanin0(pObj); + if ( Abc_ObjFanoutNum(pLatchOut) > 0 ) + Abc_ObjTransferFanout( pLatchOut, Abc_ObjFanin0(pLatchIn) ); + Abc_NtkDeleteObj( pLatchOut ); + Abc_NtkDeleteObj( pObj ); + Abc_NtkDeleteObj( pLatchIn ); + } + // set the arrays + pNtk->vCis = vCis; + pNtk->vCos = vCos; + pNtk->vBoxes = vBoxesNew; + Vec_PtrFree( vBoxes ); +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/ret/retCore.c b/src/opt/ret/retCore.c new file mode 100644 index 00000000..47b2cbbc --- /dev/null +++ b/src/opt/ret/retCore.c @@ -0,0 +1,132 @@ +/**CFile**************************************************************** + + FileName [retCore.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Retiming package.] + + Synopsis [The core retiming procedures.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - Oct 31, 2006.] + + Revision [$Id: retCore.c,v 1.00 2006/10/31 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "retInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +int timeRetime = 0; + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Implementation of retiming.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkRetime( Abc_Ntk_t * pNtk, int Mode, int fForwardOnly, int fBackwardOnly, int fOneStep, int fVerbose ) +{ + int nLatches = Abc_NtkLatchNum(pNtk); + int nLevels = Abc_NtkLevel(pNtk); + int RetValue = 0, clkTotal = clock(); + int nNodesOld, nLatchesOld; + assert( Mode > 0 && Mode < 7 ); + assert( !fForwardOnly || !fBackwardOnly ); + + // cleanup the network + nNodesOld = Abc_NtkNodeNum(pNtk); + nLatchesOld = Abc_NtkLatchNum(pNtk); + Abc_NtkCleanupSeq(pNtk, 0, 0, 0); + if ( nNodesOld > Abc_NtkNodeNum(pNtk) || nLatchesOld > Abc_NtkLatchNum(pNtk) ) + printf( "Cleanup before retiming removed %d dangling nodes and %d dangling latches.\n", + nNodesOld - Abc_NtkNodeNum(pNtk), nLatchesOld - Abc_NtkLatchNum(pNtk) ); + + // perform retiming + switch ( Mode ) + { + case 1: // forward + RetValue = Abc_NtkRetimeIncremental( pNtk, 1, 0, 0, fVerbose ); + break; + case 2: // backward + RetValue = Abc_NtkRetimeIncremental( pNtk, 0, 0, 0, fVerbose ); + break; + case 3: // min-area + RetValue = Abc_NtkRetimeMinArea( pNtk, fForwardOnly, fBackwardOnly, fVerbose ); + break; + case 4: // min-delay + if ( !fBackwardOnly ) + RetValue += Abc_NtkRetimeIncremental( pNtk, 1, 1, fOneStep, fVerbose ); + if ( !fForwardOnly ) + RetValue += Abc_NtkRetimeIncremental( pNtk, 0, 1, fOneStep, fVerbose ); + break; + case 5: // min-area + min-delay + RetValue = Abc_NtkRetimeMinArea( pNtk, fForwardOnly, fBackwardOnly, fVerbose ); + if ( !fBackwardOnly ) + RetValue += Abc_NtkRetimeIncremental( pNtk, 1, 1, 0, fVerbose ); + if ( !fForwardOnly ) + RetValue += Abc_NtkRetimeIncremental( pNtk, 0, 1, 0, fVerbose ); + break; + case 6: // Pan's algorithm + RetValue = Abc_NtkRetimeLValue( pNtk, 500, fVerbose ); + break; + default: + printf( "Unknown retiming option.\n" ); + break; + } + if ( fVerbose ) + { + printf( "Reduction in area = %3d. Reduction in delay = %3d. ", + nLatches - Abc_NtkLatchNum(pNtk), nLevels - Abc_NtkLevel(pNtk) ); + PRT( "Total runtime", clock() - clkTotal ); + } + timeRetime = clock() - clkTotal; + return RetValue; +} + +/**Function************************************************************* + + Synopsis [Used for automated debugging.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkRetimeDebug( Abc_Ntk_t * pNtk ) +{ + extern int Abc_NtkSecFraig( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int nSeconds, int nFrames, int fVerbose ); + Abc_Ntk_t * pNtkRet; + assert( Abc_NtkIsLogic(pNtk) ); + Abc_NtkToSop( pNtk, 0 ); +// if ( !Abc_NtkCheck( pNtk ) ) +// fprintf( stdout, "Abc_NtkRetimeDebug(): Network check has failed.\n" ); +// Io_WriteBlifLogic( pNtk, "debug_temp.blif", 1 ); + pNtkRet = Abc_NtkDup( pNtk ); + Abc_NtkRetime( pNtkRet, 3, 0, 1, 0, 0 ); // debugging backward flow + return !Abc_NtkSecFraig( pNtk, pNtkRet, 10000, 3, 0 ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/ret/retDelay.c b/src/opt/ret/retDelay.c new file mode 100644 index 00000000..bcfe3a2e --- /dev/null +++ b/src/opt/ret/retDelay.c @@ -0,0 +1,305 @@ +/**CFile**************************************************************** + + FileName [retDelay.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Retiming package.] + + Synopsis [Incremental retiming for optimum delay.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - Oct 31, 2006.] + + Revision [$Id: retDelay.c,v 1.00 2006/10/31 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "retInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static int Abc_NtkRetimeMinDelayTry( Abc_Ntk_t * pNtk, int fForward, int fInitial, int nIterLimit, int * pIterBest, int fVerbose ); +static int Abc_NtkRetimeTiming( Abc_Ntk_t * pNtk, int fForward, Vec_Ptr_t * vCritical ); +static int Abc_NtkRetimeTiming_rec( Abc_Obj_t * pObj, int fForward ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Retimes incrementally for minimum delay.] + + Description [This procedure cannot be called in the application code + because it assumes that the network is preprocessed by removing LIs/LOs.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkRetimeMinDelay( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkCopy, int nIterLimit, int fForward, int fVerbose ) +{ + int IterBest, DelayBest; + int IterBest2, DelayBest2; + // try to find the best delay iteration on a copy + DelayBest = Abc_NtkRetimeMinDelayTry( pNtkCopy, fForward, 0, nIterLimit, &IterBest, fVerbose ); + if ( IterBest == 0 ) + return 1; + // perform the given number of iterations on the original network + DelayBest2 = Abc_NtkRetimeMinDelayTry( pNtk, fForward, 1, IterBest, &IterBest2, fVerbose ); + assert( DelayBest == DelayBest2 ); + assert( IterBest == IterBest2 ); + return 1; +} + +/**Function************************************************************* + + Synopsis [Returns the best delay and the number of best iteration.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkRetimeMinDelayTry( Abc_Ntk_t * pNtk, int fForward, int fInitial, int nIterLimit, int * pIterBest, int fVerbose ) +{ + Abc_Ntk_t * pNtkNew = NULL; + Vec_Ptr_t * vCritical; + Vec_Int_t * vValues; + Abc_Obj_t * pObj; + int i, k, IterBest, DelayCur, DelayBest, DelayStart, LatchesBest; + // transfer intitial values + if ( fInitial ) + { + if ( fForward ) + Abc_NtkRetimeTranferToCopy( pNtk ); + else + { + // save initial value of the latches + vValues = Abc_NtkRetimeCollectLatchValues( pNtk ); + // start the network for initial value computation + pNtkNew = Abc_NtkRetimeBackwardInitialStart( pNtk ); + } + } + +if ( fVerbose && !fInitial ) + printf( "Performing analysis:\n" ); + // find the best iteration + DelayBest = ABC_INFINITY; IterBest = 0; LatchesBest = Abc_NtkLatchNum(pNtk); + vCritical = Vec_PtrAlloc( 100 ); + for ( i = 0; ; i++ ) + { + // perform moves for the timing-critical nodes + DelayCur = Abc_NtkRetimeTiming( pNtk, fForward, vCritical ); + if ( i == 0 ) + DelayStart = DelayCur; + // record this position if it has the best delay + if ( DelayBest > DelayCur ) + { +if ( fVerbose && !fInitial ) + printf( "%s Iter = %3d. Delay = %3d. Latches = %5d. Delta = %6.2f. Ratio = %4.2f %%\n", + fForward ? "Fwd": "Bwd", i, DelayCur, Abc_NtkLatchNum(pNtk), + 1.0*(Abc_NtkLatchNum(pNtk)-LatchesBest)/(DelayBest-DelayCur), + 100.0*(Abc_NtkLatchNum(pNtk)-LatchesBest)/Abc_NtkLatchNum(pNtk)/(DelayBest-DelayCur) ); + + DelayBest = DelayCur; + IterBest = i; + LatchesBest = Abc_NtkLatchNum(pNtk); + } + // quit after timing analysis + if ( i == nIterLimit ) + break; + // skip if 10 interations did not give improvement + if ( i - IterBest > 20 ) + break; + // try retiming to improve the delay + Vec_PtrForEachEntry( vCritical, pObj, k ) + if ( Abc_NtkRetimeNodeIsEnabled(pObj, fForward) ) + Abc_NtkRetimeNode( pObj, fForward, fInitial ); + // share latches + if ( !fForward ) + Abc_NtkRetimeShareLatches( pNtk, fInitial ); + } + Vec_PtrFree( vCritical ); + // transfer the initial state back to the latches + if ( fInitial ) + { + if ( fForward ) + Abc_NtkRetimeTranferFromCopy( pNtk ); + else + { + Abc_NtkRetimeBackwardInitialFinish( pNtk, pNtkNew, vValues, fVerbose ); + Abc_NtkDelete( pNtkNew ); + Vec_IntFree( vValues ); + } + } +if ( fVerbose && !fInitial ) + printf( "%s : Starting delay = %3d. Final delay = %3d. IterBest = %2d (out of %2d).\n", + fForward? "Forward " : "Backward", DelayStart, DelayBest, IterBest, nIterLimit ); + *pIterBest = (nIterLimit == 1) ? 1 : IterBest; + return DelayBest; +} + +/**Function************************************************************* + + Synopsis [Returns the set of timing-critical nodes.] + + Description [Performs static timing analysis on the network. Uses + unit-delay model.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkRetimeTiming( Abc_Ntk_t * pNtk, int fForward, Vec_Ptr_t * vCritical ) +{ + Vec_Ptr_t * vLatches; + Abc_Obj_t * pObj, * pNext; + int i, k, LevelCur, LevelMax = 0; + // mark all objects except nodes + Abc_NtkIncrementTravId(pNtk); + vLatches = Vec_PtrAlloc( Abc_NtkLatchNum(pNtk) ); + Abc_NtkForEachObj( pNtk, pObj, i ) + { + if ( Abc_ObjIsLatch(pObj) ) + Vec_PtrPush( vLatches, pObj ); + if ( Abc_ObjIsNode(pObj) ) + continue; + pObj->Level = 0; + Abc_NodeSetTravIdCurrent( pObj ); + } + // perform analysis from CIs/COs + if ( fForward ) + { + Vec_PtrForEachEntry( vLatches, pObj, i ) + { + Abc_ObjForEachFanout( pObj, pNext, k ) + { + LevelCur = Abc_NtkRetimeTiming_rec( pNext, fForward ); + if ( LevelMax < LevelCur ) + LevelMax = LevelCur; + } + } + Abc_NtkForEachPi( pNtk, pObj, i ) + { + Abc_ObjForEachFanout( pObj, pNext, k ) + { + LevelCur = Abc_NtkRetimeTiming_rec( pNext, fForward ); + if ( LevelMax < LevelCur ) + LevelMax = LevelCur; + } + } + } + else + { + Vec_PtrForEachEntry( vLatches, pObj, i ) + { + LevelCur = Abc_NtkRetimeTiming_rec( Abc_ObjFanin0(pObj), fForward ); + if ( LevelMax < LevelCur ) + LevelMax = LevelCur; + } + Abc_NtkForEachPo( pNtk, pObj, i ) + { + LevelCur = Abc_NtkRetimeTiming_rec( Abc_ObjFanin0(pObj), fForward ); + if ( LevelMax < LevelCur ) + LevelMax = LevelCur; + } + } + // collect timing critical nodes, which should be retimed forward/backward + Vec_PtrClear( vCritical ); + Abc_NtkIncrementTravId(pNtk); + if ( fForward ) + { + Vec_PtrForEachEntry( vLatches, pObj, i ) + { + Abc_ObjForEachFanout( pObj, pNext, k ) + { + if ( Abc_NodeIsTravIdCurrent(pNext) ) + continue; + if ( LevelMax != (int)pNext->Level ) + continue; + // new critical node + Vec_PtrPush( vCritical, pNext ); + Abc_NodeSetTravIdCurrent( pNext ); + } + } + } + else + { + Vec_PtrForEachEntry( vLatches, pObj, i ) + { + Abc_ObjForEachFanin( pObj, pNext, k ) + { + if ( Abc_NodeIsTravIdCurrent(pNext) ) + continue; + if ( LevelMax != (int)pNext->Level ) + continue; + // new critical node + Vec_PtrPush( vCritical, pNext ); + Abc_NodeSetTravIdCurrent( pNext ); + } + } + } + Vec_PtrFree( vLatches ); + return LevelMax; +} + +/**Function************************************************************* + + Synopsis [Recursively performs timing analysis.] + + Description [Performs static timing analysis on the network. Uses + unit-delay model.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkRetimeTiming_rec( Abc_Obj_t * pObj, int fForward ) +{ + Abc_Obj_t * pNext; + int i, LevelCur, LevelMax = 0; + // skip visited nodes + if ( Abc_NodeIsTravIdCurrent(pObj) ) + return pObj->Level; + Abc_NodeSetTravIdCurrent(pObj); + // visit the next nodes + if ( fForward ) + { + Abc_ObjForEachFanout( pObj, pNext, i ) + { + LevelCur = Abc_NtkRetimeTiming_rec( pNext, fForward ); + if ( LevelMax < LevelCur ) + LevelMax = LevelCur; + } + } + else + { + Abc_ObjForEachFanin( pObj, pNext, i ) + { + LevelCur = Abc_NtkRetimeTiming_rec( pNext, fForward ); + if ( LevelMax < LevelCur ) + LevelMax = LevelCur; + } + } +// printf( "Node %3d -> Level %3d.\n", pObj->Id, LevelMax + 1 ); + pObj->Level = LevelMax + 1; + return pObj->Level; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/ret/retFlow.c b/src/opt/ret/retFlow.c new file mode 100644 index 00000000..47ee8516 --- /dev/null +++ b/src/opt/ret/retFlow.c @@ -0,0 +1,783 @@ +/**CFile**************************************************************** + + FileName [retFlow.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Network and node package.] + + Synopsis [Implementation of maximum flow (min-area retiming).] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - Oct 31, 2006.] + + Revision [$Id: retFlow.c,v 1.00 2006/10/31 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "retInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static inline int Abc_ObjSetPath( Abc_Obj_t * pObj, Abc_Obj_t * pNext ) { pObj->pCopy = pNext; return 1; } +static inline Abc_Obj_t * Abc_ObjGetPath( Abc_Obj_t * pObj ) { return pObj->pCopy; } +static inline Abc_Obj_t * Abc_ObjGetFanoutPath( Abc_Obj_t * pObj ) +{ + Abc_Obj_t * pFanout; + int i; + assert( Abc_ObjGetPath(pObj) ); + Abc_ObjForEachFanout( pObj, pFanout, i ) + if ( Abc_ObjGetPath(pFanout) == pObj ) + return pFanout; + return NULL; +} +static inline Abc_Obj_t * Abc_ObjGetFaninPath( Abc_Obj_t * pObj ) +{ + Abc_Obj_t * pFanin; + int i; + assert( Abc_ObjGetPath(pObj) ); + Abc_ObjForEachFanin( pObj, pFanin, i ) + if ( Abc_ObjGetPath(pFanin) == pObj ) + return pFanin; + return NULL; +} +static inline Abc_Obj_t * Abc_ObjGetPredecessorBwd( Abc_Obj_t * pObj ) +{ + Abc_Obj_t * pNext; + int i; + Abc_ObjForEachFanout( pObj, pNext, i ) + if ( Abc_ObjGetPath(pNext) == pObj ) + return pNext; + Abc_ObjForEachFanin( pObj, pNext, i ) + if ( Abc_ObjGetPath(pNext) == pObj ) + return pNext; + return NULL; +} +static inline Abc_Obj_t * Abc_ObjGetPredecessorFwd( Abc_Obj_t * pObj ) +{ + Abc_Obj_t * pNext; + int i; + Abc_ObjForEachFanin( pObj, pNext, i ) + if ( Abc_ObjGetPath(pNext) == pObj ) + return pNext; + Abc_ObjForEachFanout( pObj, pNext, i ) + if ( Abc_ObjGetPath(pNext) == pObj ) + return pNext; + return NULL; +} + +static int Abc_NtkMaxFlowBwdPath_rec( Abc_Obj_t * pObj ); +static int Abc_NtkMaxFlowFwdPath_rec( Abc_Obj_t * pObj ); +static int Abc_NtkMaxFlowBwdPath2_rec( Abc_Obj_t * pObj ); +static int Abc_NtkMaxFlowFwdPath2_rec( Abc_Obj_t * pObj ); +//static int Abc_NtkMaxFlowBwdPath3_rec( Abc_Obj_t * pObj ); +static int Abc_NtkMaxFlowFwdPath3_rec( Abc_Obj_t * pObj, Abc_Obj_t * pPrev, int fFanin ); +static Vec_Ptr_t * Abc_NtkMaxFlowMinCut( Abc_Ntk_t * pNtk, int fForward ); +static void Abc_NtkMaxFlowMinCutUpdate( Abc_Ntk_t * pNtk, Vec_Ptr_t * vMinCut, int fForward ); +static int Abc_NtkMaxFlowVerifyCut( Abc_Ntk_t * pNtk, Vec_Ptr_t * vMinCut, int fForward ); +static void Abc_NtkMaxFlowPrintCut( Abc_Ntk_t * pNtk, Vec_Ptr_t * vMinCut ); +static void Abc_NtkMaxFlowPrintFlow( Abc_Ntk_t * pNtk, int fForward ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Test-bench for the max-flow computation.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NtkMaxFlowTest( Abc_Ntk_t * pNtk ) +{ + Vec_Ptr_t * vMinCut; + Abc_Obj_t * pObj; + int i; + + // forward flow + Abc_NtkForEachPo( pNtk, pObj, i ) + pObj->fMarkA = 1; + Abc_NtkForEachLatch( pNtk, pObj, i ) + pObj->fMarkA = Abc_ObjFanin0(pObj)->fMarkA = 1; +// Abc_ObjFanin0(pObj)->fMarkA = 1; + vMinCut = Abc_NtkMaxFlow( pNtk, 1, 1 ); + Vec_PtrFree( vMinCut ); + Abc_NtkCleanMarkA( pNtk ); + + // backward flow + Abc_NtkForEachPi( pNtk, pObj, i ) + pObj->fMarkA = 1; + Abc_NtkForEachLatch( pNtk, pObj, i ) + pObj->fMarkA = Abc_ObjFanout0(pObj)->fMarkA = 1; +// Abc_ObjFanout0(pObj)->fMarkA = 1; + vMinCut = Abc_NtkMaxFlow( pNtk, 0, 1 ); + Vec_PtrFree( vMinCut ); + Abc_NtkCleanMarkA( pNtk ); + +} + +/**Function************************************************************* + + Synopsis [Implementation of max-flow/min-cut computation.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Abc_NtkMaxFlow( Abc_Ntk_t * pNtk, int fForward, int fVerbose ) +{ + Vec_Ptr_t * vMinCut; + Abc_Obj_t * pLatch; + int Flow, FlowCur, RetValue, i; + int clk = clock(); + int fUseDirectedFlow = 1; + + // find the max-flow + Abc_NtkCleanCopy( pNtk ); + Flow = 0; + Abc_NtkIncrementTravId(pNtk); + Abc_NtkForEachLatch( pNtk, pLatch, i ) + { + if ( fForward ) + { +// assert( !Abc_ObjFanout0(pLatch)->fMarkA ); + FlowCur = Abc_NtkMaxFlowFwdPath2_rec( Abc_ObjFanout0(pLatch) ); +// FlowCur = Abc_NtkMaxFlowFwdPath3_rec( Abc_ObjFanout0(pLatch), pLatch, 1 ); + Flow += FlowCur; + } + else + { + assert( !Abc_ObjFanin0(pLatch)->fMarkA ); + FlowCur = Abc_NtkMaxFlowBwdPath2_rec( Abc_ObjFanin0(pLatch) ); + Flow += FlowCur; + } + if ( FlowCur ) + Abc_NtkIncrementTravId(pNtk); + } + + if ( !fUseDirectedFlow ) + { + Abc_NtkIncrementTravId(pNtk); + Abc_NtkForEachLatch( pNtk, pLatch, i ) + { + if ( fForward ) + { + // assert( !Abc_ObjFanout0(pLatch)->fMarkA ); + FlowCur = Abc_NtkMaxFlowFwdPath_rec( Abc_ObjFanout0(pLatch) ); + Flow += FlowCur; + } + else + { + assert( !Abc_ObjFanin0(pLatch)->fMarkA ); + FlowCur = Abc_NtkMaxFlowBwdPath_rec( Abc_ObjFanin0(pLatch) ); + Flow += FlowCur; + } + if ( FlowCur ) + Abc_NtkIncrementTravId(pNtk); + } + } +// Abc_NtkMaxFlowPrintFlow( pNtk, fForward ); + + // mark the nodes reachable from the latches + Abc_NtkIncrementTravId(pNtk); + Abc_NtkForEachLatch( pNtk, pLatch, i ) + { + if ( fForward ) + { +// assert( !Abc_ObjFanout0(pLatch)->fMarkA ); + if ( fUseDirectedFlow ) + RetValue = Abc_NtkMaxFlowFwdPath2_rec( Abc_ObjFanout0(pLatch) ); +// RetValue = Abc_NtkMaxFlowFwdPath3_rec( Abc_ObjFanout0(pLatch), pLatch, 1 ); + else + RetValue = Abc_NtkMaxFlowFwdPath_rec( Abc_ObjFanout0(pLatch) ); + } + else + { + assert( !Abc_ObjFanin0(pLatch)->fMarkA ); + if ( fUseDirectedFlow ) + RetValue = Abc_NtkMaxFlowBwdPath2_rec( Abc_ObjFanin0(pLatch) ); + else + RetValue = Abc_NtkMaxFlowBwdPath_rec( Abc_ObjFanin0(pLatch) ); + } + assert( RetValue == 0 ); + } + + // find the min-cut with the smallest volume + vMinCut = Abc_NtkMaxFlowMinCut( pNtk, fForward ); + // verify the cut + if ( !Abc_NtkMaxFlowVerifyCut(pNtk, vMinCut, fForward) ) + printf( "Abc_NtkMaxFlow() error! The computed min-cut is not a cut!\n" ); + // make the cut retimable + Abc_NtkMaxFlowMinCutUpdate( pNtk, vMinCut, fForward ); + + // report the results + if ( fVerbose ) + { + printf( "L = %6d. %s max-flow = %6d. Min-cut = %6d. ", + Abc_NtkLatchNum(pNtk), fForward? "Forward " : "Backward", Flow, Vec_PtrSize(vMinCut) ); +PRT( "Time", clock() - clk ); + } + +// Abc_NtkMaxFlowPrintCut( pNtk, vMinCut ); + return vMinCut; +} + +/**Function************************************************************* + + Synopsis [Tries to find an augmenting path originating in this node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkMaxFlowBwdPath_rec( Abc_Obj_t * pObj ) +{ + Abc_Obj_t * pNext, * pPred; + int i; + // skip visited nodes + if ( Abc_NodeIsTravIdCurrent(pObj) ) + return 0; + Abc_NodeSetTravIdCurrent(pObj); + // get the predecessor + pPred = Abc_ObjGetPredecessorBwd( pObj ); + // process node without flow + if ( !Abc_ObjGetPath(pObj) ) + { + // start the path if we reached a terminal node + if ( pObj->fMarkA ) + return Abc_ObjSetPath( pObj, (void *)1 ); + // explore the fanins + Abc_ObjForEachFanin( pObj, pNext, i ) + if ( pNext != pPred && !Abc_ObjIsLatch(pNext) && Abc_NtkMaxFlowBwdPath_rec(pNext) ) + return Abc_ObjSetPath( pObj, pNext ); + Abc_ObjForEachFanout( pObj, pNext, i ) + if ( pNext != pPred && !Abc_ObjIsLatch(pNext) && Abc_NtkMaxFlowBwdPath_rec(pNext) ) + return Abc_ObjSetPath( pObj, pNext ); + return 0; + } + // pObj has flow - find the fanout with flow + if ( pPred == NULL ) + return 0; + // go through the successors of the predecessor + Abc_ObjForEachFanin( pPred, pNext, i ) + if ( !Abc_ObjIsLatch(pNext) && Abc_NtkMaxFlowBwdPath_rec( pNext ) ) + return Abc_ObjSetPath( pPred, pNext ); + Abc_ObjForEachFanout( pPred, pNext, i ) + if ( !Abc_ObjIsLatch(pNext) && Abc_NtkMaxFlowBwdPath_rec( pNext ) ) + return Abc_ObjSetPath( pPred, pNext ); + // try the fanout + if ( Abc_NtkMaxFlowBwdPath_rec( pPred ) ) + return Abc_ObjSetPath( pPred, NULL ); + return 0; +} + +/**Function************************************************************* + + Synopsis [Tries to find an augmenting path originating in this node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkMaxFlowFwdPath_rec( Abc_Obj_t * pObj ) +{ + Abc_Obj_t * pNext, * pPred; + int i; + // skip visited nodes + if ( Abc_NodeIsTravIdCurrent(pObj) ) + return 0; + Abc_NodeSetTravIdCurrent(pObj); + // get the predecessor + pPred = Abc_ObjGetPredecessorFwd( pObj ); + // process node without flow + if ( !Abc_ObjGetPath(pObj) ) + { + // start the path if we reached a terminal node + if ( pObj->fMarkA ) + return Abc_ObjSetPath( pObj, (void *)1 ); + // explore the fanins + Abc_ObjForEachFanout( pObj, pNext, i ) + if ( pNext != pPred && !Abc_ObjIsLatch(pNext) && Abc_NtkMaxFlowFwdPath_rec(pNext) ) + return Abc_ObjSetPath( pObj, pNext ); + Abc_ObjForEachFanin( pObj, pNext, i ) + if ( pNext != pPred && !Abc_ObjIsLatch(pNext) && Abc_NtkMaxFlowFwdPath_rec(pNext) ) + return Abc_ObjSetPath( pObj, pNext ); + return 0; + } + // pObj has flow - find the fanout with flow + if ( pPred == NULL ) + return 0; + // go through the successors of the predecessor + Abc_ObjForEachFanout( pPred, pNext, i ) + if ( !Abc_ObjIsLatch(pNext) && Abc_NtkMaxFlowFwdPath_rec( pNext ) ) + return Abc_ObjSetPath( pPred, pNext ); + Abc_ObjForEachFanin( pPred, pNext, i ) + if ( !Abc_ObjIsLatch(pNext) && Abc_NtkMaxFlowFwdPath_rec( pNext ) ) + return Abc_ObjSetPath( pPred, pNext ); + // try the fanout + if ( Abc_NtkMaxFlowFwdPath_rec( pPred ) ) + return Abc_ObjSetPath( pPred, NULL ); + return 0; +} + + +/**Function************************************************************* + + Synopsis [Tries to find an augmenting path originating in this edge.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkMaxFlowFwdPath3_rec( Abc_Obj_t * pObj, Abc_Obj_t * pPrev, int fFanin ) +{ + Abc_Obj_t * pFanin, * pFanout; + int i; + // skip visited nodes + if ( Abc_NodeIsTravIdCurrent(pObj) ) + return 0; + Abc_NodeSetTravIdCurrent(pObj); + // skip the fanin which already has flow + if ( fFanin && Abc_ObjGetPath(pPrev) ) + return 0; + // if the node has no flow, try to push through the fanouts + if ( !Abc_ObjGetPath(pObj) ) + { + // start the path if we reached a terminal node + if ( pObj->fMarkA ) + return Abc_ObjSetPath( pObj, (void *)1 ); + // try to push flow through the fanouts + Abc_ObjForEachFanout( pObj, pFanout, i ) + if ( Abc_NtkMaxFlowFwdPath3_rec(pFanout, pObj, 1) ) + return fFanin? Abc_ObjSetPath(pPrev, pObj) : 1; + } + // try to push through the fanins + Abc_ObjForEachFanin( pObj, pFanin, i ) + if ( !Abc_ObjIsLatch(pFanin) && Abc_NtkMaxFlowFwdPath3_rec(pFanin, pObj, 0) ) + return Abc_ObjSetPath( pFanin, NULL ); + return 0; +} + +/**Function************************************************************* + + Synopsis [Tries to find an augmenting path originating in this node.] + + Description [This procedure works for directed graphs only!] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkMaxFlowBwdPath2_rec( Abc_Obj_t * pObj ) +{ + Abc_Obj_t * pFanout, * pFanin; + int i; + // skip visited nodes + if ( Abc_NodeIsTravIdCurrent(pObj) ) + return 0; + Abc_NodeSetTravIdCurrent(pObj); + // process node without flow + if ( !Abc_ObjGetPath(pObj) ) + { + // start the path if we reached a terminal node + if ( pObj->fMarkA ) + return Abc_ObjSetPath( pObj, (void *)1 ); + // explore the fanins + Abc_ObjForEachFanin( pObj, pFanin, i ) + if ( Abc_NtkMaxFlowBwdPath2_rec(pFanin) ) + return Abc_ObjSetPath( pObj, pFanin ); + return 0; + } + // pObj has flow - find the fanout with flow + pFanout = Abc_ObjGetFanoutPath( pObj ); + if ( pFanout == NULL ) + return 0; + // go through the fanins of the fanout with flow + Abc_ObjForEachFanin( pFanout, pFanin, i ) + if ( Abc_NtkMaxFlowBwdPath2_rec( pFanin ) ) + return Abc_ObjSetPath( pFanout, pFanin ); + // try the fanout + if ( Abc_NtkMaxFlowBwdPath2_rec( pFanout ) ) + return Abc_ObjSetPath( pFanout, NULL ); + return 0; +} + +/**Function************************************************************* + + Synopsis [Tries to find an augmenting path originating in this node.] + + Description [This procedure works for directed graphs only!] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkMaxFlowFwdPath2_rec( Abc_Obj_t * pObj ) +{ + Abc_Obj_t * pFanout, * pFanin; + int i; + // skip visited nodes + if ( Abc_NodeIsTravIdCurrent(pObj) ) + return 0; + Abc_NodeSetTravIdCurrent(pObj); + // process node without flow + if ( !Abc_ObjGetPath(pObj) ) + { + // start the path if we reached a terminal node + if ( pObj->fMarkA ) + return Abc_ObjSetPath( pObj, (void *)1 ); + // explore the fanins + Abc_ObjForEachFanout( pObj, pFanout, i ) + if ( Abc_NtkMaxFlowFwdPath2_rec(pFanout) ) + return Abc_ObjSetPath( pObj, pFanout ); + return 0; + } + // pObj has flow - find the fanout with flow + pFanin = Abc_ObjGetFaninPath( pObj ); + if ( pFanin == NULL ) + return 0; + // go through the fanins of the fanout with flow + Abc_ObjForEachFanout( pFanin, pFanout, i ) + if ( Abc_NtkMaxFlowFwdPath2_rec( pFanout ) ) + return Abc_ObjSetPath( pFanin, pFanout ); + // try the fanout + if ( Abc_NtkMaxFlowFwdPath2_rec( pFanin ) ) + return Abc_ObjSetPath( pFanin, NULL ); + return 0; +} + +/**Function************************************************************* + + Synopsis [Find minimum-volume minumum cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Abc_NtkMaxFlowMinCut( Abc_Ntk_t * pNtk, int fForward ) +{ + Vec_Ptr_t * vMinCut; + Abc_Obj_t * pObj; + int i; + // collect the cut nodes + vMinCut = Vec_PtrAlloc( Abc_NtkLatchNum(pNtk) ); + Abc_NtkForEachObj( pNtk, pObj, i ) + { + // node without flow is not a cut node + if ( !Abc_ObjGetPath(pObj) ) + continue; + // unvisited node is below the cut + if ( !Abc_NodeIsTravIdCurrent(pObj) ) + continue; + // add terminal with flow or node whose path is not visited + if ( pObj->fMarkA || !Abc_NodeIsTravIdCurrent( Abc_ObjGetPath(pObj) ) ) + Vec_PtrPush( vMinCut, pObj ); + } + return vMinCut; +} + +/**Function************************************************************* + + Synopsis [Marks the TFI cone with MarkA.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NtkMaxFlowMarkCut_rec( Abc_Obj_t * pObj ) +{ + Abc_Obj_t * pNext; + int i; + if ( pObj->fMarkA ) + return; + pObj->fMarkA = 1; + Abc_ObjForEachFanin( pObj, pNext, i ) + Abc_NtkMaxFlowMarkCut_rec( pNext ); +} + +/**Function************************************************************* + + Synopsis [Visits the TFI up to marked nodes and collects marked nodes.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NtkMaxFlowCollectCut_rec( Abc_Obj_t * pObj, Vec_Ptr_t * vNodes ) +{ + Abc_Obj_t * pNext; + int i; + if ( Abc_NodeIsTravIdCurrent(pObj) ) + return; + Abc_NodeSetTravIdCurrent(pObj); + if ( pObj->fMarkA ) + { + Vec_PtrPush( vNodes, pObj ); + return; + } + Abc_ObjForEachFanin( pObj, pNext, i ) + Abc_NtkMaxFlowCollectCut_rec( pNext, vNodes ); +} + +/**Function************************************************************* + + Synopsis [Updates the minimum cut to be retimable.] + + Description [This procedure also labels the nodes reachable from + the latches to the cut with fMarkA.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NtkMaxFlowMinCutUpdate( Abc_Ntk_t * pNtk, Vec_Ptr_t * vMinCut, int fForward ) +{ + Abc_Obj_t * pObj, * pNext; + int i, k; + // clean marks + Abc_NtkForEachObj( pNtk, pObj, i ) + pObj->fMarkA = 0; + // set latch outputs + Abc_NtkForEachLatch( pNtk, pObj, i ) + Abc_ObjFanout0(pObj)->fMarkA = 1; + // traverse from cut nodes + Vec_PtrForEachEntry( vMinCut, pObj, i ) + Abc_NtkMaxFlowMarkCut_rec( pObj ); + if ( fForward ) + { + // change mincut to be nodes with unmarked fanouts + Vec_PtrClear( vMinCut ); + Abc_NtkForEachObj( pNtk, pObj, i ) + { + if ( !pObj->fMarkA ) + continue; + Abc_ObjForEachFanout( pObj, pNext, k ) + { + if ( pNext->fMarkA ) + continue; + Vec_PtrPush( vMinCut, pObj ); + break; + } + } + } + else + { + // change mincut to be marked fanins of the unmarked nodes + Vec_PtrClear( vMinCut ); + Abc_NtkIncrementTravId(pNtk); + Abc_NtkForEachLatch( pNtk, pObj, i ) + Abc_NtkMaxFlowCollectCut_rec( Abc_ObjFanin0(pObj), vMinCut ); + // transfer the attribute + Abc_NtkForEachObj( pNtk, pObj, i ) + pObj->fMarkA = Abc_NodeIsTravIdCurrent(pObj); + // unmark the cut nodes + Vec_PtrForEachEntry( vMinCut, pObj, i ) + pObj->fMarkA = 0; + } +} + +/**Function************************************************************* + + Synopsis [Verifies the min-cut is indeed a cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkMaxFlowVerifyCut_rec( Abc_Obj_t * pObj, int fForward ) +{ + Abc_Obj_t * pNext; + int i; + // skip visited nodes + if ( Abc_NodeIsTravIdCurrent(pObj) ) + return 1; + Abc_NodeSetTravIdCurrent(pObj); + // visit the node + if ( fForward ) + { + if ( Abc_ObjIsCo(pObj) ) + return 0; + // explore the fanouts + Abc_ObjForEachFanout( pObj, pNext, i ) + if ( !Abc_NtkMaxFlowVerifyCut_rec(pNext, fForward) ) + return 0; + } + else + { + if ( Abc_ObjIsCi(pObj) ) + return 0; + // explore the fanins + Abc_ObjForEachFanin( pObj, pNext, i ) + if ( !Abc_NtkMaxFlowVerifyCut_rec(pNext, fForward) ) + return 0; + } + return 1; +} + +/**Function************************************************************* + + Synopsis [Verifies the min-cut is indeed a cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkMaxFlowVerifyCut( Abc_Ntk_t * pNtk, Vec_Ptr_t * vMinCut, int fForward ) +{ + Abc_Obj_t * pObj; + int i; + // mark the cut with the current traversal ID + Abc_NtkIncrementTravId(pNtk); + Vec_PtrForEachEntry( vMinCut, pObj, i ) + Abc_NodeSetTravIdCurrent( pObj ); + // search from the latches for a path to the COs/CIs + Abc_NtkForEachLatch( pNtk, pObj, i ) + { + if ( fForward ) + { + if ( !Abc_NtkMaxFlowVerifyCut_rec( Abc_ObjFanout0(pObj), fForward ) ) + return 0; + } + else + { + if ( !Abc_NtkMaxFlowVerifyCut_rec( Abc_ObjFanin0(pObj), fForward ) ) + return 0; + } + } +/* + { + // count the volume of the cut + int Counter = 0; + Abc_NtkForEachObj( pNtk, pObj, i ) + Counter += Abc_NodeIsTravIdCurrent( pObj ); + printf( "Volume = %d.\n", Counter ); + } +*/ + return 1; +} + +/**Function************************************************************* + + Synopsis [Prints the flows.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NtkMaxFlowPrintFlow( Abc_Ntk_t * pNtk, int fForward ) +{ + Abc_Obj_t * pLatch, * pNext, * pPrev; + int i; + if ( fForward ) + { + Vec_PtrForEachEntry( pNtk->vBoxes, pLatch, i ) + { + assert( !Abc_ObjFanout0(pLatch)->fMarkA ); + if ( Abc_ObjGetPath(Abc_ObjFanout0(pLatch)) == NULL ) // no flow through this latch + continue; + printf( "Path = " ); + for ( pNext = Abc_ObjFanout0(pLatch); pNext != (void *)1; pNext = Abc_ObjGetPath(pNext) ) + { + printf( "%s(%d) ", Abc_ObjName(pNext), pNext->Id ); + pPrev = pNext; + } + if ( !Abc_ObjIsPo(pPrev) ) + printf( "%s(%d) ", Abc_ObjName(Abc_ObjFanout0(pPrev)), Abc_ObjFanout0(pPrev)->Id ); + printf( "\n" ); + } + } + else + { + Vec_PtrForEachEntry( pNtk->vBoxes, pLatch, i ) + { + assert( !Abc_ObjFanin0(pLatch)->fMarkA ); + if ( Abc_ObjGetPath(Abc_ObjFanin0(pLatch)) == NULL ) // no flow through this latch + continue; + printf( "Path = " ); + for ( pNext = Abc_ObjFanin0(pLatch); pNext != (void *)1; pNext = Abc_ObjGetPath(pNext) ) + { + printf( "%s(%d) ", Abc_ObjName(pNext), pNext->Id ); + pPrev = pNext; + } + if ( !Abc_ObjIsPi(pPrev) ) + printf( "%s(%d) ", Abc_ObjName(Abc_ObjFanin0(pPrev)), Abc_ObjFanin0(pPrev)->Id ); + printf( "\n" ); + } + } +} + +/**Function************************************************************* + + Synopsis [Prints the min-cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NtkMaxFlowPrintCut( Abc_Ntk_t * pNtk, Vec_Ptr_t * vMinCut ) +{ + Abc_Obj_t * pObj; + int i; + printf( "Min-cut: " ); + Vec_PtrForEachEntry( vMinCut, pObj, i ) + printf( "%s(%d) ", Abc_ObjName(pObj), pObj->Id ); + printf( "\n" ); + printf( "Marked nodes: " ); + Abc_NtkForEachObj( pNtk, pObj, i ) + if ( pObj->fMarkA ) + printf( "%s(%d) ", Abc_ObjName(pObj), pObj->Id ); + printf( "\n" ); +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/ret/retIncrem.c b/src/opt/ret/retIncrem.c new file mode 100644 index 00000000..ba8104be --- /dev/null +++ b/src/opt/ret/retIncrem.c @@ -0,0 +1,464 @@ +/**CFile**************************************************************** + + FileName [retIncrem.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Retiming package.] + + Synopsis [Incremental retiming in one direction.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - Oct 31, 2006.] + + Revision [$Id: retIncrem.c,v 1.00 2006/10/31 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "retInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static int Abc_NtkRetimeOneWay( Abc_Ntk_t * pNtk, int fForward, int fVerbose ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Performs retiming in one direction.] + + Description [Currently does not retime over black boxes.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkRetimeIncremental( Abc_Ntk_t * pNtk, int fForward, int fMinDelay, int fOneStep, int fVerbose ) +{ + Abc_Ntk_t * pNtkCopy = NULL; + Vec_Ptr_t * vBoxes; + st_table * tLatches; + int nLatches = Abc_NtkLatchNum(pNtk); + int nIdMaxStart = Abc_NtkObjNumMax(pNtk); + int RetValue, nIterLimit; + if ( Abc_NtkNodeNum(pNtk) == 0 ) + return 0; + // reorder CI/CO/latch inputs + Abc_NtkOrderCisCos( pNtk ); + if ( fMinDelay ) + { + nIterLimit = fOneStep? 1 : 2 * Abc_NtkLevel(pNtk); + pNtkCopy = Abc_NtkDup( pNtk ); + tLatches = Abc_NtkRetimePrepareLatches( pNtkCopy ); + st_free_table( tLatches ); + } + // collect latches and remove CIs/COs + tLatches = Abc_NtkRetimePrepareLatches( pNtk ); + // share the latches + Abc_NtkRetimeShareLatches( pNtk, 0 ); + // save boxes + vBoxes = pNtk->vBoxes; pNtk->vBoxes = NULL; + // perform the retiming + if ( fMinDelay ) + Abc_NtkRetimeMinDelay( pNtk, pNtkCopy, nIterLimit, fForward, fVerbose ); + else + Abc_NtkRetimeOneWay( pNtk, fForward, fVerbose ); + if ( fMinDelay ) + Abc_NtkDelete( pNtkCopy ); + // share the latches + Abc_NtkRetimeShareLatches( pNtk, 0 ); + // restore boxes + pNtk->vBoxes = vBoxes; + // finalize the latches + RetValue = Abc_NtkRetimeFinalizeLatches( pNtk, tLatches, nIdMaxStart ); + st_free_table( tLatches ); + if ( RetValue == 0 ) + return 0; + // fix the COs +// Abc_NtkLogicMakeSimpleCos( pNtk, 0 ); + // check for correctness + if ( !Abc_NtkCheck( pNtk ) ) + fprintf( stdout, "Abc_NtkRetimeForward(): Network check has failed.\n" ); + // return the number of latches saved + return nLatches - Abc_NtkLatchNum(pNtk); +} + +/**Function************************************************************* + + Synopsis [Prepares the network for retiming.] + + Description [Hash latches into their number in the original network.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +st_table * Abc_NtkRetimePrepareLatches( Abc_Ntk_t * pNtk ) +{ + st_table * tLatches; + Abc_Obj_t * pLatch, * pLatchIn, * pLatchOut, * pFanin; + int i, nOffSet = Abc_NtkBoxNum(pNtk) - Abc_NtkLatchNum(pNtk); + // collect latches and remove CIs/COs + tLatches = st_init_table( st_ptrcmp, st_ptrhash ); + Abc_NtkForEachLatch( pNtk, pLatch, i ) + { + // map latch into its true number + st_insert( tLatches, (void *)pLatch, (void *)(i-nOffSet) ); + // disconnect LI + pLatchIn = Abc_ObjFanin0(pLatch); + pFanin = Abc_ObjFanin0(pLatchIn); + Abc_ObjTransferFanout( pLatchIn, pFanin ); + Abc_ObjDeleteFanin( pLatchIn, pFanin ); + // disconnect LO + pLatchOut = Abc_ObjFanout0(pLatch); + pFanin = Abc_ObjFanin0(pLatchOut); + if ( Abc_ObjFanoutNum(pLatchOut) > 0 ) + Abc_ObjTransferFanout( pLatchOut, pFanin ); + Abc_ObjDeleteFanin( pLatchOut, pFanin ); + } + return tLatches; +} + +/**Function************************************************************* + + Synopsis [Finalizes the latches after retiming.] + + Description [Reuses the LIs/LOs for old latches.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkRetimeFinalizeLatches( Abc_Ntk_t * pNtk, st_table * tLatches, int nIdMaxStart ) +{ + Vec_Ptr_t * vCisOld, * vCosOld, * vBoxesOld, * vCisNew, * vCosNew, * vBoxesNew; + Abc_Obj_t * pObj, * pLatch, * pLatchIn, * pLatchOut; + int i, Index; + // create new arrays + vCisOld = pNtk->vCis; pNtk->vCis = NULL; vCisNew = Vec_PtrAlloc( 100 ); + vCosOld = pNtk->vCos; pNtk->vCos = NULL; vCosNew = Vec_PtrAlloc( 100 ); + vBoxesOld = pNtk->vBoxes; pNtk->vBoxes = NULL; vBoxesNew = Vec_PtrAlloc( 100 ); + // copy boxes and their CIs/COs + Vec_PtrForEachEntryStop( vCisOld, pObj, i, Vec_PtrSize(vCisOld) - st_count(tLatches) ) + Vec_PtrPush( vCisNew, pObj ); + Vec_PtrForEachEntryStop( vCosOld, pObj, i, Vec_PtrSize(vCosOld) - st_count(tLatches) ) + Vec_PtrPush( vCosNew, pObj ); + Vec_PtrForEachEntryStop( vBoxesOld, pObj, i, Vec_PtrSize(vBoxesOld) - st_count(tLatches) ) + Vec_PtrPush( vBoxesNew, pObj ); + // go through the latches + Abc_NtkForEachObj( pNtk, pLatch, i ) + { + if ( !Abc_ObjIsLatch(pLatch) ) + continue; + if ( Abc_ObjId(pLatch) >= (unsigned)nIdMaxStart ) + { + // this is a new latch + pLatchIn = Abc_NtkCreateBi(pNtk); + pLatchOut = Abc_NtkCreateBo(pNtk); + Abc_ObjAssignName( pLatchOut, Abc_ObjName(pLatch), "_out" ); + Abc_ObjAssignName( pLatchIn, Abc_ObjName(pLatch), "_in" ); + } + else + { + // this is an old latch + // get its number in the original order + if ( !st_lookup( tLatches, (char *)pLatch, (char **)&Index ) ) + { + printf( "Abc_NtkRetimeFinalizeLatches(): Internal error.\n" ); + return 0; + } + assert( pLatch == Vec_PtrEntry(vBoxesOld, Vec_PtrSize(vBoxesOld) - st_count(tLatches) + Index) ); + // reconnect with the old LIs/LOs + pLatchIn = Vec_PtrEntry( vCosOld, Vec_PtrSize(vCosOld) - st_count(tLatches) + Index ); + pLatchOut = Vec_PtrEntry( vCisOld, Vec_PtrSize(vCisOld) - st_count(tLatches) + Index ); + } + // connect + Abc_ObjAddFanin( pLatchIn, Abc_ObjFanin0(pLatch) ); + Abc_ObjPatchFanin( pLatch, Abc_ObjFanin0(pLatch), pLatchIn ); + if ( Abc_ObjFanoutNum(pLatch) > 0 ) + Abc_ObjTransferFanout( pLatch, pLatchOut ); + Abc_ObjAddFanin( pLatchOut, pLatch ); + // add to the arrays + Vec_PtrPush( vCisNew, pLatchOut ); + Vec_PtrPush( vCosNew, pLatchIn ); + Vec_PtrPush( vBoxesNew, pLatch ); + } + // free useless Cis/Cos + Vec_PtrForEachEntry( vCisOld, pObj, i ) + if ( !Abc_ObjIsPi(pObj) && Abc_ObjFaninNum(pObj) == 0 && Abc_ObjFanoutNum(pObj) == 0 ) + Abc_NtkDeleteObj(pObj); + Vec_PtrForEachEntry( vCosOld, pObj, i ) + if ( !Abc_ObjIsPo(pObj) && Abc_ObjFaninNum(pObj) == 0 && Abc_ObjFanoutNum(pObj) == 0 ) + Abc_NtkDeleteObj(pObj); + // set the new arrays + pNtk->vCis = vCisNew; Vec_PtrFree( vCisOld ); + pNtk->vCos = vCosNew; Vec_PtrFree( vCosOld ); + pNtk->vBoxes = vBoxesNew; Vec_PtrFree( vBoxesOld ); + return 1; +} + +/**Function************************************************************* + + Synopsis [Performs retiming one way, forward or backward.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkRetimeOneWay( Abc_Ntk_t * pNtk, int fForward, int fVerbose ) +{ + Abc_Ntk_t * pNtkNew; + Vec_Int_t * vValues; + Abc_Obj_t * pObj; + int i, fChanges, nTotalMoves = 0, nTotalMovesLimit = 10000; + if ( fForward ) + Abc_NtkRetimeTranferToCopy( pNtk ); + else + { + // save initial values of the latches + vValues = Abc_NtkRetimeCollectLatchValues( pNtk ); + // start the network for initial value computation + pNtkNew = Abc_NtkRetimeBackwardInitialStart( pNtk ); + } + // try to move latches forward whenever possible + do { + fChanges = 0; + Abc_NtkForEachObj( pNtk, pObj, i ) + { + if ( !Abc_ObjIsNode(pObj) ) + continue; + if ( Abc_NtkRetimeNodeIsEnabled( pObj, fForward ) ) + { + Abc_NtkRetimeNode( pObj, fForward, 1 ); + fChanges = 1; + nTotalMoves++; + if ( nTotalMoves >= nTotalMovesLimit ) + { + printf( "Stopped after %d latch moves.\n", nTotalMoves ); + break; + } + } + } + } while ( fChanges && nTotalMoves < nTotalMovesLimit ); + // transfer the initial state back to the latches + if ( fForward ) + Abc_NtkRetimeTranferFromCopy( pNtk ); + else + { + Abc_NtkRetimeBackwardInitialFinish( pNtk, pNtkNew, vValues, fVerbose ); + Abc_NtkDelete( pNtkNew ); + Vec_IntFree( vValues ); + } + return 0; +} + + +/**Function************************************************************* + + Synopsis [Returns 1 if retiming forward/backward is possible.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkRetimeNodeIsEnabled( Abc_Obj_t * pObj, int fForward ) +{ + Abc_Obj_t * pNext; + int i; + assert( Abc_ObjIsNode(pObj) ); + if ( fForward ) + { + Abc_ObjForEachFanin( pObj, pNext, i ) + if ( !Abc_ObjIsLatch(pNext) ) + return 0; + } + else + { + Abc_ObjForEachFanout( pObj, pNext, i ) + if ( !Abc_ObjIsLatch(pNext) ) + return 0; + } + return 1; +} + +/**Function************************************************************* + + Synopsis [Retimes the node backward or forward.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NtkRetimeNode( Abc_Obj_t * pObj, int fForward, int fInitial ) +{ + Abc_Ntk_t * pNtkNew = NULL; + Vec_Ptr_t * vNodes; + Abc_Obj_t * pNext, * pLatch; + int i; + vNodes = Vec_PtrAlloc( 10 ); + if ( fForward ) + { + // compute the initial value + if ( fInitial ) + pObj->pCopy = (void *)Abc_ObjSopSimulate( pObj ); + // collect fanins + Abc_NodeCollectFanins( pObj, vNodes ); + // make the node point to the fanins fanins + Vec_PtrForEachEntry( vNodes, pNext, i ) + { + assert( Abc_ObjIsLatch(pNext) ); + Abc_ObjPatchFanin( pObj, pNext, Abc_ObjFanin0(pNext) ); + if ( Abc_ObjFanoutNum(pNext) == 0 ) + Abc_NtkDeleteObj(pNext); + } + // add a new latch on top + pNext = Abc_NtkCreateLatch(pObj->pNtk); + if ( Abc_ObjFanoutNum(pObj) > 0 ) + Abc_ObjTransferFanout( pObj, pNext ); + Abc_ObjAddFanin( pNext, pObj ); + // set the initial value + if ( fInitial ) + pNext->pCopy = pObj->pCopy; + } + else + { + // compute the initial value + if ( fInitial ) + { + pNtkNew = Abc_ObjFanout0(pObj)->pCopy->pNtk; + Abc_NtkDupObj( pNtkNew, pObj, 0 ); + Abc_ObjForEachFanout( pObj, pNext, i ) + { + assert( Abc_ObjFaninNum(pNext->pCopy) == 0 ); + Abc_ObjAddFanin( pNext->pCopy, pObj->pCopy ); + } + } + // collect fanouts + Abc_NodeCollectFanouts( pObj, vNodes ); + // make the fanouts fanouts point to the node + Vec_PtrForEachEntry( vNodes, pNext, i ) + { + assert( Abc_ObjIsLatch(pNext) ); + Abc_ObjTransferFanout( pNext, pObj ); + Abc_NtkDeleteObj( pNext ); + } + // add new latches to the fanins + Abc_ObjForEachFanin( pObj, pNext, i ) + { + pLatch = Abc_NtkCreateLatch(pObj->pNtk); + Abc_ObjPatchFanin( pObj, pNext, pLatch ); + Abc_ObjAddFanin( pLatch, pNext ); + // create buffer isomorphic to this latch + if ( fInitial ) + { + pLatch->pCopy = Abc_NtkCreateNodeBuf( pNtkNew, NULL ); + Abc_ObjAddFanin( pObj->pCopy, pLatch->pCopy ); + } + } + } + Vec_PtrFree( vNodes ); +} + +/**Function************************************************************* + + Synopsis [Returns the number of compatible fanout latches.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkRetimeCheckCompatibleLatchFanouts( Abc_Obj_t * pObj ) +{ + Abc_Obj_t * pFanout; + int i, nLatches = 0, Init = -1; + Abc_ObjForEachFanout( pObj, pFanout, i ) + { + if ( !Abc_ObjIsLatch(pFanout) ) + continue; + if ( Init == -1 ) + { + Init = (int)pObj->pData; + nLatches++; + } + else if ( Init == (int)pObj->pData ) + nLatches++; + } + return nLatches; +} + +/**Function************************************************************* + + Synopsis [Retimes the node backward or forward.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NtkRetimeShareLatches( Abc_Ntk_t * pNtk, int fInitial ) +{ + Vec_Ptr_t * vNodes; + Abc_Obj_t * pFanin, * pLatchTop, * pLatchCur; + int i, k; + vNodes = Vec_PtrAlloc( 10 ); + // consider latch fanins + Abc_NtkForEachObj( pNtk, pFanin, i ) + { + if ( Abc_NtkRetimeCheckCompatibleLatchFanouts(pFanin) <= 1 ) + continue; + // get the first latch + pLatchTop = NULL; + Abc_ObjForEachFanout( pFanin, pLatchTop, k ) + if ( Abc_ObjIsLatch(pLatchTop) ) + break; + assert( pLatchTop && Abc_ObjIsLatch(pLatchTop) ); + // redirect compatible fanout latches to the first latch + Abc_NodeCollectFanouts( pFanin, vNodes ); + Vec_PtrForEachEntry( vNodes, pLatchCur, k ) + { + if ( !Abc_ObjIsLatch(pLatchCur) ) + continue; + if ( pLatchCur == pLatchTop ) + continue; + if ( pLatchCur->pData != pLatchTop->pData ) + continue; + // connect the initial state + if ( fInitial ) + Abc_ObjAddFanin( pLatchCur->pCopy, pLatchTop->pCopy ); + // redirect the fanouts + Abc_ObjTransferFanout( pLatchCur, pLatchTop ); + Abc_NtkDeleteObj(pLatchCur); + } + } + Vec_PtrFree( vNodes ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/ret/retInit.c b/src/opt/ret/retInit.c new file mode 100644 index 00000000..dcb71c60 --- /dev/null +++ b/src/opt/ret/retInit.c @@ -0,0 +1,349 @@ +/**CFile**************************************************************** + + FileName [retInit.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Retiming package.] + + Synopsis [Initial state computation for backward retiming.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - Oct 31, 2006.] + + Revision [$Id: retInit.c,v 1.00 2006/10/31 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "retInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static int Abc_NtkRetimeVerifyModel( Abc_Ntk_t * pNtkCone, Vec_Int_t * vValues, int * pModel ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Computes initial values of the new latches.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Int_t * Abc_NtkRetimeInitialValues( Abc_Ntk_t * pNtkCone, Vec_Int_t * vValues, int fVerbose ) +{ + Vec_Int_t * vSolution; + Abc_Ntk_t * pNtkMiter, * pNtkLogic; + int RetValue, clk; + if ( pNtkCone == NULL ) + return Vec_IntDup( vValues ); + // convert the target network to AIG + pNtkLogic = Abc_NtkDup( pNtkCone ); + Abc_NtkToAig( pNtkLogic ); + // get the miter + pNtkMiter = Abc_NtkCreateTarget( pNtkLogic, pNtkLogic->vCos, vValues ); + if ( fVerbose ) + printf( "The miter for initial state computation has %d AIG nodes. ", Abc_NtkNodeNum(pNtkMiter) ); + // solve the miter + clk = clock(); + RetValue = Abc_NtkMiterSat( pNtkMiter, (sint64)500000, (sint64)50000000, 0, NULL, NULL ); + if ( fVerbose ) + { PRT( "SAT solving time", clock() - clk ); } + // analyze the result + if ( RetValue == 1 ) + printf( "Abc_NtkRetimeInitialValues(): The problem is unsatisfiable. DC latch values are used.\n" ); + else if ( RetValue == -1 ) + printf( "Abc_NtkRetimeInitialValues(): The SAT problem timed out. DC latch values are used.\n" ); + else if ( !Abc_NtkRetimeVerifyModel( pNtkCone, vValues, pNtkMiter->pModel ) ) + printf( "Abc_NtkRetimeInitialValues(): The computed counter-example is incorrect.\n" ); + // set the values of the latches + vSolution = RetValue? NULL : Vec_IntAllocArray( pNtkMiter->pModel, Abc_NtkPiNum(pNtkLogic) ); + pNtkMiter->pModel = NULL; + Abc_NtkDelete( pNtkMiter ); + Abc_NtkDelete( pNtkLogic ); + return vSolution; +} + +/**Function************************************************************* + + Synopsis [Computes the results of simulating one node.] + + Description [Assumes that fanins have pCopy set to the input values.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_ObjSopSimulate( Abc_Obj_t * pObj ) +{ + char * pCube, * pSop = pObj->pData; + int nVars, Value, v, ResOr, ResAnd, ResVar; + assert( pSop && !Abc_SopIsExorType(pSop) ); + // simulate the SOP of the node + ResOr = 0; + nVars = Abc_SopGetVarNum(pSop); + Abc_SopForEachCube( pSop, nVars, pCube ) + { + ResAnd = 1; + Abc_CubeForEachVar( pCube, Value, v ) + { + if ( Value == '0' ) + ResVar = 1 ^ ((int)Abc_ObjFanin(pObj, v)->pCopy); + else if ( Value == '1' ) + ResVar = (int)Abc_ObjFanin(pObj, v)->pCopy; + else + continue; + ResAnd &= ResVar; + } + ResOr |= ResAnd; + } + // complement the result if necessary + if ( !Abc_SopGetPhase(pSop) ) + ResOr ^= 1; + return ResOr; +} + +/**Function************************************************************* + + Synopsis [Verifies the counter-example.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkRetimeVerifyModel( Abc_Ntk_t * pNtkCone, Vec_Int_t * vValues, int * pModel ) +{ + Vec_Ptr_t * vNodes; + Abc_Obj_t * pObj; + int i, Counter = 0; + assert( Abc_NtkIsSopLogic(pNtkCone) ); + // set the PIs + Abc_NtkForEachPi( pNtkCone, pObj, i ) + pObj->pCopy = (void *)pModel[i]; + // simulate the internal nodes + vNodes = Abc_NtkDfs( pNtkCone, 0 ); + Vec_PtrForEachEntry( vNodes, pObj, i ) + pObj->pCopy = (void *)Abc_ObjSopSimulate( pObj ); + Vec_PtrFree( vNodes ); + // compare the outputs + Abc_NtkForEachPo( pNtkCone, pObj, i ) + pObj->pCopy = Abc_ObjFanin0(pObj)->pCopy; + Abc_NtkForEachPo( pNtkCone, pObj, i ) + Counter += (Vec_IntEntry(vValues, i) != (int)pObj->pCopy); + if ( Counter > 0 ) + printf( "%d outputs (out of %d) have a value mismatch.\n", Counter, Abc_NtkPoNum(pNtkCone) ); + return 1; +} + +/**Function************************************************************* + + Synopsis [Transfer latch initial values to pCopy.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NtkRetimeTranferToCopy( Abc_Ntk_t * pNtk ) +{ + Abc_Obj_t * pObj; + int i; + Abc_NtkForEachObj( pNtk, pObj, i ) + if ( Abc_ObjIsLatch(pObj) ) + pObj->pCopy = (void *)Abc_LatchIsInit1(pObj); +} + +/**Function************************************************************* + + Synopsis [Transfer latch initial values from pCopy.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NtkRetimeTranferFromCopy( Abc_Ntk_t * pNtk ) +{ + Abc_Obj_t * pObj; + int i; + Abc_NtkForEachObj( pNtk, pObj, i ) + if ( Abc_ObjIsLatch(pObj) ) + pObj->pData = (void *)(pObj->pCopy? ABC_INIT_ONE : ABC_INIT_ZERO); +} + +/**Function************************************************************* + + Synopsis [Transfer latch initial values to pCopy.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Int_t * Abc_NtkRetimeCollectLatchValues( Abc_Ntk_t * pNtk ) +{ + Vec_Int_t * vValues; + Abc_Obj_t * pObj; + int i; + vValues = Vec_IntAlloc( Abc_NtkLatchNum(pNtk) ); + Abc_NtkForEachObj( pNtk, pObj, i ) + if ( Abc_ObjIsLatch(pObj) ) + Vec_IntPush( vValues, Abc_LatchIsInit1(pObj) ); + return vValues; +} + +/**Function************************************************************* + + Synopsis [Transfer latch initial values from pCopy.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NtkRetimeInsertLatchValues( Abc_Ntk_t * pNtk, Vec_Int_t * vValues ) +{ + Abc_Obj_t * pObj; + int i, Counter = 0; + Abc_NtkForEachObj( pNtk, pObj, i ) + if ( Abc_ObjIsLatch(pObj) ) + pObj->pCopy = (void *)Counter++; + Abc_NtkForEachObj( pNtk, pObj, i ) + if ( Abc_ObjIsLatch(pObj) ) + pObj->pData = (void *)(vValues? (Vec_IntEntry(vValues,(int)pObj->pCopy)? ABC_INIT_ONE : ABC_INIT_ZERO) : ABC_INIT_DC); +} + +/**Function************************************************************* + + Synopsis [Transfer latch initial values to pCopy.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Abc_Ntk_t * Abc_NtkRetimeBackwardInitialStart( Abc_Ntk_t * pNtk ) +{ + Abc_Ntk_t * pNtkNew; + Abc_Obj_t * pObj; + int i; + // create the network used for the initial state computation + pNtkNew = Abc_NtkAlloc( ABC_NTK_LOGIC, ABC_FUNC_SOP, 1 ); + // create POs corresponding to the initial values + Abc_NtkForEachObj( pNtk, pObj, i ) + if ( Abc_ObjIsLatch(pObj) ) + pObj->pCopy = Abc_NtkCreatePo(pNtkNew); + return pNtkNew; +} + +/**Function************************************************************* + + Synopsis [Transfer latch initial values to pCopy.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NtkRetimeBackwardInitialFinish( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkNew, Vec_Int_t * vValuesOld, int fVerbose ) +{ + Vec_Int_t * vValuesNew; + Abc_Obj_t * pObj; + int i; + // create PIs corresponding to the initial values + Abc_NtkForEachObj( pNtk, pObj, i ) + if ( Abc_ObjIsLatch(pObj) ) + Abc_ObjAddFanin( pObj->pCopy, Abc_NtkCreatePi(pNtkNew) ); + // assign dummy node names + Abc_NtkAddDummyPiNames( pNtkNew ); + Abc_NtkAddDummyPoNames( pNtkNew ); + // check the network + if ( !Abc_NtkCheck( pNtkNew ) ) + fprintf( stdout, "Abc_NtkRetimeBackwardInitialFinish(): Network check has failed.\n" ); + // derive new initial values + vValuesNew = Abc_NtkRetimeInitialValues( pNtkNew, vValuesOld, fVerbose ); + // insert new initial values + Abc_NtkRetimeInsertLatchValues( pNtk, vValuesNew ); + if ( vValuesNew ) Vec_IntFree( vValuesNew ); +} + + +/**Function************************************************************* + + Synopsis [Cycles the circuit to create a new initial state.] + + Description [Simulates the circuit with random input for the given + number of timeframes to get a better initial state.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NtkCycleInitStateSop( Abc_Ntk_t * pNtk, int nFrames, int fVerbose ) +{ + Vec_Ptr_t * vNodes; + Abc_Obj_t * pObj; + int i, f; + assert( Abc_NtkIsSopLogic(pNtk) ); + srand( 0x12341234 ); + // initialize the values + Abc_NtkForEachPi( pNtk, pObj, i ) + pObj->pCopy = (void *)(rand() & 1); + Abc_NtkForEachLatch( pNtk, pObj, i ) + pObj->pCopy = (void *)Abc_LatchIsInit1(pObj); + // simulate for the given number of timeframes + vNodes = Abc_NtkDfs( pNtk, 0 ); + for ( f = 0; f < nFrames; f++ ) + { + // simulate internal nodes + Vec_PtrForEachEntry( vNodes, pObj, i ) + pObj->pCopy = (void *)Abc_ObjSopSimulate( pObj ); + // bring the results to the COs + Abc_NtkForEachCo( pNtk, pObj, i ) + pObj->pCopy = Abc_ObjFanin0(pObj)->pCopy; + // assign PI values + Abc_NtkForEachPi( pNtk, pObj, i ) + pObj->pCopy = (void *)(rand() & 1); + // transfer the latch values + Abc_NtkForEachLatch( pNtk, pObj, i ) + Abc_ObjFanout0(pObj)->pCopy = Abc_ObjFanin0(pObj)->pCopy; + } + Vec_PtrFree( vNodes ); + // set the final values + Abc_NtkForEachLatch( pNtk, pObj, i ) + pObj->pData = (void *)(Abc_ObjFanout0(pObj)->pCopy ? ABC_INIT_ONE : ABC_INIT_ZERO); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/ret/retInt.h b/src/opt/ret/retInt.h new file mode 100644 index 00000000..51428bce --- /dev/null +++ b/src/opt/ret/retInt.h @@ -0,0 +1,80 @@ +/**CFile**************************************************************** + + FileName [retInt.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Retiming package.] + + Synopsis [Internal declarations.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - Oct 31, 2006.] + + Revision [$Id: retInt.h,v 1.00 2006/10/31 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef __RET_INT_H__ +#define __RET_INT_H__ + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +#include "abc.h" + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// STRUCTURE DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +/*=== retArea.c ========================================================*/ +extern int Abc_NtkRetimeMinArea( Abc_Ntk_t * pNtk, int fForwardOnly, int fBackwardOnly, int fVerbose ); +/*=== retCore.c ========================================================*/ +extern int Abc_NtkRetime( Abc_Ntk_t * pNtk, int Mode, int fForwardOnly, int fBackwardOnly, int fOneStep, int fVerbose ); +/*=== retDelay.c ========================================================*/ +extern int Abc_NtkRetimeMinDelay( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkCopy, int nIterLimit, int fForward, int fVerbose ); +/*=== retDirect.c ========================================================*/ +extern int Abc_NtkRetimeIncremental( Abc_Ntk_t * pNtk, int fForward, int fMinDelay, int fOneStep, int fVerbose ); +extern void Abc_NtkRetimeShareLatches( Abc_Ntk_t * pNtk, int fInitial ); +extern int Abc_NtkRetimeNodeIsEnabled( Abc_Obj_t * pObj, int fForward ); +extern void Abc_NtkRetimeNode( Abc_Obj_t * pObj, int fForward, int fInitial ); +extern st_table * Abc_NtkRetimePrepareLatches( Abc_Ntk_t * pNtk ); +extern int Abc_NtkRetimeFinalizeLatches( Abc_Ntk_t * pNtk, st_table * tLatches, int nIdMaxStart ); +/*=== retFlow.c ========================================================*/ +extern void Abc_NtkMaxFlowTest( Abc_Ntk_t * pNtk ); +extern Vec_Ptr_t * Abc_NtkMaxFlow( Abc_Ntk_t * pNtk, int fForward, int fVerbose ); +/*=== retInit.c ========================================================*/ +extern Vec_Int_t * Abc_NtkRetimeInitialValues( Abc_Ntk_t * pNtkSat, Vec_Int_t * vValues, int fVerbose ); +extern int Abc_ObjSopSimulate( Abc_Obj_t * pObj ); +extern void Abc_NtkRetimeTranferToCopy( Abc_Ntk_t * pNtk ); +extern void Abc_NtkRetimeTranferFromCopy( Abc_Ntk_t * pNtk ); +extern Vec_Int_t * Abc_NtkRetimeCollectLatchValues( Abc_Ntk_t * pNtk ); +extern void Abc_NtkRetimeInsertLatchValues( Abc_Ntk_t * pNtk, Vec_Int_t * vValues ); +extern Abc_Ntk_t * Abc_NtkRetimeBackwardInitialStart( Abc_Ntk_t * pNtk ); +extern void Abc_NtkRetimeBackwardInitialFinish( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkNew, Vec_Int_t * vValuesOld, int fVerbose ); +/*=== retLvalue.c ========================================================*/ +extern int Abc_NtkRetimeLValue( Abc_Ntk_t * pNtk, int nIterLimit, int fVerbose ); + +#endif + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/ret/retLvalue.c b/src/opt/ret/retLvalue.c new file mode 100644 index 00000000..b4d9e946 --- /dev/null +++ b/src/opt/ret/retLvalue.c @@ -0,0 +1,395 @@ +/**CFile**************************************************************** + + FileName [retLvalue.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Retiming package.] + + Synopsis [Implementation of Pan's retiming algorithm.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - Oct 31, 2006.] + + Revision [$Id: retLvalue.c,v 1.00 2006/10/31 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "retInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +// node status after updating its arrival time +enum { ABC_RET_UPDATE_FAIL, ABC_RET_UPDATE_NO, ABC_RET_UPDATE_YES }; + +// the internal procedures +static Vec_Int_t * Abc_NtkRetimeGetLags( Abc_Ntk_t * pNtk, int nIterLimit, int fVerbose ); +static int Abc_NtkRetimeSearch_rec( Abc_Ntk_t * pNtk, Vec_Ptr_t * vNodes, Vec_Ptr_t * vLatches, int FiMin, int FiMax, int nMaxIters, int fVerbose ); +static int Abc_NtkRetimeForPeriod( Abc_Ntk_t * pNtk, Vec_Ptr_t * vNodes, Vec_Ptr_t * vLatches, int Fi, int nMaxIters, int fVerbose ); +static int Abc_NtkRetimeUpdateLValue( Abc_Ntk_t * pNtk, Vec_Ptr_t * vNodes, Vec_Ptr_t * vLatches, int Fi ); +static int Abc_NtkRetimePosOverLimit( Abc_Ntk_t * pNtk, int Fi ); +static Vec_Ptr_t * Abc_ManCollectLatches( Abc_Ntk_t * pNtk ); +static int Abc_NtkRetimeUsingLags( Abc_Ntk_t * pNtk, Vec_Int_t * vLags, int fVerbose ); + +static inline int Abc_NodeComputeLag( int LValue, int Fi ) { return (LValue + (1<<16)*Fi)/Fi - (1<<16) - (int)(LValue % Fi == 0); } +static inline int Abc_NodeGetLValue( Abc_Obj_t * pNode ) { return (int)pNode->pCopy; } +static inline void Abc_NodeSetLValue( Abc_Obj_t * pNode, int Value ) { pNode->pCopy = (void *)Value; } + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Implements Pan's retiming algorithm.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkRetimeLValue( Abc_Ntk_t * pNtk, int nIterLimit, int fVerbose ) +{ + Vec_Int_t * vLags; + int nLatches = Abc_NtkLatchNum(pNtk); + assert( Abc_NtkIsLogic( pNtk ) ); + // get the lags + vLags = Abc_NtkRetimeGetLags( pNtk, nIterLimit, fVerbose ); + // compute the retiming +// Abc_NtkRetimeUsingLags( pNtk, vLags, fVerbose ); + Vec_IntFree( vLags ); + // fix the COs +// Abc_NtkLogicMakeSimpleCos( pNtk, 0 ); + // check for correctness + if ( !Abc_NtkCheck( pNtk ) ) + fprintf( stdout, "Abc_NtkRetimeLValue(): Network check has failed.\n" ); + // return the number of latches saved + return nLatches - Abc_NtkLatchNum(pNtk); +} + +/**Function************************************************************* + + Synopsis [Computes the retiming lags.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Int_t * Abc_NtkRetimeGetLags( Abc_Ntk_t * pNtk, int nIterLimit, int fVerbose ) +{ + Vec_Int_t * vLags; + Vec_Ptr_t * vNodes, * vLatches; + Abc_Obj_t * pNode; + int i, FiMax, FiBest, RetValue, clk, clkIter; + char NodeLag; + + // get the upper bound on the clock period + FiMax = Abc_NtkLevel(pNtk); + + // make sure this clock period is feasible + vNodes = Abc_NtkDfs( pNtk, 0 ); + vLatches = Abc_ManCollectLatches( pNtk ); + if ( !Abc_NtkRetimeForPeriod( pNtk, vNodes, vLatches, FiMax, nIterLimit, fVerbose ) ) + { + Vec_PtrFree( vNodes ); + printf( "Abc_NtkRetimeGetLags() error: The upper bound on the clock period cannot be computed.\n" ); + return Vec_IntStart( Abc_NtkObjNumMax(pNtk) + 1 ); + } + + // search for the optimal clock period between 0 and nLevelMax +clk = clock(); + FiBest = Abc_NtkRetimeSearch_rec( pNtk, vNodes, vLatches, 0, FiMax, nIterLimit, fVerbose ); +clkIter = clock() - clk; + + // recompute the best l-values + RetValue = Abc_NtkRetimeForPeriod( pNtk, vNodes, vLatches, FiBest, nIterLimit, fVerbose ); + assert( RetValue ); + + // fix the problem with non-converged delays + Abc_NtkForEachNode( pNtk, pNode, i ) + if ( Abc_NodeGetLValue(pNode) < -ABC_INFINITY/2 ) + Abc_NodeSetLValue( pNode, 0 ); + + // write the retiming lags + vLags = Vec_IntStart( Abc_NtkObjNumMax(pNtk) + 1 ); + Abc_NtkForEachNode( pNtk, pNode, i ) + { + NodeLag = Abc_NodeComputeLag( Abc_NodeGetLValue(pNode), FiBest ); + Vec_IntWriteEntry( vLags, pNode->Id, NodeLag ); + } +/* + Abc_NtkForEachPo( pNtk, pNode, i ) + printf( "%d ", Abc_NodeGetLValue(Abc_ObjFanin0(pNode)) ); + printf( "\n" ); + Abc_NtkForEachLatch( pNtk, pNode, i ) + printf( "%d/%d ", Abc_NodeGetLValue(Abc_ObjFanout0(pNode)), Abc_NodeGetLValue(Abc_ObjFanout0(pNode)) + FiBest ); + printf( "\n" ); +*/ + + // print the result +// if ( fVerbose ) + printf( "The best clock period is %3d. (Currently, network is not modified.)\n", FiBest ); +/* + { + FILE * pTable; + pTable = fopen( "iscas/seqmap__stats2.txt", "a+" ); + fprintf( pTable, "%d ", FiBest ); + fprintf( pTable, "\n" ); + fclose( pTable ); + } +*/ + Vec_PtrFree( vNodes ); + Vec_PtrFree( vLatches ); + return vLags; +} + +/**Function************************************************************* + + Synopsis [Performs binary search for the optimal clock period.] + + Description [Assumes that FiMin is infeasible while FiMax is feasible.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkRetimeSearch_rec( Abc_Ntk_t * pNtk, Vec_Ptr_t * vNodes, Vec_Ptr_t * vLatches, int FiMin, int FiMax, int nMaxIters, int fVerbose ) +{ + int Median; + assert( FiMin < FiMax ); + if ( FiMin + 1 == FiMax ) + return FiMax; + Median = FiMin + (FiMax - FiMin)/2; + if ( Abc_NtkRetimeForPeriod( pNtk, vNodes, vLatches, Median, nMaxIters, fVerbose ) ) + return Abc_NtkRetimeSearch_rec( pNtk, vNodes, vLatches, FiMin, Median, nMaxIters, fVerbose ); // Median is feasible + else + return Abc_NtkRetimeSearch_rec( pNtk, vNodes, vLatches, Median, FiMax, nMaxIters, fVerbose ); // Median is infeasible +} + +/**Function************************************************************* + + Synopsis [Returns 1 if retiming with this clock period is feasible.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkRetimeForPeriod( Abc_Ntk_t * pNtk, Vec_Ptr_t * vNodes, Vec_Ptr_t * vLatches, int Fi, int nMaxIters, int fVerbose ) +{ + Abc_Obj_t * pObj; + int c, i, fConverged; + // set l-values of all nodes to be minus infinity, except PIs and constants + Abc_NtkForEachObj( pNtk, pObj, i ) + if ( Abc_ObjFaninNum(pObj) == 0 ) + Abc_NodeSetLValue( pObj, 0 ); + else + Abc_NodeSetLValue( pObj, -ABC_INFINITY ); + // update all values iteratively + fConverged = 0; + for ( c = 1; c <= nMaxIters; c++ ) + { + if ( !Abc_NtkRetimeUpdateLValue( pNtk, vNodes, vLatches, Fi ) ) + { + fConverged = 1; + break; + } + if ( Abc_NtkRetimePosOverLimit(pNtk, Fi) ) + break; + } + // report the results + if ( fVerbose ) + { + if ( !fConverged ) + printf( "Period = %3d. Iterations = %3d. Infeasible %s\n", Fi, c, (c > nMaxIters)? "(timeout)" : "" ); + else + printf( "Period = %3d. Iterations = %3d. Feasible\n", Fi, c ); + } +/* + // check if any AND gates have infinite delay + Counter = 0; + Abc_NtkForEachNode( pNtk, pObj, i ) + Counter += (Abc_NodeGetLValue(pObj) < -ABC_INFINITY/2); + if ( Counter > 0 ) + printf( "Warning: %d internal nodes have wrong l-values!\n", Counter ); +*/ + return fConverged; +} + +/**Function************************************************************* + + Synopsis [Performs one iteration of l-value computation for the nodes.] + + Description [Experimentally it was found that checking POs changes + is not enough to detect the convergence of l-values in the network.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkRetimeUpdateLValue( Abc_Ntk_t * pNtk, Vec_Ptr_t * vNodes, Vec_Ptr_t * vLatches, int Fi ) +{ + Abc_Obj_t * pObj, * pFanin; + int i, k, lValueNew, fChange; + // go through the nodes and detect change + fChange = 0; + Vec_PtrForEachEntry( vNodes, pObj, i ) + { + assert( Abc_ObjIsNode(pObj) ); + lValueNew = -ABC_INFINITY; + Abc_ObjForEachFanin( pObj, pFanin, k ) + { + if ( lValueNew < Abc_NodeGetLValue(pFanin) ) + lValueNew = Abc_NodeGetLValue(pFanin); + } + lValueNew++; + if ( Abc_NodeGetLValue(pObj) < lValueNew ) + { + Abc_NodeSetLValue( pObj, lValueNew ); + fChange = 1; + } + } + // propagate values through the latches + Vec_PtrForEachEntry( vLatches, pObj, i ) + Abc_NodeSetLValue( Abc_ObjFanout0(pObj), Abc_NodeGetLValue(Abc_ObjFanin0(Abc_ObjFanin0(pObj))) - Fi ); + return fChange; +} + +/**Function************************************************************* + + Synopsis [Detects the case when l-values exceeded the limit.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkRetimePosOverLimit( Abc_Ntk_t * pNtk, int Fi ) +{ + Abc_Obj_t * pObj; + int i; + Abc_NtkForEachPo( pNtk, pObj, i ) + if ( Abc_NodeGetLValue(Abc_ObjFanin0(pObj)) > Fi ) + return 1; + return 0; +} + +/**Function************************************************************* + + Synopsis [Collects latches in the topological order.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_ManCollectLatches_rec( Abc_Obj_t * pObj, Vec_Ptr_t * vLatches ) +{ + Abc_Obj_t * pDriver; + if ( !Abc_ObjIsLatch(pObj) ) + return; + // skip already collected latches + if ( Abc_NodeIsTravIdCurrent(pObj) ) + return; + Abc_NodeSetTravIdCurrent(pObj); + // get the driver node feeding into the latch + pDriver = Abc_ObjFanin0(Abc_ObjFanin0(pObj)); + // call recursively if the driver looks like a latch output + if ( Abc_ObjIsBo(pDriver) ) + Abc_ManCollectLatches_rec( Abc_ObjFanin0(pDriver), vLatches ); + // collect the latch + Vec_PtrPush( vLatches, pObj ); +} + +/**Function************************************************************* + + Synopsis [Collects latches in the topological order.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Abc_ManCollectLatches( Abc_Ntk_t * pNtk ) +{ + Vec_Ptr_t * vLatches; + Abc_Obj_t * pObj; + int i; + vLatches = Vec_PtrAlloc( Abc_NtkLatchNum(pNtk) ); + Abc_NtkIncrementTravId( pNtk ); + Abc_NtkForEachLatch( pNtk, pObj, i ) + Abc_ManCollectLatches_rec( pObj, vLatches ); + assert( Vec_PtrSize(vLatches) == Abc_NtkLatchNum(pNtk) ); + return vLatches; +} + +/**Function************************************************************* + + Synopsis [Implements the retiming given as the array of retiming lags.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_NtkRetimeUsingLags( Abc_Ntk_t * pNtk, Vec_Int_t * vLags, int fVerbose ) +{ + Abc_Obj_t * pObj; + int fChanges, fForward, nTotalMoves, Lag, Counter, i; + // iterate over the nodes + nTotalMoves = 0; + do { + fChanges = 0; + Abc_NtkForEachNode( pNtk, pObj, i ) + { + Lag = Vec_IntEntry( vLags, pObj->Id ); + if ( !Lag ) + continue; + fForward = (Lag < 0); + if ( Abc_NtkRetimeNodeIsEnabled( pObj, fForward ) ) + { + Abc_NtkRetimeNode( pObj, fForward, 0 ); + fChanges = 1; + nTotalMoves++; + Vec_IntAddToEntry( vLags, pObj->Id, fForward? 1 : -1 ); + } + } + } while ( fChanges ); + if ( fVerbose ) + printf( "Total latch moves = %d.\n", nTotalMoves ); + // check if there are remaining lags + Counter = 0; + Abc_NtkForEachNode( pNtk, pObj, i ) + Counter += (Vec_IntEntry( vLags, pObj->Id ) != 0); + if ( Counter ) + printf( "Warning! The number of nodes with unrealized lag = %d.\n", Counter ); + return 1; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/ret/ret_.c b/src/opt/ret/ret_.c new file mode 100644 index 00000000..89625e17 --- /dev/null +++ b/src/opt/ret/ret_.c @@ -0,0 +1,48 @@ +/**CFile**************************************************************** + + FileName [ret_.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Retiming package.] + + Synopsis [] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - Oct 31, 2006.] + + Revision [$Id: ret_.c,v 1.00 2006/10/31 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "retInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/rwr/module.make b/src/opt/rwr/module.make new file mode 100644 index 00000000..077a3c01 --- /dev/null +++ b/src/opt/rwr/module.make @@ -0,0 +1,7 @@ +SRC += src/opt/rwr/rwrDec.c \ + src/opt/rwr/rwrEva.c \ + src/opt/rwr/rwrExp.c \ + src/opt/rwr/rwrLib.c \ + src/opt/rwr/rwrMan.c \ + src/opt/rwr/rwrPrint.c \ + src/opt/rwr/rwrUtil.c diff --git a/src/opt/rwr/rwr.h b/src/opt/rwr/rwr.h new file mode 100644 index 00000000..f24f9535 --- /dev/null +++ b/src/opt/rwr/rwr.h @@ -0,0 +1,169 @@ +/**CFile**************************************************************** + + FileName [rwr.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [DAG-aware AIG rewriting package.] + + Synopsis [External declarations.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: rwr.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef __RWR_H__ +#define __RWR_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +#include "abc.h" +#include "cut.h" + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// BASIC TYPES /// +//////////////////////////////////////////////////////////////////////// + +#define RWR_LIMIT 1048576/4 // ((1 << 20) + +typedef struct Rwr_Man_t_ Rwr_Man_t; +typedef struct Rwr_Node_t_ Rwr_Node_t; + +struct Rwr_Man_t_ +{ + // internal lookups + int nFuncs; // number of four var functions + unsigned short * puCanons; // canonical forms + char * pPhases; // canonical phases + char * pPerms; // canonical permutations + unsigned char * pMap; // mapping of functions into class numbers + unsigned short * pMapInv; // mapping of classes into functions + char * pPractical; // practical NPN classes + char ** pPerms4; // four-var permutations + // node space + Vec_Ptr_t * vForest; // all the nodes + Rwr_Node_t ** pTable; // the hash table of nodes by their canonical form + Vec_Vec_t * vClasses; // the nodes of the equivalence classes + Extra_MmFixed_t * pMmNode; // memory for nodes and cuts + // statistical variables + int nTravIds; // the counter of traversal IDs + int nConsidered; // the number of nodes considered + int nAdded; // the number of nodes added to lists + int nClasses; // the number of NN classes + // the result of resynthesis + int fCompl; // indicates if the output of FF should be complemented + void * pGraph; // the decomposition tree (temporary) + Vec_Ptr_t * vFanins; // the fanins array (temporary) + Vec_Ptr_t * vFaninsCur; // the fanins array (temporary) + Vec_Int_t * vLevNums; // the array of levels (temporary) + Vec_Ptr_t * vNodesTemp; // the nodes in MFFC (temporary) + // node statistics + int nNodesConsidered; + int nNodesRewritten; + int nNodesGained; + int nNodesBeg; + int nNodesEnd; + int nScores[222]; + int nCutsGood; + int nCutsBad; + int nSubgraphs; + // runtime statistics + int timeStart; + int timeCut; + int timeRes; + int timeEval; + int timeMffc; + int timeUpdate; + int timeTotal; +}; + +struct Rwr_Node_t_ // 24 bytes +{ + int Id; // ID + int TravId; // traversal ID + short nScore; + short nGain; + short nAdded; + unsigned uTruth : 16; // truth table + unsigned Volume : 8; // volume + unsigned Level : 6; // level + unsigned fUsed : 1; // mark + unsigned fExor : 1; // mark + Rwr_Node_t * p0; // first child + Rwr_Node_t * p1; // second child + Rwr_Node_t * pNext; // next in the table +}; + +// manipulation of complemented attributes +static inline bool Rwr_IsComplement( Rwr_Node_t * p ) { return (bool)(((unsigned long)p) & 01); } +static inline Rwr_Node_t * Rwr_Regular( Rwr_Node_t * p ) { return (Rwr_Node_t *)((unsigned long)(p) & ~01); } +static inline Rwr_Node_t * Rwr_Not( Rwr_Node_t * p ) { return (Rwr_Node_t *)((unsigned long)(p) ^ 01); } +static inline Rwr_Node_t * Rwr_NotCond( Rwr_Node_t * p, int c ) { return (Rwr_Node_t *)((unsigned long)(p) ^ (c)); } + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +/*=== rwrDec.c ========================================================*/ +extern void Rwr_ManPreprocess( Rwr_Man_t * p ); +/*=== rwrEva.c ========================================================*/ +extern int Rwr_NodeRewrite( Rwr_Man_t * p, Cut_Man_t * pManCut, Abc_Obj_t * pNode, int fUpdateLevel, int fUseZeros, int fPlaceEnable ); +extern void Rwr_ScoresClean( Rwr_Man_t * p ); +extern void Rwr_ScoresReport( Rwr_Man_t * p ); +/*=== rwrLib.c ========================================================*/ +extern void Rwr_ManPrecompute( Rwr_Man_t * p ); +extern Rwr_Node_t * Rwr_ManAddVar( Rwr_Man_t * p, unsigned uTruth, int fPrecompute ); +extern Rwr_Node_t * Rwr_ManAddNode( Rwr_Man_t * p, Rwr_Node_t * p0, Rwr_Node_t * p1, int fExor, int Level, int Volume ); +extern int Rwr_ManNodeVolume( Rwr_Man_t * p, Rwr_Node_t * p0, Rwr_Node_t * p1 ); +extern void Rwr_ManIncTravId( Rwr_Man_t * p ); +/*=== rwrMan.c ========================================================*/ +extern Rwr_Man_t * Rwr_ManStart( bool fPrecompute ); +extern void Rwr_ManStop( Rwr_Man_t * p ); +extern void Rwr_ManPrintStats( Rwr_Man_t * p ); +extern void Rwr_ManPrintStatsFile( Rwr_Man_t * p ); +extern void * Rwr_ManReadDecs( Rwr_Man_t * p ); +extern Vec_Ptr_t * Rwr_ManReadLeaves( Rwr_Man_t * p ); +extern int Rwr_ManReadCompl( Rwr_Man_t * p ); +extern void Rwr_ManAddTimeCuts( Rwr_Man_t * p, int Time ); +extern void Rwr_ManAddTimeUpdate( Rwr_Man_t * p, int Time ); +extern void Rwr_ManAddTimeTotal( Rwr_Man_t * p, int Time ); +/*=== rwrPrint.c ========================================================*/ +extern void Rwr_ManPrint( Rwr_Man_t * p ); +/*=== rwrUtil.c ========================================================*/ +extern void Rwr_ManWriteToArray( Rwr_Man_t * p ); +extern void Rwr_ManLoadFromArray( Rwr_Man_t * p, int fVerbose ); +extern void Rwr_ManWriteToFile( Rwr_Man_t * p, char * pFileName ); +extern void Rwr_ManLoadFromFile( Rwr_Man_t * p, char * pFileName ); +extern void Rwr_ListAddToTail( Rwr_Node_t ** ppList, Rwr_Node_t * pNode ); +extern char * Rwr_ManGetPractical( Rwr_Man_t * p ); + +#ifdef __cplusplus +} +#endif + +#endif + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + diff --git a/src/opt/rwr/rwrDec.c b/src/opt/rwr/rwrDec.c new file mode 100644 index 00000000..ef7af34f --- /dev/null +++ b/src/opt/rwr/rwrDec.c @@ -0,0 +1,150 @@ +/**CFile**************************************************************** + + FileName [rwrDec.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [DAG-aware AIG rewriting package.] + + Synopsis [Evaluation and decomposition procedures.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: rwrDec.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "rwr.h" +#include "dec.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static Dec_Graph_t * Rwr_NodePreprocess( Rwr_Man_t * p, Rwr_Node_t * pNode ); +static Dec_Edge_t Rwr_TravCollect_rec( Rwr_Man_t * p, Rwr_Node_t * pNode, Dec_Graph_t * pGraph ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Preprocesses computed library of subgraphs.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_ManPreprocess( Rwr_Man_t * p ) +{ + Dec_Graph_t * pGraph; + Rwr_Node_t * pNode; + int i, k; + // put the nodes into the structure + p->pMapInv = ALLOC( unsigned short, 222 ); + memset( p->pMapInv, 0, sizeof(unsigned short) * 222 ); + p->vClasses = Vec_VecStart( 222 ); + for ( i = 0; i < p->nFuncs; i++ ) + { + if ( p->pTable[i] == NULL ) + continue; + // consider all implementations of this function + for ( pNode = p->pTable[i]; pNode; pNode = pNode->pNext ) + { + assert( pNode->uTruth == p->pTable[i]->uTruth ); + assert( p->pMap[pNode->uTruth] >= 0 && p->pMap[pNode->uTruth] < 222 ); + Vec_VecPush( p->vClasses, p->pMap[pNode->uTruth], pNode ); + p->pMapInv[ p->pMap[pNode->uTruth] ] = p->puCanons[pNode->uTruth]; + } + } + // compute decomposition forms for each node and verify them + Vec_VecForEachEntry( p->vClasses, pNode, i, k ) + { + pGraph = Rwr_NodePreprocess( p, pNode ); + pNode->pNext = (Rwr_Node_t *)pGraph; + assert( pNode->uTruth == (Dec_GraphDeriveTruth(pGraph) & 0xFFFF) ); + } +} + +/**Function************************************************************* + + Synopsis [Preprocesses subgraphs rooted at this node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Dec_Graph_t * Rwr_NodePreprocess( Rwr_Man_t * p, Rwr_Node_t * pNode ) +{ + Dec_Graph_t * pGraph; + Dec_Edge_t eRoot; + assert( !Rwr_IsComplement(pNode) ); + // consider constant + if ( pNode->uTruth == 0 ) + return Dec_GraphCreateConst0(); + // consider the case of elementary var + if ( pNode->uTruth == 0x00FF ) + return Dec_GraphCreateLeaf( 3, 4, 1 ); + // start the subgraphs + pGraph = Dec_GraphCreate( 4 ); + // collect the nodes + Rwr_ManIncTravId( p ); + eRoot = Rwr_TravCollect_rec( p, pNode, pGraph ); + Dec_GraphSetRoot( pGraph, eRoot ); + return pGraph; +} + +/**Function************************************************************* + + Synopsis [Adds one node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Dec_Edge_t Rwr_TravCollect_rec( Rwr_Man_t * p, Rwr_Node_t * pNode, Dec_Graph_t * pGraph ) +{ + Dec_Edge_t eNode0, eNode1, eNode; + // elementary variable + if ( pNode->fUsed ) + return Dec_EdgeCreate( pNode->Id - 1, 0 ); + // previously visited node + if ( pNode->TravId == p->nTravIds ) + return Dec_IntToEdge( pNode->Volume ); + pNode->TravId = p->nTravIds; + // solve for children + eNode0 = Rwr_TravCollect_rec( p, Rwr_Regular(pNode->p0), pGraph ); + if ( Rwr_IsComplement(pNode->p0) ) + eNode0.fCompl = !eNode0.fCompl; + eNode1 = Rwr_TravCollect_rec( p, Rwr_Regular(pNode->p1), pGraph ); + if ( Rwr_IsComplement(pNode->p1) ) + eNode1.fCompl = !eNode1.fCompl; + // create the decomposition node(s) + if ( pNode->fExor ) + eNode = Dec_GraphAddNodeXor( pGraph, eNode0, eNode1, 0 ); + else + eNode = Dec_GraphAddNodeAnd( pGraph, eNode0, eNode1 ); + // save the result + pNode->Volume = Dec_EdgeToInt( eNode ); + return eNode; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/rwr/rwrEva.c b/src/opt/rwr/rwrEva.c new file mode 100644 index 00000000..0eb547f2 --- /dev/null +++ b/src/opt/rwr/rwrEva.c @@ -0,0 +1,588 @@ +/**CFile**************************************************************** + + FileName [rwrDec.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [DAG-aware AIG rewriting package.] + + Synopsis [Evaluation and decomposition procedures.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: rwrDec.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "rwr.h" +#include "dec.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static Dec_Graph_t * Rwr_CutEvaluate( Rwr_Man_t * p, Abc_Obj_t * pRoot, Cut_Cut_t * pCut, Vec_Ptr_t * vFaninsCur, int nNodesSaved, int LevelMax, int * pGainBest, int fPlaceEnable ); +static int Rwr_CutIsBoolean( Abc_Obj_t * pObj, Vec_Ptr_t * vLeaves ); +static int Rwr_CutCountNumNodes( Abc_Obj_t * pObj, Cut_Cut_t * pCut ); +static int Rwr_NodeGetDepth_rec( Abc_Obj_t * pObj, Vec_Ptr_t * vLeaves ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Performs rewriting for one node.] + + Description [This procedure considers all the cuts computed for the node + and tries to rewrite each of them using the "forest" of different AIG + structures precomputed and stored in the RWR manager. + Determines the best rewriting and computes the gain in the number of AIG + nodes in the final network. In the end, p->vFanins contains information + about the best cut that can be used for rewriting, while p->pGraph gives + the decomposition dag (represented using decomposition graph data structure). + Returns gain in the number of nodes or -1 if node cannot be rewritten.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Rwr_NodeRewrite( Rwr_Man_t * p, Cut_Man_t * pManCut, Abc_Obj_t * pNode, int fUpdateLevel, int fUseZeros, int fPlaceEnable ) +{ + int fVeryVerbose = 0; + Dec_Graph_t * pGraph; + Cut_Cut_t * pCut;//, * pTemp; + Abc_Obj_t * pFanin; + unsigned uPhase, uTruthBest, uTruth; + char * pPerm; + int Required, nNodesSaved, nNodesSaveCur; + int i, GainCur, GainBest = -1; + int clk, clk2;//, Counter; + + p->nNodesConsidered++; + // get the required times + Required = fUpdateLevel? Abc_ObjRequiredLevel(pNode) : ABC_INFINITY; + + // get the node's cuts +clk = clock(); + pCut = (Cut_Cut_t *)Abc_NodeGetCutsRecursive( pManCut, pNode, 0, 0 ); + assert( pCut != NULL ); +p->timeCut += clock() - clk; + +//printf( " %d", Rwr_CutCountNumNodes(pNode, pCut) ); +/* + Counter = 0; + for ( pTemp = pCut->pNext; pTemp; pTemp = pTemp->pNext ) + Counter++; + printf( "%d ", Counter ); +*/ + // go through the cuts +clk = clock(); + for ( pCut = pCut->pNext; pCut; pCut = pCut->pNext ) + { + // consider only 4-input cuts + if ( pCut->nLeaves < 4 ) + continue; +// Cut_CutPrint( pCut, 0 ), printf( "\n" ); + + // get the fanin permutation + uTruth = 0xFFFF & *Cut_CutReadTruth(pCut); + pPerm = p->pPerms4[ p->pPerms[uTruth] ]; + uPhase = p->pPhases[uTruth]; + // collect fanins with the corresponding permutation/phase + Vec_PtrClear( p->vFaninsCur ); + Vec_PtrFill( p->vFaninsCur, (int)pCut->nLeaves, 0 ); + for ( i = 0; i < (int)pCut->nLeaves; i++ ) + { + pFanin = Abc_NtkObj( pNode->pNtk, pCut->pLeaves[pPerm[i]] ); + if ( pFanin == NULL ) + break; + pFanin = Abc_ObjNotCond(pFanin, ((uPhase & (1< 0) ); + Vec_PtrWriteEntry( p->vFaninsCur, i, pFanin ); + } + if ( i != (int)pCut->nLeaves ) + { + p->nCutsBad++; + continue; + } + p->nCutsGood++; + + { + int Counter = 0; + Vec_PtrForEachEntry( p->vFaninsCur, pFanin, i ) + if ( Abc_ObjFanoutNum(Abc_ObjRegular(pFanin)) == 1 ) + Counter++; + if ( Counter > 2 ) + continue; + } + +clk2 = clock(); +/* + printf( "Considering: (" ); + Vec_PtrForEachEntry( p->vFaninsCur, pFanin, i ) + printf( "%d ", Abc_ObjFanoutNum(Abc_ObjRegular(pFanin)) ); + printf( ")\n" ); +*/ + // mark the fanin boundary + Vec_PtrForEachEntry( p->vFaninsCur, pFanin, i ) + Abc_ObjRegular(pFanin)->vFanouts.nSize++; + + // label MFFC with current ID + Abc_NtkIncrementTravId( pNode->pNtk ); + nNodesSaved = Abc_NodeMffcLabelAig( pNode ); + // unmark the fanin boundary + Vec_PtrForEachEntry( p->vFaninsCur, pFanin, i ) + Abc_ObjRegular(pFanin)->vFanouts.nSize--; +p->timeMffc += clock() - clk2; + + // evaluate the cut +clk2 = clock(); + pGraph = Rwr_CutEvaluate( p, pNode, pCut, p->vFaninsCur, nNodesSaved, Required, &GainCur, fPlaceEnable ); +p->timeEval += clock() - clk2; + + // check if the cut is better than the current best one + if ( pGraph != NULL && GainBest < GainCur ) + { + // save this form + nNodesSaveCur = nNodesSaved; + GainBest = GainCur; + p->pGraph = pGraph; + p->fCompl = ((uPhase & (1<<4)) > 0); + uTruthBest = 0xFFFF & *Cut_CutReadTruth(pCut); + // collect fanins in the + Vec_PtrClear( p->vFanins ); + Vec_PtrForEachEntry( p->vFaninsCur, pFanin, i ) + Vec_PtrPush( p->vFanins, pFanin ); + } + } +p->timeRes += clock() - clk; + + if ( GainBest == -1 ) + return -1; +/* + if ( GainBest > 0 ) + { + printf( "Class %d ", p->pMap[uTruthBest] ); + printf( "Gain = %d. Node %d : ", GainBest, pNode->Id ); + Vec_PtrForEachEntry( p->vFanins, pFanin, i ) + printf( "%d ", Abc_ObjRegular(pFanin)->Id ); + Dec_GraphPrint( stdout, p->pGraph, NULL, NULL ); + printf( "\n" ); + } +*/ + +// printf( "%d", nNodesSaveCur - GainBest ); +/* + if ( GainBest > 0 ) + { + if ( Rwr_CutIsBoolean( pNode, p->vFanins ) ) + printf( "b" ); + else + { + printf( "Node %d : ", pNode->Id ); + Vec_PtrForEachEntry( p->vFanins, pFanin, i ) + printf( "%d ", Abc_ObjRegular(pFanin)->Id ); + printf( "a" ); + } + } +*/ +/* + if ( GainBest > 0 ) + if ( p->fCompl ) + printf( "c" ); + else + printf( "." ); +*/ + + // copy the leaves + Vec_PtrForEachEntry( p->vFanins, pFanin, i ) + Dec_GraphNode(p->pGraph, i)->pFunc = pFanin; +/* + printf( "(" ); + Vec_PtrForEachEntry( p->vFanins, pFanin, i ) + printf( " %d", Abc_ObjRegular(pFanin)->vFanouts.nSize - 1 ); + printf( " ) " ); +*/ +// printf( "%d ", Rwr_NodeGetDepth_rec( pNode, p->vFanins ) ); + + p->nScores[p->pMap[uTruthBest]]++; + p->nNodesGained += GainBest; + if ( fUseZeros || GainBest > 0 ) + { + p->nNodesRewritten++; + } + + // report the progress + if ( fVeryVerbose && GainBest > 0 ) + { + printf( "Node %6s : ", Abc_ObjName(pNode) ); + printf( "Fanins = %d. ", p->vFanins->nSize ); + printf( "Save = %d. ", nNodesSaveCur ); + printf( "Add = %d. ", nNodesSaveCur-GainBest ); + printf( "GAIN = %d. ", GainBest ); + printf( "Cone = %d. ", p->pGraph? Dec_GraphNodeNum(p->pGraph) : 0 ); + printf( "Class = %d. ", p->pMap[uTruthBest] ); + printf( "\n" ); + } + return GainBest; +} + +/**Function************************************************************* + + Synopsis [Evaluates the cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Dec_Graph_t * Rwr_CutEvaluate( Rwr_Man_t * p, Abc_Obj_t * pRoot, Cut_Cut_t * pCut, Vec_Ptr_t * vFaninsCur, int nNodesSaved, int LevelMax, int * pGainBest, int fPlaceEnable ) +{ + Vec_Ptr_t * vSubgraphs; + Dec_Graph_t * pGraphBest, * pGraphCur; + Rwr_Node_t * pNode, * pFanin; + int nNodesAdded, GainBest, i, k; + unsigned uTruth; + float CostBest;//, CostCur; + // find the matching class of subgraphs + uTruth = 0xFFFF & *Cut_CutReadTruth(pCut); + vSubgraphs = Vec_VecEntry( p->vClasses, p->pMap[uTruth] ); + p->nSubgraphs += vSubgraphs->nSize; + // determine the best subgraph + GainBest = -1; + CostBest = ABC_INFINITY; + Vec_PtrForEachEntry( vSubgraphs, pNode, i ) + { + // get the current graph + pGraphCur = (Dec_Graph_t *)pNode->pNext; + // copy the leaves + Vec_PtrForEachEntry( vFaninsCur, pFanin, k ) + Dec_GraphNode(pGraphCur, k)->pFunc = pFanin; + // detect how many unlabeled nodes will be reused + nNodesAdded = Dec_GraphToNetworkCount( pRoot, pGraphCur, nNodesSaved, LevelMax ); + if ( nNodesAdded == -1 ) + continue; + assert( nNodesSaved >= nNodesAdded ); +/* + // evaluate the cut + if ( fPlaceEnable ) + { + extern float Abc_PlaceEvaluateCut( Abc_Obj_t * pRoot, Vec_Ptr_t * vFanins ); + + float Alpha = 0.5; // ??? + float PlaceCost; + + // get the placement cost of the cut + PlaceCost = Abc_PlaceEvaluateCut( pRoot, vFaninsCur ); + + // get the weigted cost of the cut + CostCur = nNodesSaved - nNodesAdded + Alpha * PlaceCost; + + // do not allow uphill moves + if ( nNodesSaved - nNodesAdded < 0 ) + continue; + + // decide what cut to use + if ( CostBest > CostCur ) + { + GainBest = nNodesSaved - nNodesAdded; // pure node cost + CostBest = CostCur; // cost with placement + pGraphBest = pGraphCur; // subgraph to be used for rewriting + + // score the graph + if ( nNodesSaved - nNodesAdded > 0 ) + { + pNode->nScore++; + pNode->nGain += GainBest; + pNode->nAdded += nNodesAdded; + } + } + } + else +*/ + { + // count the gain at this node + if ( GainBest < nNodesSaved - nNodesAdded ) + { + GainBest = nNodesSaved - nNodesAdded; + pGraphBest = pGraphCur; + + // score the graph + if ( nNodesSaved - nNodesAdded > 0 ) + { + pNode->nScore++; + pNode->nGain += GainBest; + pNode->nAdded += nNodesAdded; + } + } + } + } + if ( GainBest == -1 ) + return NULL; + *pGainBest = GainBest; + return pGraphBest; +} + +/**Function************************************************************* + + Synopsis [Checks the type of the cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_CutIsBoolean_rec( Abc_Obj_t * pObj, Vec_Ptr_t * vLeaves, int fMarkA ) +{ + if ( Vec_PtrFind(vLeaves, pObj) >= 0 || Vec_PtrFind(vLeaves, Abc_ObjNot(pObj)) >= 0 ) + { + if ( fMarkA ) + pObj->fMarkA = 1; + else + pObj->fMarkB = 1; + return; + } + assert( !Abc_ObjIsCi(pObj) ); + Rwr_CutIsBoolean_rec( Abc_ObjFanin0(pObj), vLeaves, fMarkA ); + Rwr_CutIsBoolean_rec( Abc_ObjFanin1(pObj), vLeaves, fMarkA ); +} + +/**Function************************************************************* + + Synopsis [Checks the type of the cut.] + + Description [Returns 1(0) if the cut is Boolean (algebraic).] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Rwr_CutIsBoolean( Abc_Obj_t * pObj, Vec_Ptr_t * vLeaves ) +{ + Abc_Obj_t * pTemp; + int i, RetValue; + Vec_PtrForEachEntry( vLeaves, pTemp, i ) + { + pTemp = Abc_ObjRegular(pTemp); + assert( !pTemp->fMarkA && !pTemp->fMarkB ); + } + Rwr_CutIsBoolean_rec( Abc_ObjFanin0(pObj), vLeaves, 1 ); + Rwr_CutIsBoolean_rec( Abc_ObjFanin1(pObj), vLeaves, 0 ); + RetValue = 0; + Vec_PtrForEachEntry( vLeaves, pTemp, i ) + { + pTemp = Abc_ObjRegular(pTemp); + RetValue |= pTemp->fMarkA && pTemp->fMarkB; + pTemp->fMarkA = pTemp->fMarkB = 0; + } + return RetValue; +} + + +/**Function************************************************************* + + Synopsis [Count the nodes in the cut space of a node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_CutCountNumNodes_rec( Abc_Obj_t * pObj, Cut_Cut_t * pCut, Vec_Ptr_t * vNodes ) +{ + int i; + for ( i = 0; i < (int)pCut->nLeaves; i++ ) + if ( pCut->pLeaves[i] == pObj->Id ) + { + // check if the node is collected + if ( pObj->fMarkC == 0 ) + { + pObj->fMarkC = 1; + Vec_PtrPush( vNodes, pObj ); + } + return; + } + assert( Abc_ObjIsNode(pObj) ); + // check if the node is collected + if ( pObj->fMarkC == 0 ) + { + pObj->fMarkC = 1; + Vec_PtrPush( vNodes, pObj ); + } + // traverse the fanins + Rwr_CutCountNumNodes_rec( Abc_ObjFanin0(pObj), pCut, vNodes ); + Rwr_CutCountNumNodes_rec( Abc_ObjFanin1(pObj), pCut, vNodes ); +} + +/**Function************************************************************* + + Synopsis [Count the nodes in the cut space of a node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Rwr_CutCountNumNodes( Abc_Obj_t * pObj, Cut_Cut_t * pCut ) +{ + Vec_Ptr_t * vNodes; + int i, Counter; + // collect all nodes + vNodes = Vec_PtrAlloc( 100 ); + for ( pCut = pCut->pNext; pCut; pCut = pCut->pNext ) + Rwr_CutCountNumNodes_rec( pObj, pCut, vNodes ); + // clean all nodes + Vec_PtrForEachEntry( vNodes, pObj, i ) + pObj->fMarkC = 0; + // delete and return + Counter = Vec_PtrSize(vNodes); + Vec_PtrFree( vNodes ); + return Counter; +} + + +/**Function************************************************************* + + Synopsis [Returns depth of the cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Rwr_NodeGetDepth_rec( Abc_Obj_t * pObj, Vec_Ptr_t * vLeaves ) +{ + Abc_Obj_t * pLeaf; + int i, Depth0, Depth1; + if ( Abc_ObjIsCi(pObj) ) + return 0; + Vec_PtrForEachEntry( vLeaves, pLeaf, i ) + if ( pObj == Abc_ObjRegular(pLeaf) ) + return 0; + Depth0 = Rwr_NodeGetDepth_rec( Abc_ObjFanin0(pObj), vLeaves ); + Depth1 = Rwr_NodeGetDepth_rec( Abc_ObjFanin1(pObj), vLeaves ); + return 1 + ABC_MAX( Depth0, Depth1 ); +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_ScoresClean( Rwr_Man_t * p ) +{ + Vec_Ptr_t * vSubgraphs; + Rwr_Node_t * pNode; + int i, k; + for ( i = 0; i < p->vClasses->nSize; i++ ) + { + vSubgraphs = Vec_VecEntry( p->vClasses, i ); + Vec_PtrForEachEntry( vSubgraphs, pNode, k ) + pNode->nScore = pNode->nGain = pNode->nAdded = 0; + } +} + +static int Gains[222]; + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Rwr_ScoresCompare( int * pNum1, int * pNum2 ) +{ + if ( Gains[*pNum1] > Gains[*pNum2] ) + return -1; + if ( Gains[*pNum1] < Gains[*pNum2] ) + return 1; + return 0; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_ScoresReport( Rwr_Man_t * p ) +{ + extern void Ivy_TruthDsdComputePrint( unsigned uTruth ); + int Perm[222]; + Vec_Ptr_t * vSubgraphs; + Rwr_Node_t * pNode; + int i, iNew, k; + unsigned uTruth; + // collect total gains + assert( p->vClasses->nSize == 222 ); + for ( i = 0; i < p->vClasses->nSize; i++ ) + { + Perm[i] = i; + Gains[i] = 0; + vSubgraphs = Vec_VecEntry( p->vClasses, i ); + Vec_PtrForEachEntry( vSubgraphs, pNode, k ) + Gains[i] += pNode->nGain; + } + // sort the gains + qsort( Perm, 222, sizeof(int), (int (*)(const void *, const void *))Rwr_ScoresCompare ); + + // print classes + for ( i = 0; i < p->vClasses->nSize; i++ ) + { + iNew = Perm[i]; + if ( Gains[iNew] == 0 ) + break; + vSubgraphs = Vec_VecEntry( p->vClasses, iNew ); + printf( "CLASS %3d: Subgr = %3d. Total gain = %6d. ", iNew, Vec_PtrSize(vSubgraphs), Gains[iNew] ); + uTruth = (unsigned)p->pMapInv[iNew]; + Extra_PrintBinary( stdout, &uTruth, 16 ); + printf( " " ); + Ivy_TruthDsdComputePrint( (unsigned)p->pMapInv[iNew] | ((unsigned)p->pMapInv[iNew] << 16) ); + Vec_PtrForEachEntry( vSubgraphs, pNode, k ) + { + if ( pNode->nScore == 0 ) + continue; + printf( " %2d: S=%5d. A=%5d. G=%6d. ", k, pNode->nScore, pNode->nAdded, pNode->nGain ); + Dec_GraphPrint( stdout, (Dec_Graph_t *)pNode->pNext, NULL, NULL ); + } + } +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/rwr/rwrExp.c b/src/opt/rwr/rwrExp.c new file mode 100644 index 00000000..2d00bb1c --- /dev/null +++ b/src/opt/rwr/rwrExp.c @@ -0,0 +1,333 @@ +/**CFile**************************************************************** + + FileName [rwrExp.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [DAG-aware AIG rewriting package.] + + Synopsis [Computation of practically used NN-classes of 4-input cuts.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: rwrExp.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "rwr.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Rwr_Man4_t_ Rwr_Man4_t; +struct Rwr_Man4_t_ +{ + // internal lookups + int nFuncs; // the number of four-var functions + unsigned short * puCanons; // canonical forms + int * pnCounts; // the counters of functions in each class + int nConsidered; // the number of nodes considered + int nClasses; // the number of NN classes +}; + +typedef struct Rwr_Man5_t_ Rwr_Man5_t; +struct Rwr_Man5_t_ +{ + // internal lookups + stmm_table * tTableNN; // the NN canonical forms + stmm_table * tTableNPN; // the NPN canonical forms +}; + +static Rwr_Man4_t * s_pManRwrExp4 = NULL; +static Rwr_Man5_t * s_pManRwrExp5 = NULL; + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Collects stats about 4-var functions appearing in netlists.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwt_Man4ExploreStart() +{ + Rwr_Man4_t * p; + p = ALLOC( Rwr_Man4_t, 1 ); + memset( p, 0, sizeof(Rwr_Man4_t) ); + // canonical forms + p->nFuncs = (1<<16); + // canonical forms, phases, perms + Extra_Truth4VarNPN( &p->puCanons, NULL, NULL, NULL ); + // counters + p->pnCounts = ALLOC( int, p->nFuncs ); + memset( p->pnCounts, 0, sizeof(int) * p->nFuncs ); + s_pManRwrExp4 = p; +} + +/**Function************************************************************* + + Synopsis [Collects stats about 4-var functions appearing in netlists.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwt_Man4ExploreCount( unsigned uTruth ) +{ + assert( uTruth < (1<<16) ); + s_pManRwrExp4->pnCounts[ s_pManRwrExp4->puCanons[uTruth] ]++; +} + +/**Function************************************************************* + + Synopsis [Collects stats about 4-var functions appearing in netlists.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwt_Man4ExplorePrint() +{ + FILE * pFile; + int i, CountMax, CountWrite, nCuts, nClasses; + int * pDistrib; + int * pReprs; + // find the max number of occurences + nCuts = nClasses = 0; + CountMax = 0; + for ( i = 0; i < s_pManRwrExp4->nFuncs; i++ ) + { + if ( CountMax < s_pManRwrExp4->pnCounts[i] ) + CountMax = s_pManRwrExp4->pnCounts[i]; + nCuts += s_pManRwrExp4->pnCounts[i]; + if ( s_pManRwrExp4->pnCounts[i] > 0 ) + nClasses++; + } + printf( "Number of cuts considered = %8d.\n", nCuts ); + printf( "Classes occurring at least once = %8d.\n", nClasses ); + // print the distribution of classes + pDistrib = ALLOC( int, CountMax + 1 ); + pReprs = ALLOC( int, CountMax + 1 ); + memset( pDistrib, 0, sizeof(int)*(CountMax + 1) ); + for ( i = 0; i < s_pManRwrExp4->nFuncs; i++ ) + { + pDistrib[ s_pManRwrExp4->pnCounts[i] ]++; + pReprs[ s_pManRwrExp4->pnCounts[i] ] = i; + } + + printf( "Occurence = %6d. Num classes = %4d. \n", 0, 2288-nClasses ); + for ( i = 1; i <= CountMax; i++ ) + if ( pDistrib[i] ) + { + printf( "Occurence = %6d. Num classes = %4d. Repr = ", i, pDistrib[i] ); + Extra_PrintBinary( stdout, (unsigned*)&(pReprs[i]), 16 ); + printf( "\n" ); + } + free( pDistrib ); + free( pReprs ); + // write into a file all classes above limit (5) + CountWrite = 0; + pFile = fopen( "npnclass_stats4.txt", "w" ); + for ( i = 0; i < s_pManRwrExp4->nFuncs; i++ ) + if ( s_pManRwrExp4->pnCounts[i] > 0 ) + { + Extra_PrintHex( pFile, i, 4 ); + fprintf( pFile, " %10d\n", s_pManRwrExp4->pnCounts[i] ); +// fprintf( pFile, "%d ", i ); + CountWrite++; + } + fclose( pFile ); + printf( "%d classes written into file \"%s\".\n", CountWrite, "npnclass_stats4.txt" ); +} + + + + +/**Function************************************************************* + + Synopsis [Collects stats about 4-var functions appearing in netlists.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwt_Man5ExploreStart() +{ + Rwr_Man5_t * p; + p = ALLOC( Rwr_Man5_t, 1 ); + memset( p, 0, sizeof(Rwr_Man5_t) ); + p->tTableNN = stmm_init_table( st_numcmp, st_numhash ); + p->tTableNPN = stmm_init_table( st_numcmp, st_numhash ); + s_pManRwrExp5 = p; + +//Extra_PrintHex( stdout, Extra_TruthCanonNPN( 0x0000FFFF, 5 ), 5 ); +//printf( "\n" ); +} + +/**Function************************************************************* + + Synopsis [Collects stats about 4-var functions appearing in netlists.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwt_Man5ExploreCount( unsigned uTruth ) +{ + int * pCounter; + if ( !stmm_find_or_add( s_pManRwrExp5->tTableNN, (char *)uTruth, (char***)&pCounter ) ) + *pCounter = 0; + (*pCounter)++; +} + +/**Function************************************************************* + + Synopsis [Collects stats about 4-var functions appearing in netlists.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwt_Man5ExplorePrint() +{ + FILE * pFile; + stmm_generator * gen; + int i, CountMax, nCuts, Counter; + int * pDistrib; + unsigned * pReprs; + unsigned uTruth, uTruthC; + int clk = clock(); + Vec_Int_t * vClassesNN, * vClassesNPN; + + // find the max number of occurences + nCuts = 0; + CountMax = 0; + stmm_foreach_item( s_pManRwrExp5->tTableNN, gen, (char **)&uTruth, (char **)&Counter ) + { + nCuts += Counter; + if ( CountMax < Counter ) + CountMax = Counter; + } + printf( "Number of cuts considered = %8d.\n", nCuts ); + printf( "Classes occurring at least once = %8d.\n", stmm_count(s_pManRwrExp5->tTableNN) ); + printf( "The largest number of occurence = %8d.\n", CountMax ); + + // print the distribution of classes + pDistrib = ALLOC( int, CountMax + 1 ); + pReprs = ALLOC( unsigned, CountMax + 1 ); + memset( pDistrib, 0, sizeof(int)*(CountMax + 1) ); + stmm_foreach_item( s_pManRwrExp5->tTableNN, gen, (char **)&uTruth, (char **)&Counter ) + { + assert( Counter <= CountMax ); + pDistrib[ Counter ]++; + pReprs[ Counter ] = uTruth; + } + + for ( i = 1; i <= CountMax; i++ ) + if ( pDistrib[i] ) + { + printf( "Occurence = %6d. Num classes = %4d. Repr = ", i, pDistrib[i] ); + Extra_PrintBinary( stdout, pReprs + i, 32 ); + printf( "\n" ); + } + free( pDistrib ); + free( pReprs ); + + + // put them into an array + vClassesNN = Vec_IntAlloc( stmm_count(s_pManRwrExp5->tTableNN) ); + stmm_foreach_item( s_pManRwrExp5->tTableNN, gen, (char **)&uTruth, NULL ) + Vec_IntPush( vClassesNN, (int)uTruth ); + Vec_IntSortUnsigned( vClassesNN ); + + // write into a file all classes + pFile = fopen( "nnclass_stats5.txt", "w" ); + Vec_IntForEachEntry( vClassesNN, uTruth, i ) + { + if ( !stmm_lookup( s_pManRwrExp5->tTableNN, (char *)uTruth, (char **)&Counter ) ) + { + assert( 0 ); + } + Extra_PrintHex( pFile, uTruth, 5 ); + fprintf( pFile, " %10d\n", Counter ); + } + fclose( pFile ); + printf( "%d classes written into file \"%s\".\n", vClassesNN->nSize, "nnclass_stats5.txt" ); + + +clk = clock(); + // how many NPN classes exist? + Vec_IntForEachEntry( vClassesNN, uTruth, i ) + { + int * pCounter; + uTruthC = Extra_TruthCanonNPN( uTruth, 5 ); + if ( !stmm_find_or_add( s_pManRwrExp5->tTableNPN, (char *)uTruthC, (char***)&pCounter ) ) + *pCounter = 0; + if ( !stmm_lookup( s_pManRwrExp5->tTableNN, (char *)uTruth, (char **)&Counter ) ) + { + assert( 0 ); + } + (*pCounter) += Counter; + } + printf( "The numbe of NPN classes = %d.\n", stmm_count(s_pManRwrExp5->tTableNPN) ); +PRT( "Computing NPN classes", clock() - clk ); + + // put them into an array + vClassesNPN = Vec_IntAlloc( stmm_count(s_pManRwrExp5->tTableNPN) ); + stmm_foreach_item( s_pManRwrExp5->tTableNPN, gen, (char **)&uTruth, NULL ) + Vec_IntPush( vClassesNPN, (int)uTruth ); + Vec_IntSortUnsigned( vClassesNPN ); + + // write into a file all classes + pFile = fopen( "npnclass_stats5.txt", "w" ); + Vec_IntForEachEntry( vClassesNPN, uTruth, i ) + { + if ( !stmm_lookup( s_pManRwrExp5->tTableNPN, (char *)uTruth, (char **)&Counter ) ) + { + assert( 0 ); + } + Extra_PrintHex( pFile, uTruth, 5 ); + fprintf( pFile, " %10d\n", Counter ); + } + fclose( pFile ); + printf( "%d classes written into file \"%s\".\n", vClassesNPN->nSize, "npnclass_stats5.txt" ); + + + // can they be uniquely characterized? + +} + + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/rwr/rwrLib.c b/src/opt/rwr/rwrLib.c new file mode 100644 index 00000000..1cdf350e --- /dev/null +++ b/src/opt/rwr/rwrLib.c @@ -0,0 +1,362 @@ +/**CFile**************************************************************** + + FileName [rwrLib.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [DAG-aware AIG rewriting package.] + + Synopsis [] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: rwrLib.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "rwr.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static Rwr_Node_t * Rwr_ManTryNode( Rwr_Man_t * p, Rwr_Node_t * p0, Rwr_Node_t * p1, int fExor, int Level, int Volume ); +static void Rwr_MarkUsed_rec( Rwr_Man_t * p, Rwr_Node_t * pNode ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Precomputes the forest in the manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_ManPrecompute( Rwr_Man_t * p ) +{ + Rwr_Node_t * p0, * p1; + int i, k, Level, Volume; + int LevelOld = -1; + int nNodes; + + Vec_PtrForEachEntryStart( p->vForest, p0, i, 1 ) + Vec_PtrForEachEntryStart( p->vForest, p1, k, 1 ) + { + if ( LevelOld < (int)p0->Level ) + { + LevelOld = p0->Level; + printf( "Starting level %d (at %d nodes).\n", LevelOld+1, i ); + printf( "Considered = %5d M. Found = %8d. Classes = %6d. Trying %7d.\n", + p->nConsidered/1000000, p->vForest->nSize, p->nClasses, i ); + } + + if ( k == i ) + break; +// if ( p0->Level + p1->Level > 6 ) // hard +// break; + + if ( p0->Level + p1->Level > 5 ) // easy + break; + +// if ( p0->Level + p1->Level > 6 || (p0->Level == 3 && p1->Level == 3) ) +// break; + + // compute the level and volume of the new nodes + Level = 1 + ABC_MAX( p0->Level, p1->Level ); + Volume = 1 + Rwr_ManNodeVolume( p, p0, p1 ); + // try four different AND nodes + Rwr_ManTryNode( p, p0 , p1 , 0, Level, Volume ); + Rwr_ManTryNode( p, Rwr_Not(p0), p1 , 0, Level, Volume ); + Rwr_ManTryNode( p, p0 , Rwr_Not(p1), 0, Level, Volume ); + Rwr_ManTryNode( p, Rwr_Not(p0), Rwr_Not(p1), 0, Level, Volume ); + // try EXOR + Rwr_ManTryNode( p, p0 , p1 , 1, Level, Volume + 1 ); + // report the progress + if ( p->nConsidered % 50000000 == 0 ) + printf( "Considered = %5d M. Found = %8d. Classes = %6d. Trying %7d.\n", + p->nConsidered/1000000, p->vForest->nSize, p->nClasses, i ); + // quit after some time + if ( p->vForest->nSize == RWR_LIMIT + 5 ) + { + printf( "Considered = %5d M. Found = %8d. Classes = %6d. Trying %7d.\n", + p->nConsidered/1000000, p->vForest->nSize, p->nClasses, i ); + goto save; + } + } +save : + + // mark the relevant ones + Rwr_ManIncTravId( p ); + k = 5; + nNodes = 0; + Vec_PtrForEachEntryStart( p->vForest, p0, i, 5 ) + if ( p0->uTruth == p->puCanons[p0->uTruth] ) + { + Rwr_MarkUsed_rec( p, p0 ); + nNodes++; + } + + // compact the array by throwing away non-canonical + k = 5; + Vec_PtrForEachEntryStart( p->vForest, p0, i, 5 ) + if ( p0->fUsed ) + { + p->vForest->pArray[k] = p0; + p0->Id = k++; + } + p->vForest->nSize = k; + printf( "Total canonical = %4d. Total used = %5d.\n", nNodes, p->vForest->nSize ); +} + +/**Function************************************************************* + + Synopsis [Adds one node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Rwr_Node_t * Rwr_ManTryNode( Rwr_Man_t * p, Rwr_Node_t * p0, Rwr_Node_t * p1, int fExor, int Level, int Volume ) +{ + Rwr_Node_t * pOld, * pNew, ** ppPlace; + unsigned uTruth; + // compute truth table, level, volume + p->nConsidered++; + if ( fExor ) + { +// printf( "Considering EXOR of %d and %d.\n", p0->Id, p1->Id ); + uTruth = (p0->uTruth ^ p1->uTruth); + } + else + uTruth = (Rwr_IsComplement(p0)? ~Rwr_Regular(p0)->uTruth : Rwr_Regular(p0)->uTruth) & + (Rwr_IsComplement(p1)? ~Rwr_Regular(p1)->uTruth : Rwr_Regular(p1)->uTruth) & 0xFFFF; + // skip non-practical classes + if ( Level > 2 && !p->pPractical[p->puCanons[uTruth]] ) + return NULL; + // enumerate through the nodes with the same canonical form + ppPlace = p->pTable + uTruth; + for ( pOld = *ppPlace; pOld; ppPlace = &pOld->pNext, pOld = pOld->pNext ) + { + if ( pOld->Level < (unsigned)Level && pOld->Volume < (unsigned)Volume ) + return NULL; + if ( pOld->Level == (unsigned)Level && pOld->Volume < (unsigned)Volume ) + return NULL; +// if ( pOld->Level < (unsigned)Level && pOld->Volume == (unsigned)Volume ) +// return NULL; + } +/* + // enumerate through the nodes with the opposite polarity + for ( pOld = p->pTable[~uTruth & 0xFFFF]; pOld; pOld = pOld->pNext ) + { + if ( pOld->Level < (unsigned)Level && pOld->Volume < (unsigned)Volume ) + return NULL; + if ( pOld->Level == (unsigned)Level && pOld->Volume < (unsigned)Volume ) + return NULL; +// if ( pOld->Level < (unsigned)Level && pOld->Volume == (unsigned)Volume ) +// return NULL; + } +*/ + // count the classes + if ( p->pTable[uTruth] == NULL && p->puCanons[uTruth] == uTruth ) + p->nClasses++; + // create the new node + pNew = (Rwr_Node_t *)Extra_MmFixedEntryFetch( p->pMmNode ); + pNew->Id = p->vForest->nSize; + pNew->TravId = 0; + pNew->uTruth = uTruth; + pNew->Level = Level; + pNew->Volume = Volume; + pNew->fUsed = 0; + pNew->fExor = fExor; + pNew->p0 = p0; + pNew->p1 = p1; + pNew->pNext = NULL; + Vec_PtrPush( p->vForest, pNew ); + *ppPlace = pNew; + return pNew; +} + +/**Function************************************************************* + + Synopsis [Adds one node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Rwr_Node_t * Rwr_ManAddNode( Rwr_Man_t * p, Rwr_Node_t * p0, Rwr_Node_t * p1, int fExor, int Level, int Volume ) +{ + Rwr_Node_t * pNew; + unsigned uTruth; + // compute truth table, leve, volume + p->nConsidered++; + if ( fExor ) + uTruth = (p0->uTruth ^ p1->uTruth); + else + uTruth = (Rwr_IsComplement(p0)? ~Rwr_Regular(p0)->uTruth : Rwr_Regular(p0)->uTruth) & + (Rwr_IsComplement(p1)? ~Rwr_Regular(p1)->uTruth : Rwr_Regular(p1)->uTruth) & 0xFFFF; + // create the new node + pNew = (Rwr_Node_t *)Extra_MmFixedEntryFetch( p->pMmNode ); + pNew->Id = p->vForest->nSize; + pNew->TravId = 0; + pNew->uTruth = uTruth; + pNew->Level = Level; + pNew->Volume = Volume; + pNew->fUsed = 0; + pNew->fExor = fExor; + pNew->p0 = p0; + pNew->p1 = p1; + pNew->pNext = NULL; + Vec_PtrPush( p->vForest, pNew ); + // do not add if the node is not essential + if ( uTruth != p->puCanons[uTruth] ) + return pNew; + + // add to the list + p->nAdded++; + if ( p->pTable[uTruth] == NULL ) + p->nClasses++; + Rwr_ListAddToTail( p->pTable + uTruth, pNew ); + return pNew; +} + +/**Function************************************************************* + + Synopsis [Adds one node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Rwr_Node_t * Rwr_ManAddVar( Rwr_Man_t * p, unsigned uTruth, int fPrecompute ) +{ + Rwr_Node_t * pNew; + pNew = (Rwr_Node_t *)Extra_MmFixedEntryFetch( p->pMmNode ); + pNew->Id = p->vForest->nSize; + pNew->TravId = 0; + pNew->uTruth = uTruth; + pNew->Level = 0; + pNew->Volume = 0; + pNew->fUsed = 1; + pNew->fExor = 0; + pNew->p0 = NULL; + pNew->p1 = NULL; + pNew->pNext = NULL; + Vec_PtrPush( p->vForest, pNew ); + if ( fPrecompute ) + Rwr_ListAddToTail( p->pTable + uTruth, pNew ); + return pNew; +} + + + +/**Function************************************************************* + + Synopsis [Adds one node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_MarkUsed_rec( Rwr_Man_t * p, Rwr_Node_t * pNode ) +{ + if ( pNode->fUsed || pNode->TravId == p->nTravIds ) + return; + pNode->TravId = p->nTravIds; + pNode->fUsed = 1; + Rwr_MarkUsed_rec( p, Rwr_Regular(pNode->p0) ); + Rwr_MarkUsed_rec( p, Rwr_Regular(pNode->p1) ); +} + +/**Function************************************************************* + + Synopsis [Adds one node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_Trav_rec( Rwr_Man_t * p, Rwr_Node_t * pNode, int * pVolume ) +{ + if ( pNode->fUsed || pNode->TravId == p->nTravIds ) + return; + pNode->TravId = p->nTravIds; + (*pVolume)++; + if ( pNode->fExor ) + (*pVolume)++; + Rwr_Trav_rec( p, Rwr_Regular(pNode->p0), pVolume ); + Rwr_Trav_rec( p, Rwr_Regular(pNode->p1), pVolume ); +} + +/**Function************************************************************* + + Synopsis [Adds one node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Rwr_ManNodeVolume( Rwr_Man_t * p, Rwr_Node_t * p0, Rwr_Node_t * p1 ) +{ + int Volume = 0; + Rwr_ManIncTravId( p ); + Rwr_Trav_rec( p, p0, &Volume ); + Rwr_Trav_rec( p, p1, &Volume ); + return Volume; +} + +/**Function************************************************************* + + Synopsis [Adds one node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_ManIncTravId( Rwr_Man_t * p ) +{ + Rwr_Node_t * pNode; + int i; + if ( p->nTravIds++ < 0x8FFFFFFF ) + return; + Vec_PtrForEachEntry( p->vForest, pNode, i ) + pNode->TravId = 0; + p->nTravIds = 1; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/rwr/rwrMan.c b/src/opt/rwr/rwrMan.c new file mode 100644 index 00000000..87a080c7 --- /dev/null +++ b/src/opt/rwr/rwrMan.c @@ -0,0 +1,318 @@ +/**CFile**************************************************************** + + FileName [rwrMan.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [DAG-aware AIG rewriting package.] + + Synopsis [Rewriting manager.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: rwrMan.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "rwr.h" +#include "main.h" +#include "dec.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Starts rewriting manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Rwr_Man_t * Rwr_ManStart( bool fPrecompute ) +{ + Dec_Man_t * pManDec; + Rwr_Man_t * p; + int clk = clock(); +clk = clock(); + p = ALLOC( Rwr_Man_t, 1 ); + memset( p, 0, sizeof(Rwr_Man_t) ); + p->nFuncs = (1<<16); + pManDec = Abc_FrameReadManDec(); + p->puCanons = pManDec->puCanons; + p->pPhases = pManDec->pPhases; + p->pPerms = pManDec->pPerms; + p->pMap = pManDec->pMap; + // initialize practical NPN classes + p->pPractical = Rwr_ManGetPractical( p ); + // create the table + p->pTable = ALLOC( Rwr_Node_t *, p->nFuncs ); + memset( p->pTable, 0, sizeof(Rwr_Node_t *) * p->nFuncs ); + // create the elementary nodes + p->pMmNode = Extra_MmFixedStart( sizeof(Rwr_Node_t) ); + p->vForest = Vec_PtrAlloc( 100 ); + Rwr_ManAddVar( p, 0x0000, fPrecompute ); // constant 0 + Rwr_ManAddVar( p, 0xAAAA, fPrecompute ); // var A + Rwr_ManAddVar( p, 0xCCCC, fPrecompute ); // var B + Rwr_ManAddVar( p, 0xF0F0, fPrecompute ); // var C + Rwr_ManAddVar( p, 0xFF00, fPrecompute ); // var D + p->nClasses = 5; + // other stuff + p->nTravIds = 1; + p->pPerms4 = Extra_Permutations( 4 ); + p->vLevNums = Vec_IntAlloc( 50 ); + p->vFanins = Vec_PtrAlloc( 50 ); + p->vFaninsCur = Vec_PtrAlloc( 50 ); + p->vNodesTemp = Vec_PtrAlloc( 50 ); + if ( fPrecompute ) + { // precompute subgraphs + Rwr_ManPrecompute( p ); +// Rwr_ManPrint( p ); + Rwr_ManWriteToArray( p ); + } + else + { // load saved subgraphs + Rwr_ManLoadFromArray( p, 0 ); +// Rwr_ManPrint( p ); + Rwr_ManPreprocess( p ); + } +p->timeStart = clock() - clk; + return p; +} + +/**Function************************************************************* + + Synopsis [Stops rewriting manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_ManStop( Rwr_Man_t * p ) +{ + if ( p->vClasses ) + { + Rwr_Node_t * pNode; + int i, k; + Vec_VecForEachEntry( p->vClasses, pNode, i, k ) + Dec_GraphFree( (Dec_Graph_t *)pNode->pNext ); + } + if ( p->vClasses ) Vec_VecFree( p->vClasses ); + Vec_PtrFree( p->vNodesTemp ); + Vec_PtrFree( p->vForest ); + Vec_IntFree( p->vLevNums ); + Vec_PtrFree( p->vFanins ); + Vec_PtrFree( p->vFaninsCur ); + Extra_MmFixedStop( p->pMmNode ); + FREE( p->pMapInv ); + free( p->pTable ); + free( p->pPractical ); + free( p->pPerms4 ); + free( p ); +} + +/**Function************************************************************* + + Synopsis [Stops the resynthesis manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_ManPrintStats( Rwr_Man_t * p ) +{ + int i, Counter = 0; + for ( i = 0; i < 222; i++ ) + Counter += (p->nScores[i] > 0); + + printf( "Rewriting statistics:\n" ); + printf( "Total cuts tries = %8d.\n", p->nCutsGood ); + printf( "Bad cuts found = %8d.\n", p->nCutsBad ); + printf( "Total subgraphs = %8d.\n", p->nSubgraphs ); + printf( "Used NPN classes = %8d.\n", Counter ); + printf( "Nodes considered = %8d.\n", p->nNodesConsidered ); + printf( "Nodes rewritten = %8d.\n", p->nNodesRewritten ); + printf( "Gain = %8d. (%6.2f %%).\n", p->nNodesBeg-p->nNodesEnd, 100.0*(p->nNodesBeg-p->nNodesEnd)/p->nNodesBeg ); + PRT( "Start ", p->timeStart ); + PRT( "Cuts ", p->timeCut ); + PRT( "Resynthesis ", p->timeRes ); + PRT( " Mffc ", p->timeMffc ); + PRT( " Eval ", p->timeEval ); + PRT( "Update ", p->timeUpdate ); + PRT( "TOTAL ", p->timeTotal ); + +/* + printf( "The scores are:\n" ); + for ( i = 0; i < 222; i++ ) + if ( p->nScores[i] > 0 ) + { + extern void Ivy_TruthDsdComputePrint( unsigned uTruth ); + printf( "%3d = %8d canon = %5d ", i, p->nScores[i], p->pMapInv[i] ); + Ivy_TruthDsdComputePrint( (unsigned)p->pMapInv[i] | ((unsigned)p->pMapInv[i] << 16) ); + } +*/ + printf( "\n" ); + +} + +/**Function************************************************************* + + Synopsis [Stops the resynthesis manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_ManPrintStatsFile( Rwr_Man_t * p ) +{ + FILE * pTable; + pTable = fopen( "stats.txt", "a+" ); + fprintf( pTable, "%d ", p->nCutsGood ); + fprintf( pTable, "%d ", p->nSubgraphs ); + fprintf( pTable, "%d ", p->nNodesRewritten ); + fprintf( pTable, "%d", p->nNodesGained ); + fprintf( pTable, "\n" ); + fclose( pTable ); +} + +/**Function************************************************************* + + Synopsis [Stops the resynthesis manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void * Rwr_ManReadDecs( Rwr_Man_t * p ) +{ + return p->pGraph; +} + +/**Function************************************************************* + + Synopsis [Stops the resynthesis manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Rwr_ManReadLeaves( Rwr_Man_t * p ) +{ + return p->vFanins; +} + +/**Function************************************************************* + + Synopsis [Stops the resynthesis manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Rwr_ManReadCompl( Rwr_Man_t * p ) +{ + return p->fCompl; +} + +/**Function************************************************************* + + Synopsis [Stops the resynthesis manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_ManAddTimeCuts( Rwr_Man_t * p, int Time ) +{ + p->timeCut += Time; +} + +/**Function************************************************************* + + Synopsis [Stops the resynthesis manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_ManAddTimeUpdate( Rwr_Man_t * p, int Time ) +{ + p->timeUpdate += Time; +} + +/**Function************************************************************* + + Synopsis [Stops the resynthesis manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_ManAddTimeTotal( Rwr_Man_t * p, int Time ) +{ + p->timeTotal += Time; +} + + +/**Function************************************************************* + + Synopsis [Precomputes AIG subgraphs.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_Precompute() +{ + Rwr_Man_t * p; + p = Rwr_ManStart( 1 ); + Rwr_ManStop( p ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/rwr/rwrPrint.c b/src/opt/rwr/rwrPrint.c new file mode 100644 index 00000000..82ad2a90 --- /dev/null +++ b/src/opt/rwr/rwrPrint.c @@ -0,0 +1,266 @@ +/**CFile**************************************************************** + + FileName [rwrCut.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [DAG-aware AIG rewriting package.] + + Synopsis [Cut computation.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: rwrCut.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "rwr.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Adds one node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_Trav2_rec( Rwr_Man_t * p, Rwr_Node_t * pNode, int * pVolume ) +{ + if ( pNode->fUsed || pNode->TravId == p->nTravIds ) + return; + pNode->TravId = p->nTravIds; + (*pVolume)++; + Rwr_Trav2_rec( p, Rwr_Regular(pNode->p0), pVolume ); + Rwr_Trav2_rec( p, Rwr_Regular(pNode->p1), pVolume ); +} + +/**Function************************************************************* + + Synopsis [Adds the node to the end of the list.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_GetBushVolume( Rwr_Man_t * p, int Entry, int * pVolume, int * pnFuncs ) +{ + Rwr_Node_t * pNode; + int Volume = 0; + int nFuncs = 0; + Rwr_ManIncTravId( p ); + for ( pNode = p->pTable[Entry]; pNode; pNode = pNode->pNext ) + { + if ( pNode->uTruth != p->puCanons[pNode->uTruth] ) + continue; + nFuncs++; + Rwr_Trav2_rec( p, pNode, &Volume ); + } + *pVolume = Volume; + *pnFuncs = nFuncs; +} + +/**Function************************************************************* + + Synopsis [Adds the node to the end of the list.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Rwr_GetBushSumOfVolumes( Rwr_Man_t * p, int Entry ) +{ + Rwr_Node_t * pNode; + int Volume, VolumeTotal = 0; + for ( pNode = p->pTable[Entry]; pNode; pNode = pNode->pNext ) + { + if ( pNode->uTruth != p->puCanons[pNode->uTruth] ) + continue; + Volume = 0; + Rwr_ManIncTravId( p ); + Rwr_Trav2_rec( p, pNode, &Volume ); + VolumeTotal += Volume; + } + return VolumeTotal; +} + +/**Function************************************************************* + + Synopsis [Prints one rwr node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_NodePrint_rec( FILE * pFile, Rwr_Node_t * pNode ) +{ + assert( !Rwr_IsComplement(pNode) ); + + if ( pNode->Id == 0 ) + { + fprintf( pFile, "Const1" ); + return; + } + + if ( pNode->Id < 5 ) + { + fprintf( pFile, "%c", 'a' + pNode->Id - 1 ); + return; + } + + if ( Rwr_IsComplement(pNode->p0) ) + { + if ( Rwr_Regular(pNode->p0)->Id < 5 ) + { + Rwr_NodePrint_rec( pFile, Rwr_Regular(pNode->p0) ); + fprintf( pFile, "\'" ); + } + else + { + fprintf( pFile, "(" ); + Rwr_NodePrint_rec( pFile, Rwr_Regular(pNode->p0) ); + fprintf( pFile, ")\'" ); + } + } + else + { + if ( Rwr_Regular(pNode->p0)->Id < 5 ) + { + Rwr_NodePrint_rec( pFile, Rwr_Regular(pNode->p0) ); + } + else + { + fprintf( pFile, "(" ); + Rwr_NodePrint_rec( pFile, Rwr_Regular(pNode->p0) ); + fprintf( pFile, ")" ); + } + } + + if ( pNode->fExor ) + fprintf( pFile, "+" ); + + if ( Rwr_IsComplement(pNode->p1) ) + { + if ( Rwr_Regular(pNode->p1)->Id < 5 ) + { + Rwr_NodePrint_rec( pFile, Rwr_Regular(pNode->p1) ); + fprintf( pFile, "\'" ); + } + else + { + fprintf( pFile, "(" ); + Rwr_NodePrint_rec( pFile, Rwr_Regular(pNode->p1) ); + fprintf( pFile, ")\'" ); + } + } + else + { + if ( Rwr_Regular(pNode->p1)->Id < 5 ) + { + Rwr_NodePrint_rec( pFile, Rwr_Regular(pNode->p1) ); + } + else + { + fprintf( pFile, "(" ); + Rwr_NodePrint_rec( pFile, Rwr_Regular(pNode->p1) ); + fprintf( pFile, ")" ); + } + } +} + +/**Function************************************************************* + + Synopsis [Prints one rwr node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_NodePrint( FILE * pFile, Rwr_Man_t * p, Rwr_Node_t * pNode ) +{ + unsigned uTruth; + fprintf( pFile, "%5d : ", pNode->Id ); + Extra_PrintHex( pFile, pNode->uTruth, 4 ); + fprintf( pFile, " tt=" ); + uTruth = pNode->uTruth; + Extra_PrintBinary( pFile, &uTruth, 16 ); +// fprintf( pFile, " cn=", pNode->Id ); +// uTruth = p->puCanons[pNode->uTruth]; +// Extra_PrintBinary( pFile, &uTruth, 16 ); + fprintf( pFile, " lev=%d", pNode->Level ); + fprintf( pFile, " vol=%d", pNode->Volume ); + fprintf( pFile, " " ); + Rwr_NodePrint_rec( pFile, pNode ); + fprintf( pFile, "\n" ); +} + +/**Function************************************************************* + + Synopsis [Prints one rwr node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_ManPrint( Rwr_Man_t * p ) +{ + FILE * pFile; + Rwr_Node_t * pNode; + unsigned uTruth; + int Limit, Counter, Volume, nFuncs, i; + pFile = fopen( "graph_lib.txt", "w" ); + Counter = 0; + Limit = (1 << 16); + for ( i = 0; i < Limit; i++ ) + { + if ( p->pTable[i] == NULL ) + continue; + if ( i != p->puCanons[i] ) + continue; + fprintf( pFile, "\nClass %3d. Func %6d. ", p->pMap[i], Counter++ ); + Rwr_GetBushVolume( p, i, &Volume, &nFuncs ); + fprintf( pFile, "Roots = %3d. Vol = %3d. Sum = %3d. ", nFuncs, Volume, Rwr_GetBushSumOfVolumes(p, i) ); + uTruth = i; + Extra_PrintBinary( pFile, &uTruth, 16 ); + fprintf( pFile, "\n" ); + for ( pNode = p->pTable[i]; pNode; pNode = pNode->pNext ) + if ( pNode->uTruth == p->puCanons[pNode->uTruth] ) + Rwr_NodePrint( pFile, p, pNode ); + } + fclose( pFile ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/rwr/rwrTemp.c b/src/opt/rwr/rwrTemp.c new file mode 100644 index 00000000..3ffbd408 --- /dev/null +++ b/src/opt/rwr/rwrTemp.c @@ -0,0 +1,121 @@ +/**CFile**************************************************************** + + FileName [rwrCut.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [DAG-aware AIG rewriting package.] + + Synopsis [Cut computation.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: rwrCut.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "rwr.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static int pTruths[13719]; +static int pFreqs[13719]; +static int pPerm[13719]; + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Rwr_TempCompare( int * pNum1, int * pNum2 ) +{ + int Freq1 = pFreqs[*pNum1]; + int Freq2 = pFreqs[*pNum2]; + if ( Freq1 < Freq2 ) + return 1; + if ( Freq1 > Freq2 ) + return -1; + return 0; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_Temp() +{ + char Buffer[32]; + int nFuncs = 13719; + int nEntries = 100; + unsigned uTruth; + int i, k; + FILE * pFile; + + pFile = fopen( "nnclass_stats5.txt", "r" ); + for ( i = 0; i < 13719; i++ ) + { + fscanf( pFile, "%s%d", Buffer, &pFreqs[i] ); + Extra_ReadHexadecimal( &uTruth, Buffer+2, 5 ); + pTruths[i] = uTruth; + } + fclose( pFile ); + + for ( i = 0; i < 13719; i++ ) + pPerm[i] = i; + + qsort( (void *)pPerm, 13719, sizeof(int), + (int (*)(const void *, const void *)) Rwr_TempCompare ); + + + pFile = fopen( "5npn_100.blif", "w" ); + fprintf( pFile, "# Most frequent NPN classes of 5 vars.\n" ); + fprintf( pFile, ".model 5npn\n" ); + fprintf( pFile, ".inputs a b c d e\n" ); + fprintf( pFile, ".outputs" ); + for ( i = 0; i < nEntries; i++ ) + fprintf( pFile, " %02d", i ); + fprintf( pFile, "\n" ); + + for ( i = 0; i < nEntries; i++ ) + { + fprintf( pFile, ".names a b c d e %02d\n", i ); + uTruth = pTruths[pPerm[i]]; + for ( k = 0; k < 32; k++ ) + if ( uTruth & (1 << k) ) + { + Extra_PrintBinary( pFile, &k, 5 ); + fprintf( pFile, " 1\n" ); + } + } + fprintf( pFile, ".end\n" ); + fclose( pFile ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/rwr/rwrUtil.c b/src/opt/rwr/rwrUtil.c new file mode 100644 index 00000000..b2add2bf --- /dev/null +++ b/src/opt/rwr/rwrUtil.c @@ -0,0 +1,659 @@ +/**CFile**************************************************************** + + FileName [rwrUtil.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [DAG-aware AIG rewriting package.] + + Synopsis [Various utilities.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: rwrUtil.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "rwr.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +// precomputed data +#ifdef _WIN32 +unsigned short s_RwrPracticalClasses[]; +unsigned short s_RwtAigSubgraphs[]; +#else +static unsigned short s_RwrPracticalClasses[]; +static unsigned short s_RwtAigSubgraphs[]; +#endif + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Writes data.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_ManWriteToArray( Rwr_Man_t * p ) +{ + FILE * pFile; + Rwr_Node_t * pNode; + unsigned Entry0, Entry1; + int i, nEntries, clk = clock(); + // prepare the buffer + nEntries = p->vForest->nSize - 5; + pFile = fopen( "npn4_aig_array.txt", "w" ); + fprintf( pFile, "static unsigned short s_RwtAigSubgraphs[] = \n{" ); + for ( i = 0; i < nEntries; i++ ) + { + if ( i % 5 == 0 ) + fprintf( pFile, "\n " ); + pNode = p->vForest->pArray[i+5]; + Entry0 = (Rwr_Regular(pNode->p0)->Id << 1) | Rwr_IsComplement(pNode->p0); + Entry1 = (Rwr_Regular(pNode->p1)->Id << 1) | Rwr_IsComplement(pNode->p1); + Entry0 = (Entry0 << 1) | pNode->fExor; + Extra_PrintHex( pFile, Entry0, 4 ); + fprintf( pFile, "," ); + Extra_PrintHex( pFile, Entry1, 4 ); + fprintf( pFile, ", " ); + } + if ( i % 5 == 0 ) + fprintf( pFile, "\n " ); + Extra_PrintHex( pFile, 0, 4 ); + fprintf( pFile, "," ); + Extra_PrintHex( pFile, 0, 4 ); + fprintf( pFile, " \n};\n" ); + fclose( pFile ); + printf( "The number of nodes saved = %d. ", nEntries ); PRT( "Saving", clock() - clk ); +} + +/**Function************************************************************* + + Synopsis [Loads data.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_ManLoadFromArray( Rwr_Man_t * p, int fVerbose ) +{ + unsigned short * pArray = s_RwtAigSubgraphs; + Rwr_Node_t * p0, * p1; + unsigned Entry0, Entry1; + int Level, Volume, nEntries, fExor; + int i, clk = clock(); + + // reconstruct the forest + for ( i = 0; ; i++ ) + { + Entry0 = pArray[2*i + 0]; + Entry1 = pArray[2*i + 1]; + if ( Entry0 == 0 && Entry1 == 0 ) + break; + // get EXOR flag + fExor = (Entry0 & 1); + Entry0 >>= 1; + // get the nodes + p0 = p->vForest->pArray[Entry0 >> 1]; + p1 = p->vForest->pArray[Entry1 >> 1]; + // compute the level and volume of the new nodes + Level = 1 + ABC_MAX( p0->Level, p1->Level ); + Volume = 1 + Rwr_ManNodeVolume( p, p0, p1 ); + // set the complemented attributes + p0 = Rwr_NotCond( p0, (Entry0 & 1) ); + p1 = Rwr_NotCond( p1, (Entry1 & 1) ); + // add the node +// Rwr_ManTryNode( p, p0, p1, Level, Volume ); + Rwr_ManAddNode( p, p0, p1, fExor, Level, Volume + fExor ); + } + nEntries = i - 1; + if ( fVerbose ) + { + printf( "The number of classes = %d. Canonical nodes = %d.\n", p->nClasses, p->nAdded ); + printf( "The number of nodes loaded = %d. ", nEntries ); PRT( "Loading", clock() - clk ); + } +} + + +/**Function************************************************************* + + Synopsis [Writes.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_ManWriteToFile( Rwr_Man_t * p, char * pFileName ) +{ + FILE * pFile; + Rwr_Node_t * pNode; + unsigned * pBuffer; + int i, nEntries, clk = clock(); + // prepare the buffer + nEntries = p->vForest->nSize - 5; + pBuffer = ALLOC( unsigned, nEntries * 2 ); + for ( i = 0; i < nEntries; i++ ) + { + pNode = p->vForest->pArray[i+5]; + pBuffer[2*i + 0] = (Rwr_Regular(pNode->p0)->Id << 1) | Rwr_IsComplement(pNode->p0); + pBuffer[2*i + 1] = (Rwr_Regular(pNode->p1)->Id << 1) | Rwr_IsComplement(pNode->p1); + // save EXOR flag + pBuffer[2*i + 0] = (pBuffer[2*i + 0] << 1) | pNode->fExor; + + } + pFile = fopen( pFileName, "wb" ); + fwrite( &nEntries, sizeof(int), 1, pFile ); + fwrite( pBuffer, sizeof(unsigned), nEntries * 2, pFile ); + free( pBuffer ); + fclose( pFile ); + printf( "The number of nodes saved = %d. ", nEntries ); PRT( "Saving", clock() - clk ); +} + +/**Function************************************************************* + + Synopsis [Loads data.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_ManLoadFromFile( Rwr_Man_t * p, char * pFileName ) +{ + FILE * pFile; + Rwr_Node_t * p0, * p1; + unsigned * pBuffer; + int Level, Volume, nEntries, fExor; + int i, clk = clock(); + + // load the data + pFile = fopen( pFileName, "rb" ); + if ( pFile == NULL ) + { + printf( "Rwr_ManLoadFromFile: Cannot open file \"%s\".\n", pFileName ); + return; + } + fread( &nEntries, sizeof(int), 1, pFile ); + pBuffer = ALLOC( unsigned, nEntries * 2 ); + fread( pBuffer, sizeof(unsigned), nEntries * 2, pFile ); + fclose( pFile ); + // reconstruct the forest + for ( i = 0; i < nEntries; i++ ) + { + // get EXOR flag + fExor = (pBuffer[2*i + 0] & 1); + pBuffer[2*i + 0] = (pBuffer[2*i + 0] >> 1); + // get the nodes + p0 = p->vForest->pArray[pBuffer[2*i + 0] >> 1]; + p1 = p->vForest->pArray[pBuffer[2*i + 1] >> 1]; + // compute the level and volume of the new nodes + Level = 1 + ABC_MAX( p0->Level, p1->Level ); + Volume = 1 + Rwr_ManNodeVolume( p, p0, p1 ); + // set the complemented attributes + p0 = Rwr_NotCond( p0, (pBuffer[2*i + 0] & 1) ); + p1 = Rwr_NotCond( p1, (pBuffer[2*i + 1] & 1) ); + // add the node +// Rwr_ManTryNode( p, p0, p1, Level, Volume ); + Rwr_ManAddNode( p, p0, p1, fExor, Level, Volume + fExor ); + } + free( pBuffer ); + printf( "The number of classes = %d. Canonical nodes = %d.\n", p->nClasses, p->nAdded ); + printf( "The number of nodes loaded = %d. ", nEntries ); PRT( "Loading", clock() - clk ); +} + + +/**Function************************************************************* + + Synopsis [Adds the node to the end of the list.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Rwr_ListAddToTail( Rwr_Node_t ** ppList, Rwr_Node_t * pNode ) +{ + Rwr_Node_t * pTemp; + // find the last one + for ( pTemp = *ppList; pTemp; pTemp = pTemp->pNext ) + ppList = &pTemp->pNext; + // attach at the end + *ppList = pNode; +} + +/**Function************************************************************* + + Synopsis [Create practical classes.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +char * Rwr_ManGetPractical( Rwr_Man_t * p ) +{ + char * pPractical; + int i; + pPractical = ALLOC( char, p->nFuncs ); + memset( pPractical, 0, sizeof(char) * p->nFuncs ); + pPractical[0] = 1; + for ( i = 1; ; i++ ) + { + if ( s_RwrPracticalClasses[i] == 0 ) + break; + pPractical[ s_RwrPracticalClasses[i] ] = 1; + } + return pPractical; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + +// the following 135 practical NPN classes of 4-variable functions were computed +// by considering all 4-input cuts appearing in IWLS, MCNC, and ISCAS benchmarks +static unsigned short s_RwrPracticalClasses[] = +{ + 0x0000, 0x0001, 0x0003, 0x0006, 0x0007, 0x000f, 0x0016, 0x0017, 0x0018, 0x0019, 0x001b, + 0x001e, 0x001f, 0x003c, 0x003d, 0x003f, 0x0069, 0x006b, 0x006f, 0x007e, 0x007f, 0x00ff, + 0x0116, 0x0118, 0x0119, 0x011a, 0x011b, 0x011e, 0x011f, 0x012c, 0x012d, 0x012f, 0x013c, + 0x013d, 0x013e, 0x013f, 0x0168, 0x0169, 0x016f, 0x017f, 0x0180, 0x0181, 0x0182, 0x0183, + 0x0186, 0x0189, 0x018b, 0x018f, 0x0198, 0x0199, 0x019b, 0x01a8, 0x01a9, 0x01aa, 0x01ab, + 0x01ac, 0x01ad, 0x01ae, 0x01af, 0x01bf, 0x01e9, 0x01ea, 0x01eb, 0x01ee, 0x01ef, 0x01fe, + 0x033c, 0x033d, 0x033f, 0x0356, 0x0357, 0x0358, 0x0359, 0x035a, 0x035b, 0x035f, 0x0368, + 0x0369, 0x036c, 0x036e, 0x037d, 0x03c0, 0x03c1, 0x03c3, 0x03c7, 0x03cf, 0x03d4, 0x03d5, + 0x03d7, 0x03d8, 0x03d9, 0x03dc, 0x03dd, 0x03de, 0x03fc, 0x0660, 0x0661, 0x0666, 0x0669, + 0x066f, 0x0676, 0x067e, 0x0690, 0x0696, 0x0697, 0x069f, 0x06b1, 0x06b6, 0x06f0, 0x06f2, + 0x06f6, 0x06f9, 0x0776, 0x0778, 0x07b0, 0x07b1, 0x07b4, 0x07bc, 0x07f0, 0x07f2, 0x07f8, + 0x0ff0, 0x1683, 0x1696, 0x1698, 0x169e, 0x16e9, 0x178e, 0x17e8, 0x18e7, 0x19e6, 0x1be4, + 0x1ee1, 0x3cc3, 0x6996, 0x0000 +}; + +static unsigned short s_RwtAigSubgraphs[] = +{ + 0x0008,0x0002, 0x000a,0x0002, 0x0008,0x0003, 0x000a,0x0003, 0x0009,0x0002, + 0x000c,0x0002, 0x000e,0x0002, 0x000c,0x0003, 0x000e,0x0003, 0x000d,0x0002, + 0x000c,0x0004, 0x000e,0x0004, 0x000c,0x0005, 0x000e,0x0005, 0x000d,0x0004, + 0x0010,0x0002, 0x0012,0x0002, 0x0010,0x0003, 0x0012,0x0003, 0x0011,0x0002, + 0x0010,0x0004, 0x0012,0x0004, 0x0010,0x0005, 0x0012,0x0005, 0x0011,0x0004, + 0x0010,0x0006, 0x0012,0x0006, 0x0010,0x0007, 0x0012,0x0007, 0x0011,0x0006, + 0x0016,0x0005, 0x0014,0x0006, 0x0016,0x0006, 0x0014,0x0007, 0x0016,0x0007, + 0x0015,0x0006, 0x0014,0x0008, 0x0016,0x0008, 0x0014,0x0009, 0x0016,0x0009, + 0x0015,0x0008, 0x0018,0x0006, 0x001a,0x0006, 0x0018,0x0007, 0x001a,0x0007, + 0x0019,0x0006, 0x0018,0x0009, 0x001a,0x0009, 0x0019,0x0008, 0x001e,0x0005, + 0x001c,0x0006, 0x001e,0x0006, 0x001c,0x0007, 0x001e,0x0007, 0x001d,0x0006, + 0x001c,0x0008, 0x001e,0x0008, 0x001c,0x0009, 0x001e,0x0009, 0x001d,0x0008, + 0x0020,0x0006, 0x0022,0x0006, 0x0020,0x0007, 0x0022,0x0007, 0x0021,0x0006, + 0x0020,0x0008, 0x0022,0x0008, 0x0020,0x0009, 0x0022,0x0009, 0x0021,0x0008, + 0x0024,0x0006, 0x0026,0x0006, 0x0024,0x0007, 0x0026,0x0007, 0x0025,0x0006, + 0x0026,0x0008, 0x0024,0x0009, 0x0026,0x0009, 0x0025,0x0008, 0x0028,0x0004, + 0x002a,0x0004, 0x0028,0x0005, 0x002a,0x0007, 0x0028,0x0008, 0x002a,0x0009, + 0x0029,0x0008, 0x002a,0x000b, 0x0029,0x000a, 0x002a,0x000f, 0x0029,0x000e, + 0x002a,0x0011, 0x002a,0x0013, 0x002c,0x0004, 0x002e,0x0004, 0x002c,0x0005, + 0x002c,0x0009, 0x002e,0x0009, 0x002d,0x0008, 0x002d,0x000c, 0x002e,0x000f, + 0x002e,0x0011, 0x002e,0x0012, 0x0030,0x0004, 0x0032,0x0007, 0x0032,0x0009, + 0x0031,0x0008, 0x0032,0x000b, 0x0032,0x000d, 0x0032,0x000f, 0x0031,0x000e, + 0x0032,0x0013, 0x0034,0x0004, 0x0036,0x0004, 0x0034,0x0005, 0x0036,0x0005, + 0x0035,0x0004, 0x0036,0x0008, 0x0034,0x0009, 0x0036,0x0009, 0x0035,0x0008, + 0x0036,0x000b, 0x0036,0x000d, 0x0036,0x0011, 0x0035,0x0010, 0x0036,0x0013, + 0x0038,0x0004, 0x0039,0x0004, 0x0038,0x0009, 0x003a,0x0009, 0x0039,0x0008, + 0x0038,0x000b, 0x003a,0x000b, 0x003a,0x000d, 0x003a,0x0011, 0x003a,0x0012, + 0x0038,0x0013, 0x003a,0x0013, 0x003c,0x0002, 0x003e,0x0002, 0x003c,0x0003, + 0x003e,0x0005, 0x003e,0x0007, 0x003c,0x0008, 0x003e,0x0008, 0x003c,0x0009, + 0x003e,0x0009, 0x003d,0x0008, 0x003e,0x000d, 0x003e,0x0011, 0x003e,0x0013, + 0x003e,0x0017, 0x003e,0x001b, 0x003e,0x001d, 0x0040,0x0002, 0x0042,0x0002, + 0x0042,0x0005, 0x0041,0x0006, 0x0042,0x0008, 0x0041,0x0008, 0x0042,0x000d, + 0x0042,0x0011, 0x0042,0x0015, 0x0042,0x0019, 0x0042,0x001b, 0x0042,0x001c, + 0x0041,0x001c, 0x0044,0x0002, 0x0046,0x0003, 0x0045,0x0004, 0x0046,0x0007, + 0x0045,0x0008, 0x0046,0x000b, 0x0046,0x000f, 0x0046,0x0013, 0x0045,0x0012, + 0x0046,0x0017, 0x0046,0x001b, 0x0046,0x0021, 0x0048,0x0002, 0x004a,0x0002, + 0x0048,0x0003, 0x004a,0x0003, 0x0049,0x0002, 0x0048,0x0008, 0x004a,0x0008, + 0x0048,0x0009, 0x004a,0x0009, 0x0049,0x0008, 0x004a,0x000b, 0x004a,0x000f, + 0x004a,0x0011, 0x004a,0x0012, 0x004a,0x0013, 0x004a,0x0015, 0x004a,0x0019, + 0x004a,0x001b, 0x004a,0x001d, 0x004c,0x0002, 0x004c,0x0003, 0x004d,0x0002, + 0x004c,0x0008, 0x004e,0x0008, 0x004c,0x0009, 0x004e,0x0009, 0x004d,0x0008, + 0x004c,0x000b, 0x004e,0x000b, 0x004c,0x000f, 0x004e,0x000f, 0x004e,0x0011, + 0x004c,0x0012, 0x004c,0x0013, 0x004e,0x0013, 0x004e,0x0015, 0x004c,0x0017, + 0x004e,0x0019, 0x004c,0x001b, 0x004e,0x001b, 0x004c,0x001c, 0x004c,0x001d, + 0x004e,0x001d, 0x0050,0x0004, 0x0052,0x0004, 0x0050,0x0006, 0x0052,0x0009, + 0x0052,0x000d, 0x0052,0x000f, 0x0052,0x0013, 0x0052,0x0017, 0x0052,0x0019, + 0x0052,0x001d, 0x0052,0x001f, 0x0052,0x0021, 0x0052,0x0023, 0x0052,0x0024, + 0x0052,0x0025, 0x0051,0x0024, 0x0052,0x0027, 0x0054,0x0004, 0x0056,0x0004, + 0x0054,0x0005, 0x0056,0x0006, 0x0054,0x0007, 0x0056,0x0011, 0x0056,0x001b, + 0x0056,0x001e, 0x0054,0x001f, 0x0056,0x001f, 0x0056,0x0020, 0x0054,0x0021, + 0x0055,0x0020, 0x0056,0x0024, 0x0054,0x0025, 0x0056,0x0025, 0x0055,0x0024, + 0x0054,0x0027, 0x0056,0x0027, 0x0055,0x0026, 0x005a,0x0007, 0x005a,0x0009, + 0x005a,0x000b, 0x005a,0x0015, 0x005a,0x001f, 0x0059,0x0020, 0x0058,0x0024, + 0x005a,0x0024, 0x005a,0x0027, 0x0059,0x0026, 0x005c,0x0004, 0x005e,0x0004, + 0x005c,0x0005, 0x005e,0x0006, 0x005c,0x0007, 0x005d,0x0006, 0x005e,0x000d, + 0x005e,0x0013, 0x005e,0x0017, 0x005c,0x001f, 0x005d,0x001e, 0x005e,0x0020, + 0x005e,0x0021, 0x005e,0x0022, 0x005e,0x0023, 0x005c,0x0024, 0x005e,0x0024, + 0x005c,0x0025, 0x005e,0x0025, 0x005d,0x0024, 0x005e,0x0026, 0x005e,0x0027, + 0x0062,0x0004, 0x0061,0x0004, 0x0062,0x0006, 0x0061,0x0006, 0x0060,0x000f, + 0x0060,0x0013, 0x0062,0x0013, 0x0060,0x0019, 0x0062,0x001c, 0x0060,0x001d, + 0x0062,0x001d, 0x0062,0x001f, 0x0060,0x0021, 0x0060,0x0023, 0x0062,0x0024, + 0x0060,0x0027, 0x0061,0x0026, 0x0064,0x0002, 0x0066,0x0002, 0x0064,0x0006, + 0x0066,0x0007, 0x0066,0x0009, 0x0066,0x000d, 0x0066,0x0013, 0x0066,0x0015, + 0x0066,0x0017, 0x0066,0x0019, 0x0066,0x001a, 0x0065,0x001a, 0x0066,0x001f, + 0x0066,0x0023, 0x0066,0x0027, 0x0066,0x002f, 0x0066,0x0030, 0x006a,0x0002, + 0x0068,0x0003, 0x0068,0x0006, 0x006a,0x0006, 0x006a,0x0011, 0x0068,0x0016, + 0x0068,0x0017, 0x006a,0x0017, 0x006a,0x001a, 0x006a,0x001b, 0x006a,0x0025, + 0x006a,0x002d, 0x006e,0x0003, 0x006e,0x0007, 0x006e,0x0009, 0x006e,0x000b, + 0x006e,0x0015, 0x006e,0x0016, 0x006e,0x0017, 0x006c,0x001a, 0x006e,0x001a, + 0x006e,0x001f, 0x006e,0x002b, 0x006e,0x0035, 0x0070,0x0002, 0x0070,0x0003, + 0x0072,0x0006, 0x0070,0x0007, 0x0071,0x0006, 0x0072,0x000b, 0x0072,0x000f, + 0x0072,0x0013, 0x0070,0x0015, 0x0071,0x0014, 0x0072,0x0017, 0x0072,0x0018, + 0x0070,0x0019, 0x0072,0x0019, 0x0070,0x001a, 0x0070,0x001b, 0x0072,0x001b, + 0x0071,0x001a, 0x0072,0x0021, 0x0072,0x0029, 0x0076,0x0002, 0x0076,0x0003, + 0x0075,0x0002, 0x0076,0x0006, 0x0074,0x0007, 0x0076,0x0007, 0x0075,0x0006, + 0x0076,0x000d, 0x0076,0x0011, 0x0076,0x0013, 0x0075,0x0014, 0x0076,0x0019, + 0x0076,0x001a, 0x0076,0x001b, 0x0075,0x001c, 0x0074,0x0023, 0x0075,0x0022, + 0x0074,0x0026, 0x0076,0x0026, 0x0074,0x0027, 0x0076,0x002b, 0x0076,0x002f, + 0x0078,0x0002, 0x0078,0x0004, 0x007a,0x0004, 0x007a,0x0005, 0x0079,0x0004, + 0x007a,0x0009, 0x007a,0x000a, 0x007a,0x000b, 0x007a,0x000d, 0x007a,0x000f, + 0x007a,0x0010, 0x007a,0x0011, 0x007a,0x0012, 0x007a,0x0013, 0x007a,0x0017, + 0x007a,0x001b, 0x007a,0x0021, 0x007a,0x0027, 0x007a,0x002b, 0x007a,0x002f, + 0x007a,0x0030, 0x0079,0x0034, 0x007a,0x0039, 0x007a,0x003a, 0x007e,0x0002, + 0x007c,0x0004, 0x007e,0x0004, 0x007e,0x000c, 0x007c,0x000d, 0x007e,0x0011, + 0x007e,0x0013, 0x007e,0x001b, 0x007e,0x0025, 0x007e,0x002d, 0x007e,0x0037, + 0x0082,0x0003, 0x0082,0x0005, 0x0082,0x0009, 0x0082,0x000b, 0x0080,0x0010, + 0x0082,0x0010, 0x0082,0x0012, 0x0082,0x0015, 0x0082,0x001f, 0x0082,0x002b, + 0x0082,0x0035, 0x0082,0x0039, 0x0082,0x003f, 0x0084,0x0002, 0x0086,0x0002, + 0x0084,0x0003, 0x0086,0x0003, 0x0085,0x0002, 0x0086,0x0004, 0x0084,0x0005, + 0x0085,0x0004, 0x0086,0x000a, 0x0084,0x000b, 0x0085,0x000a, 0x0086,0x000d, + 0x0086,0x000e, 0x0086,0x000f, 0x0084,0x0010, 0x0084,0x0011, 0x0086,0x0011, + 0x0085,0x0010, 0x0084,0x0012, 0x0084,0x0013, 0x0086,0x0013, 0x0085,0x0012, + 0x0086,0x0019, 0x0086,0x0023, 0x0086,0x0029, 0x0086,0x0033, 0x0086,0x0039, + 0x008a,0x0003, 0x0089,0x0002, 0x0088,0x0004, 0x008a,0x0004, 0x0088,0x0005, + 0x0089,0x0004, 0x008a,0x000b, 0x008a,0x0010, 0x0088,0x0011, 0x008a,0x0011, + 0x0089,0x0010, 0x0088,0x0012, 0x008a,0x0012, 0x0089,0x0012, 0x008a,0x0017, + 0x008a,0x001b, 0x0089,0x0020, 0x008a,0x0025, 0x0088,0x0027, 0x008a,0x002b, + 0x008a,0x002f, 0x008a,0x0039, 0x0088,0x003a, 0x008d,0x0044, 0x0092,0x0009, + 0x0092,0x0025, 0x0092,0x0029, 0x0092,0x002d, 0x0092,0x0033, 0x0092,0x0037, + 0x0092,0x003d, 0x0092,0x0041, 0x0095,0x0002, 0x0095,0x0004, 0x0095,0x0010, + 0x0095,0x0012, 0x0096,0x0021, 0x0096,0x0029, 0x0095,0x002e, 0x0096,0x0030, + 0x0096,0x0033, 0x0096,0x003a, 0x0096,0x0043, 0x009a,0x0008, 0x009a,0x0009, + 0x0099,0x0008, 0x009a,0x0011, 0x009a,0x0023, 0x009a,0x0033, 0x009a,0x003d, + 0x009a,0x0044, 0x009a,0x0045, 0x0099,0x0044, 0x009d,0x0002, 0x009e,0x0008, + 0x009c,0x0009, 0x009e,0x0009, 0x009d,0x0008, 0x009e,0x0011, 0x009d,0x0010, + 0x009e,0x001f, 0x009e,0x003f, 0x00a0,0x0009, 0x00a0,0x0011, 0x00a2,0x0030, + 0x00a2,0x0033, 0x00a6,0x0006, 0x00a6,0x0007, 0x00a6,0x0011, 0x00a6,0x0044, + 0x00a6,0x004b, 0x00aa,0x0007, 0x00aa,0x0015, 0x00ae,0x0006, 0x00ae,0x0011, + 0x00ae,0x001b, 0x00ae,0x0025, 0x00ae,0x003d, 0x00ae,0x0041, 0x00ae,0x0043, + 0x00ae,0x0045, 0x00b2,0x0006, 0x00b0,0x0007, 0x00b1,0x0006, 0x00b2,0x0017, + 0x00b1,0x0016, 0x00b0,0x0019, 0x00b2,0x0021, 0x00b2,0x003d, 0x00b5,0x004a, + 0x00ba,0x0009, 0x00ba,0x000f, 0x00bc,0x0009, 0x00be,0x0009, 0x00be,0x000f, + 0x00bd,0x000e, 0x00be,0x0017, 0x00c2,0x0009, 0x00c2,0x0019, 0x00c2,0x001f, + 0x00c2,0x0033, 0x00c6,0x0009, 0x00c5,0x000e, 0x00c6,0x0015, 0x00c6,0x0023, + 0x00c4,0x002d, 0x00c6,0x002f, 0x00c5,0x002e, 0x00c6,0x0045, 0x00ce,0x0007, + 0x00ce,0x0021, 0x00ce,0x0023, 0x00ce,0x0025, 0x00ce,0x0027, 0x00ce,0x0033, + 0x00ce,0x003d, 0x00d2,0x0006, 0x00d0,0x0015, 0x00d0,0x001b, 0x00d2,0x001b, + 0x00d1,0x001a, 0x00d0,0x001f, 0x00d2,0x0025, 0x00d1,0x0024, 0x00d2,0x0037, + 0x00d2,0x0041, 0x00d2,0x0045, 0x00d9,0x0044, 0x00e1,0x0004, 0x00e2,0x000d, + 0x00e2,0x0021, 0x00e0,0x003a, 0x00e6,0x003d, 0x00e6,0x0061, 0x00e6,0x0067, + 0x00e9,0x0004, 0x00ea,0x0008, 0x00ea,0x0009, 0x00ea,0x0039, 0x00e9,0x0038, + 0x00ea,0x003f, 0x00ec,0x000d, 0x00ee,0x000d, 0x00ee,0x0037, 0x00f2,0x003d, + 0x00f2,0x0062, 0x00f5,0x0002, 0x00fa,0x0017, 0x00fa,0x003d, 0x00fe,0x0006, + 0x00fd,0x0006, 0x00fc,0x0015, 0x00fe,0x001b, 0x00fc,0x0025, 0x00fe,0x0025, + 0x00fd,0x0024, 0x00fe,0x0041, 0x00fe,0x004d, 0x00fd,0x004e, 0x0101,0x0014, + 0x0106,0x004d, 0x010a,0x0009, 0x010a,0x000b, 0x0109,0x000a, 0x010a,0x004f, + 0x010a,0x0058, 0x010e,0x0008, 0x010c,0x0009, 0x010e,0x0009, 0x010d,0x0008, + 0x010e,0x000b, 0x010e,0x002b, 0x010d,0x002a, 0x010e,0x0035, 0x010e,0x003d, + 0x010e,0x003f, 0x010e,0x0049, 0x010e,0x0057, 0x010d,0x0056, 0x010d,0x0058, + 0x0111,0x0004, 0x0111,0x0006, 0x0110,0x0009, 0x0112,0x0009, 0x0111,0x0008, + 0x0112,0x002f, 0x0110,0x0035, 0x0110,0x0037, 0x0112,0x0039, 0x0112,0x003d, + 0x0112,0x003f, 0x0112,0x0045, 0x0111,0x0044, 0x0112,0x004b, 0x0112,0x0059, + 0x0112,0x0069, 0x0112,0x007f, 0x0116,0x0009, 0x0115,0x0008, 0x0114,0x000b, + 0x0116,0x000b, 0x0116,0x0058, 0x011a,0x0015, 0x011a,0x001f, 0x011a,0x002b, + 0x011a,0x003f, 0x011a,0x0049, 0x011a,0x0085, 0x011e,0x0007, 0x011e,0x0019, + 0x011e,0x001b, 0x011e,0x0023, 0x011e,0x0027, 0x011e,0x002f, 0x011e,0x0043, + 0x011e,0x004b, 0x011e,0x004e, 0x011e,0x004f, 0x011e,0x005f, 0x011e,0x0061, + 0x011e,0x0065, 0x011e,0x0083, 0x0122,0x0006, 0x0120,0x0007, 0x0122,0x0007, + 0x0121,0x0006, 0x0122,0x0049, 0x0121,0x004e, 0x0122,0x008f, 0x0125,0x0004, + 0x0124,0x0007, 0x0125,0x0006, 0x0124,0x001b, 0x0126,0x001b, 0x0126,0x0045, + 0x0126,0x0087, 0x0128,0x0007, 0x0129,0x0006, 0x012a,0x0019, 0x012a,0x003d, + 0x012a,0x0051, 0x012a,0x0065, 0x012a,0x0083, 0x012d,0x005a, 0x0132,0x0009, + 0x0132,0x008f, 0x0134,0x0009, 0x0135,0x003e, 0x013a,0x003d, 0x013a,0x0044, + 0x0139,0x0044, 0x013e,0x0009, 0x013d,0x0008, 0x013c,0x003d, 0x013c,0x0044, + 0x013c,0x0053, 0x013e,0x008f, 0x013e,0x0095, 0x0142,0x0044, 0x0142,0x0097, + 0x0142,0x009e, 0x0144,0x0007, 0x0148,0x0015, 0x0148,0x001c, 0x0148,0x001f, + 0x0148,0x0026, 0x0149,0x0086, 0x014d,0x0006, 0x014e,0x0044, 0x014d,0x0048, + 0x014e,0x009e, 0x0152,0x0009, 0x0151,0x00a6, 0x0155,0x0030, 0x015d,0x003a, + 0x0162,0x009e, 0x0164,0x000f, 0x0164,0x0013, 0x0169,0x000e, 0x0174,0x0009, + 0x0179,0x0008, 0x0180,0x0009, 0x0181,0x0044, 0x0186,0x0044, 0x0185,0x0044, + 0x018a,0x0068, 0x0195,0x004e, 0x01a6,0x0009, 0x01a5,0x0008, 0x01b1,0x003a, + 0x01c4,0x0029, 0x01c4,0x0030, 0x01ca,0x008f, 0x01ca,0x0095, 0x01cc,0x0029, + 0x01cc,0x0033, 0x01ce,0x003d, 0x01d6,0x00b2, 0x01d8,0x0009, 0x01d9,0x002a, + 0x01d9,0x0056, 0x01d9,0x00a4, 0x01dd,0x003a, 0x01e2,0x00b2, 0x01e6,0x0013, + 0x01e6,0x009f, 0x01e6,0x00ba, 0x01e6,0x00c0, 0x01e6,0x00d3, 0x01e6,0x00d5, + 0x01e6,0x00e5, 0x01e8,0x0005, 0x01f2,0x0013, 0x01f2,0x0095, 0x01f2,0x009f, + 0x01f2,0x00ba, 0x01f2,0x00c0, 0x01f2,0x00d3, 0x0202,0x008f, 0x0202,0x0095, + 0x0202,0x00f3, 0x0202,0x00f9, 0x020a,0x0044, 0x0209,0x00b4, 0x020e,0x0009, + 0x020d,0x0008, 0x020c,0x003d, 0x020c,0x0044, 0x020c,0x0053, 0x020e,0x008f, + 0x020e,0x0095, 0x020c,0x00b1, 0x020e,0x00f3, 0x020e,0x00f9, 0x0210,0x0013, + 0x0211,0x0024, 0x0210,0x0026, 0x0219,0x0004, 0x021e,0x008f, 0x021e,0x0095, + 0x0221,0x003a, 0x0230,0x0009, 0x0236,0x0009, 0x0234,0x0029, 0x0234,0x0030, + 0x0234,0x0033, 0x0234,0x003a, 0x0234,0x003d, 0x0234,0x0044, 0x0235,0x00a6, + 0x023a,0x0009, 0x023d,0x003a, 0x0245,0x0044, 0x0249,0x003a, 0x024e,0x009e, + 0x024e,0x0106, 0x0251,0x0026, 0x0258,0x0013, 0x0259,0x0024, 0x0258,0x0061, + 0x0259,0x0086, 0x0258,0x00c7, 0x0258,0x00df, 0x0259,0x00ec, 0x0258,0x00fc, + 0x025d,0x0024, 0x025d,0x00de, 0x0260,0x00f6, 0x0268,0x0009, 0x0269,0x0044, + 0x0268,0x00f3, 0x0268,0x00f9, 0x026d,0x003a, 0x0270,0x0068, 0x0275,0x003a, + 0x027a,0x0044, 0x0279,0x0044, 0x027e,0x007e, 0x0281,0x0044, 0x0285,0x0008, + 0x028d,0x0006, 0x028d,0x00d2, 0x0295,0x00cc, 0x0296,0x00f6, 0x0295,0x00f8, + 0x0299,0x0030, 0x029e,0x007e, 0x029d,0x0080, 0x02a6,0x008f, 0x02a6,0x0095, + 0x02aa,0x0029, 0x02aa,0x0030, 0x02b5,0x0008, 0x02b9,0x003a, 0x02bd,0x0004, + 0x02bd,0x00fc, 0x02c2,0x00b2, 0x02c1,0x00b4, 0x02c4,0x0029, 0x02c8,0x0029, + 0x02c8,0x0033, 0x02ca,0x003d, 0x02ce,0x0029, 0x02ce,0x0030, 0x02d2,0x0068, + 0x02d1,0x006a, 0x02d5,0x006a, 0x02d9,0x0008, 0x02de,0x012c, 0x02e2,0x012c, + 0x02e4,0x0009, 0x02e5,0x002a, 0x02e5,0x0056, 0x02e5,0x012c, 0x02ea,0x0029, + 0x02ea,0x0030, 0x02e9,0x0030, 0x02ec,0x0029, 0x02ec,0x0030, 0x02ee,0x012c, + 0x02f1,0x0068, 0x02f1,0x00b2, 0x02f1,0x0108, 0x02f1,0x012c, 0x02f6,0x0013, + 0x02f6,0x0015, 0x02f6,0x001f, 0x02f6,0x0030, 0x02f6,0x0065, 0x02f6,0x0067, + 0x02f6,0x009f, 0x02f6,0x00b6, 0x02f6,0x00b9, 0x02f6,0x00c0, 0x02f6,0x00cf, + 0x02f6,0x0107, 0x02f6,0x010b, 0x02f6,0x010f, 0x02f6,0x0115, 0x02f6,0x012d, + 0x02f6,0x0134, 0x02f6,0x0153, 0x02f6,0x0171, 0x02f6,0x0176, 0x02f8,0x0003, + 0x02fa,0x017b, 0x02fc,0x00ba, 0x02fc,0x00d3, 0x0302,0x0013, 0x0302,0x001f, + 0x0302,0x0030, 0x0302,0x005d, 0x0302,0x0065, 0x0302,0x0067, 0x0302,0x0099, + 0x0302,0x009f, 0x0302,0x00ad, 0x0302,0x00b9, 0x0302,0x00c0, 0x0302,0x00cf, + 0x0301,0x00d2, 0x0301,0x00fe, 0x0302,0x0107, 0x0302,0x010b, 0x0302,0x010f, + 0x0302,0x0117, 0x0302,0x0134, 0x0302,0x0153, 0x0302,0x0157, 0x0302,0x0176, + 0x0306,0x0029, 0x0308,0x00b2, 0x0309,0x00dc, 0x030d,0x00f8, 0x0312,0x00f3, + 0x0318,0x007e, 0x031d,0x0080, 0x0321,0x0008, 0x0321,0x0094, 0x0326,0x017b, + 0x0326,0x0181, 0x0329,0x012e, 0x032a,0x017b, 0x032a,0x0181, 0x032e,0x008f, + 0x032e,0x0095, 0x032e,0x00f3, 0x032e,0x00f9, 0x0332,0x0009, 0x0331,0x0008, + 0x0330,0x003d, 0x0330,0x0044, 0x0330,0x0053, 0x0332,0x008f, 0x0332,0x0095, + 0x0330,0x00b1, 0x0332,0x00f3, 0x0332,0x00f9, 0x0330,0x0127, 0x0332,0x017b, + 0x0332,0x0181, 0x033c,0x0013, 0x033c,0x001c, 0x033d,0x0086, 0x033d,0x00ec, + 0x033d,0x0172, 0x033e,0x019d, 0x0345,0x0002, 0x0344,0x008f, 0x0344,0x00f3, + 0x034d,0x0030, 0x0352,0x0033, 0x0354,0x0029, 0x0354,0x0030, 0x035a,0x0009, + 0x035a,0x017b, 0x035a,0x019b, 0x035a,0x01a2, 0x035e,0x0181, 0x0360,0x0009, + 0x0366,0x0009, 0x0364,0x0029, 0x0364,0x0030, 0x0364,0x0033, 0x0364,0x003a, + 0x0364,0x003d, 0x0364,0x0044, 0x0369,0x0030, 0x0370,0x0029, 0x0370,0x0030, + 0x0376,0x0033, 0x037a,0x0009, 0x037a,0x019b, 0x037a,0x01a2, 0x037c,0x0009, + 0x0382,0x0181, 0x0386,0x0009, 0x0384,0x0029, 0x0384,0x0030, 0x0384,0x0033, + 0x0384,0x003a, 0x0384,0x003d, 0x0384,0x0044, 0x038a,0x0044, 0x038a,0x009e, + 0x038a,0x0106, 0x038a,0x0198, 0x038d,0x010e, 0x038d,0x0152, 0x038d,0x0158, + 0x0392,0x009e, 0x0392,0x0106, 0x0392,0x0198, 0x0395,0x0086, 0x0395,0x009a, + 0x0395,0x00ec, 0x0395,0x0172, 0x0398,0x014e, 0x0398,0x0175, 0x0398,0x018d, + 0x039c,0x0023, 0x039c,0x0027, 0x039c,0x00ef, 0x039c,0x0139, 0x039c,0x0168, + 0x03a0,0x0019, 0x03a0,0x001d, 0x03a0,0x0023, 0x03a0,0x0027, 0x03a1,0x004e, + 0x03a4,0x0162, 0x03a4,0x0183, 0x03a8,0x0013, 0x03a8,0x0027, 0x03a8,0x0133, + 0x03a8,0x0148, 0x03a8,0x0181, 0x03ac,0x0013, 0x03ac,0x0027, 0x03b0,0x017b, + 0x03b0,0x0181, 0x03b4,0x004b, 0x03b4,0x00e0, 0x03b4,0x00fb, 0x03b8,0x000f, + 0x03b8,0x0013, 0x03b8,0x00ab, 0x03b8,0x00bf, 0x03b8,0x00d0, 0x03bd,0x00da, + 0x03bd,0x012c, 0x03c8,0x000f, 0x03c8,0x0013, 0x03c8,0x0019, 0x03c8,0x001d, + 0x03cd,0x0086, 0x03cd,0x00ec, 0x03cd,0x0172, 0x03d2,0x00e0, 0x03d2,0x00ef, + 0x03d2,0x0112, 0x03d2,0x0139, 0x03d2,0x0168, 0x03d6,0x017b, 0x03d6,0x0181, + 0x03da,0x0133, 0x03da,0x0148, 0x03e2,0x0023, 0x03e2,0x0027, 0x03e6,0x0027, + 0x03e6,0x0181, 0x03ee,0x017b, 0x03ee,0x0181, 0x03fe,0x003d, 0x0401,0x012a, + 0x0401,0x019e, 0x0405,0x01a0, 0x040a,0x000d, 0x040a,0x011f, 0x040a,0x016f, + 0x040d,0x012a, 0x0412,0x017b, 0x041a,0x0033, 0x041a,0x003d, 0x041a,0x0181, + 0x0421,0x0086, 0x0421,0x009a, 0x0421,0x00ec, 0x0421,0x0172, 0x042e,0x0205, + 0x043a,0x0205, 0x043e,0x017b, 0x0442,0x01f5, 0x044c,0x0007, 0x0452,0x0033, + 0x0452,0x01ce, 0x0452,0x01d0, 0x0452,0x01f1, 0x0452,0x01fb, 0x0452,0x0225, + 0x0454,0x0005, 0x045a,0x0033, 0x045a,0x0181, 0x045a,0x01ce, 0x045a,0x01d0, + 0x045a,0x01f1, 0x0469,0x01de, 0x046e,0x0181, 0x047a,0x01ce, 0x047a,0x01f1, + 0x0485,0x012c, 0x0489,0x012c, 0x0490,0x01d8, 0x0496,0x0033, 0x0496,0x003d, + 0x0498,0x008f, 0x0498,0x00f3, 0x049e,0x0044, 0x049e,0x0221, 0x04a1,0x0006, + 0x04a2,0x0044, 0x04a6,0x0221, 0x04a9,0x0004, 0x04ac,0x0027, 0x04b1,0x009a, + 0x04b6,0x0097, 0x04b8,0x0027, 0x04c6,0x0219, 0x04ca,0x017b, 0x04cc,0x004b, + 0x04d0,0x00ab, 0x04d6,0x017b, 0x04d8,0x000f, 0x04d8,0x0019, 0x04d8,0x0033, + 0x04d8,0x003d, 0x04de,0x003d, 0x04de,0x0103, 0x04de,0x018b, 0x04de,0x0231, + 0x04e2,0x0044, 0x04e2,0x009e, 0x04e2,0x0106, 0x04e2,0x0198, 0x04e5,0x01a4, + 0x04e5,0x01b6, 0x04ea,0x009e, 0x04ea,0x0106, 0x04ea,0x0198, 0x04ed,0x002e, + 0x04ed,0x0038, 0x04ed,0x00a2, 0x04f1,0x0086, 0x04f1,0x009a, 0x04f1,0x00ec, + 0x04f1,0x0172, 0x04f9,0x004e, 0x04f8,0x0229, 0x04f8,0x022d, 0x0500,0x023e, + 0x0504,0x0217, 0x0510,0x00f3, 0x0514,0x0043, 0x0514,0x004d, 0x0514,0x00c3, + 0x0514,0x013d, 0x0514,0x0215, 0x0514,0x0232, 0x0515,0x0260, 0x0519,0x002a, + 0x0518,0x0030, 0x0518,0x0067, 0x0518,0x00c9, 0x0518,0x01eb, 0x0518,0x01ef, + 0x051c,0x0139, 0x051c,0x0168, 0x0520,0x0027, 0x0526,0x014e, 0x0526,0x0175, + 0x0526,0x018d, 0x052d,0x0200, 0x0532,0x0021, 0x0532,0x00bf, 0x0532,0x00d0, + 0x0532,0x0239, 0x0532,0x0266, 0x053d,0x0024, 0x053d,0x00da, 0x054a,0x000f, + 0x054a,0x00ab, 0x054a,0x023a, 0x054e,0x0043, 0x054e,0x004d, 0x054e,0x00c3, + 0x054e,0x013d, 0x054e,0x0215, 0x054e,0x0232, 0x054e,0x029d, 0x0552,0x014e, + 0x0552,0x018d, 0x0556,0x00f3, 0x0556,0x01e4, 0x055a,0x0299, 0x055d,0x0086, + 0x055d,0x009a, 0x055d,0x00ec, 0x055d,0x0172, 0x0566,0x01dc, 0x0566,0x02a5, + 0x056d,0x020a, 0x057a,0x003d, 0x057a,0x01d4, 0x057a,0x01f3, 0x0579,0x025e, + 0x057e,0x0139, 0x057e,0x0168, 0x0581,0x0006, 0x0586,0x017b, 0x0586,0x0181, + 0x0586,0x028c, 0x0588,0x0007, 0x058e,0x0033, 0x058e,0x008f, 0x058e,0x01d0, + 0x058e,0x027c, 0x0590,0x0003, 0x0596,0x0033, 0x0596,0x008f, 0x0596,0x0095, + 0x0596,0x01d0, 0x0596,0x027c, 0x05a2,0x026f, 0x05a5,0x0284, 0x05aa,0x017b, + 0x05ac,0x0205, 0x05b2,0x008f, 0x05b6,0x017b, 0x05b8,0x01da, 0x05c1,0x0276, + 0x05c6,0x0248, 0x05c8,0x0247, 0x05c8,0x027e, 0x05cc,0x003d, 0x05cc,0x01d4, + 0x05cc,0x01f3, 0x05d0,0x014e, 0x05d0,0x018d, 0x05da,0x00f9, 0x05dd,0x0006, + 0x05de,0x0044, 0x05e5,0x002e, 0x05e6,0x02f1, 0x05ea,0x01d4, 0x05ea,0x01f3, + 0x05ea,0x022d, 0x05ed,0x0002, 0x05f6,0x0027, 0x05fa,0x0097, 0x05fc,0x003d, + 0x0602,0x003d, 0x0606,0x00f3, 0x060a,0x0027, 0x060e,0x003d, 0x060e,0x0103, + 0x060e,0x018b, 0x060e,0x0231, 0x060e,0x02d1, 0x0611,0x01fc, 0x0611,0x0234, + 0x061a,0x0287, 0x061d,0x0214, 0x0621,0x01d4, 0x062a,0x0027, 0x062a,0x022d, + 0x062e,0x009e, 0x062e,0x0106, 0x062e,0x0198, 0x0632,0x009e, 0x0632,0x0106, + 0x0632,0x0198, 0x0639,0x0042, 0x0639,0x00b2, 0x0639,0x0108, 0x063d,0x01f8, + 0x0641,0x0086, 0x0641,0x009a, 0x0641,0x00ec, 0x0641,0x0172, 0x0645,0x0044, + 0x0649,0x0042, 0x0648,0x0087, 0x0648,0x00ed, 0x0648,0x0173, 0x0649,0x01a0, + 0x0648,0x0241, 0x0648,0x026f, 0x0648,0x02df, 0x0648,0x0307, 0x064c,0x023a, + 0x064c,0x02b3, 0x0651,0x0062, 0x0650,0x0217, 0x0651,0x02ac, 0x0650,0x02d6, + 0x0655,0x0042, 0x065d,0x0042, 0x0664,0x02b1, 0x0664,0x02ce, 0x0669,0x0238, + 0x066d,0x002a, 0x066c,0x0039, 0x066d,0x01f6, 0x066c,0x0213, 0x066c,0x022e, + 0x066d,0x02a2, 0x066c,0x02e1, 0x0671,0x002a, 0x0670,0x0030, 0x0670,0x0067, + 0x0670,0x00c9, 0x0670,0x01eb, 0x0670,0x01ef, 0x0670,0x02c3, 0x0675,0x0020, + 0x0678,0x0133, 0x0678,0x0148, 0x067c,0x0027, 0x0681,0x023a, 0x0684,0x0021, + 0x0684,0x00bf, 0x0684,0x00d0, 0x0689,0x01fc, 0x068e,0x0162, 0x068e,0x0183, + 0x0691,0x0200, 0x0696,0x0023, 0x0696,0x00e0, 0x0696,0x00fb, 0x0696,0x0268, + 0x069a,0x0282, 0x069d,0x007e, 0x06a2,0x004b, 0x06a2,0x023e, 0x06a2,0x02dc, + 0x06a6,0x0097, 0x06aa,0x02b1, 0x06aa,0x02ce, 0x06ae,0x0039, 0x06ae,0x0213, + 0x06ae,0x022e, 0x06ae,0x02e1, 0x06b2,0x0162, 0x06b2,0x0183, 0x06b6,0x0023, + 0x06b6,0x00e0, 0x06b6,0x00fb, 0x06ba,0x008f, 0x06ba,0x01e4, 0x06be,0x034b, + 0x06c1,0x0086, 0x06c1,0x009a, 0x06c1,0x00ec, 0x06c1,0x0172, 0x06c6,0x01da, + 0x06c6,0x0280, 0x06c6,0x0351, 0x06ce,0x008f, 0x06d2,0x01e3, 0x06d2,0x0287, + 0x06d2,0x0353, 0x06d6,0x027a, 0x06d6,0x029b, 0x06da,0x0033, 0x06da,0x01ce, + 0x06da,0x01f1, 0x06de,0x0133, 0x06de,0x0148, 0x06e2,0x0021, 0x06e2,0x00bf, + 0x06e2,0x00d0, 0x06e5,0x023a, 0x06e9,0x0004, 0x06ee,0x028c, 0x06ee,0x0338, + 0x06f2,0x0328, 0x06f2,0x0330, 0x06f4,0x0005, 0x06f9,0x01e0, 0x06fe,0x0328, + 0x06fe,0x0330, 0x0702,0x003d, 0x0702,0x00f3, 0x0702,0x0330, 0x0704,0x0003, + 0x070a,0x003d, 0x070a,0x00f3, 0x070a,0x01d4, 0x070a,0x01f3, 0x070a,0x0330, + 0x0711,0x032a, 0x0711,0x032e, 0x0716,0x003d, 0x0718,0x0205, 0x0718,0x0282, + 0x071e,0x00f3, 0x0720,0x01dc, 0x0720,0x02a5, 0x0726,0x0324, 0x072a,0x028a, + 0x072a,0x02a7, 0x0729,0x031c, 0x0729,0x032a, 0x072e,0x003d, 0x072e,0x00f9, + 0x072e,0x022d, 0x072e,0x0248, 0x072e,0x02e4, 0x0730,0x003d, 0x0730,0x0247, + 0x0730,0x02e3, 0x0730,0x0324, 0x0732,0x0324, 0x0739,0x032e, 0x073e,0x003d, + 0x0740,0x003d, 0x0744,0x027a, 0x0744,0x029b, 0x0748,0x0033, 0x0748,0x01ce, + 0x0748,0x01f1, 0x074c,0x0162, 0x074c,0x0183, 0x0750,0x0023, 0x0750,0x00e0, + 0x0750,0x00fb, 0x0755,0x0246, 0x075a,0x0095, 0x075a,0x0397, 0x075d,0x0004, + 0x076a,0x03b3, 0x076d,0x0002, 0x0772,0x02fb, 0x0772,0x0301, 0x0772,0x0315, + 0x0772,0x0397, 0x0776,0x008f, 0x077e,0x0027, 0x078a,0x00a1, 0x0792,0x009d, + 0x0792,0x00c3, 0x0792,0x02fb, 0x0792,0x0301, 0x0792,0x0315, 0x0792,0x03bd, + 0x0796,0x0027, 0x0796,0x024f, 0x079e,0x009d, 0x07a6,0x009d, 0x07a6,0x02fb, + 0x07a6,0x0301, 0x07a6,0x0315, 0x07a6,0x03bd, 0x07aa,0x0027, 0x07aa,0x024f, + 0x07ae,0x009d, 0x07b9,0x004e, 0x07b8,0x0087, 0x07b8,0x00ed, 0x07b8,0x0173, + 0x07b8,0x0197, 0x07b9,0x021a, 0x07b9,0x02b8, 0x07b9,0x0364, 0x07be,0x0029, + 0x07be,0x0030, 0x07c0,0x017b, 0x07c6,0x017b, 0x07c8,0x00f3, 0x07ce,0x00f3, + 0x07d0,0x008f, 0x07d6,0x008f, 0x07d9,0x01e8, 0x07dd,0x0292, 0x07e2,0x0053, + 0x07e6,0x008f, 0x07e6,0x00f3, 0x07e6,0x017b, 0x07e8,0x0029, 0x07e8,0x0030, + 0x07ec,0x0021, 0x07ec,0x02ad, 0x07f2,0x0181, 0x07f2,0x0315, 0x07f4,0x0021, + 0x07f8,0x020f, 0x07fd,0x002e, 0x0800,0x008f, 0x0805,0x0006, 0x0809,0x03c2, + 0x080d,0x0084, 0x0812,0x0009, 0x0811,0x0008, 0x0812,0x00f3, 0x0812,0x00f9, + 0x0812,0x017b, 0x0812,0x0181, 0x0814,0x0033, 0x0818,0x0023, 0x081c,0x0285, + 0x0826,0x03bd, 0x082c,0x008f, 0x082c,0x017b, 0x0832,0x0043, 0x0832,0x011b, + 0x0832,0x01b3, 0x0832,0x01c3, 0x0835,0x032a, 0x0838,0x0085, 0x0839,0x032a, + 0x083e,0x0049, 0x083d,0x0084, 0x083e,0x02fb, 0x083e,0x0301, 0x083e,0x0315, + 0x083e,0x0397, 0x0842,0x0009, 0x0841,0x0008, 0x0844,0x0009, 0x0846,0x008f, + 0x084a,0x0033, 0x084e,0x0285, 0x0851,0x009a, 0x0856,0x00a1, 0x0859,0x031c, + 0x085d,0x00b2, 0x0861,0x0012, 0x0861,0x02cc, 0x0865,0x0058, 0x0865,0x007e, + 0x0869,0x004a, 0x0871,0x0010, 0x0876,0x003d, 0x0879,0x032c, 0x087e,0x0089, + 0x0882,0x0229, 0x0882,0x022d, 0x0882,0x02c7, 0x0882,0x02cb, 0x0886,0x0021, + 0x0886,0x02ad, 0x0885,0x0356, 0x088a,0x0017, 0x088a,0x020f, 0x0889,0x0354, + 0x088d,0x009c, 0x0892,0x0089, 0x0895,0x0246, 0x089a,0x03bd, 0x089e,0x008f, + 0x089e,0x02f9, 0x089e,0x0313, 0x08a1,0x032a, 0x08a6,0x0053, 0x08a6,0x0095, + 0x08a6,0x0397, 0x08a8,0x017b, 0x08ad,0x031a, 0x08b2,0x017b, 0x08b4,0x00f3, + 0x08b5,0x02a0, 0x08b8,0x0089, 0x08c1,0x0024, 0x08c4,0x00f3, 0x08c9,0x007e, + 0x08cd,0x007c, 0x08cd,0x0222, 0x08cd,0x0294, 0x08d1,0x003a, 0x08d6,0x0009, + 0x08d9,0x003a, 0x08dc,0x001f, 0x08e0,0x008f, 0x08e0,0x017b, 0x08e4,0x0009, + 0x08e8,0x01ed, 0x08ed,0x031c, 0x08f2,0x003d, 0x08f6,0x008f, 0x08f6,0x017b, + 0x08fa,0x0009, 0x08fe,0x003d, 0x0902,0x01e9, 0x0904,0x01e9, 0x0904,0x0381, + 0x090a,0x03b1, 0x090d,0x031a, 0x0910,0x0299, 0x0914,0x034b, 0x0919,0x0008, + 0x091c,0x0033, 0x091c,0x003d, 0x0920,0x0027, 0x0924,0x0027, 0x0924,0x01fb, + 0x092a,0x01ce, 0x092a,0x01f1, 0x092d,0x031c, 0x0930,0x001f, 0x0936,0x00c5, + 0x0938,0x00c5, 0x0938,0x0381, 0x093c,0x001b, 0x0942,0x017d, 0x094a,0x0027, + 0x094e,0x0027, 0x094e,0x01fb, 0x0952,0x03b1, 0x095a,0x0029, 0x095a,0x0030, + 0x095d,0x0030, 0x0961,0x0030, 0x0966,0x02f9, 0x0966,0x0313, 0x0968,0x02eb, + 0x096d,0x0008, 0x0970,0x017b, 0x0974,0x0033, 0x0979,0x0150, 0x097d,0x009a, + 0x0982,0x0293, 0x0984,0x0293, 0x0984,0x0379, 0x098a,0x02eb, 0x098e,0x0009, + 0x0992,0x003d, 0x0996,0x003d, 0x0999,0x0062, 0x099e,0x003d, 0x09a0,0x0027, + 0x09a5,0x0144, 0x09a8,0x02b5, 0x09ae,0x008f, 0x09ae,0x009d, 0x09b2,0x004d, + 0x09b2,0x0053, 0x09b2,0x00c3, 0x09b2,0x013d, 0x09b2,0x01c5, 0x09b2,0x0271, + 0x09b4,0x0025, 0x09ba,0x0033, 0x09ba,0x0079, 0x09bc,0x0015, 0x09c2,0x013f, + 0x09c4,0x013f, 0x09c4,0x0379, 0x09ca,0x02b5, 0x09cd,0x0006, 0x09da,0x0009, + 0x09d9,0x0008, 0x09dc,0x000b, 0x09dc,0x004f, 0x09dd,0x0086, 0x09e0,0x0009, + 0x09e6,0x00a1, 0x09e8,0x0009, 0x09ed,0x0086, 0x09f2,0x001f, 0x09f2,0x002f, + 0x09f2,0x0049, 0x09f2,0x006f, 0x09f2,0x0085, 0x09f2,0x0091, 0x09f2,0x00a9, + 0x09f2,0x00d3, 0x09f2,0x00d7, 0x09f2,0x011d, 0x09f2,0x0121, 0x09f2,0x0235, + 0x09f2,0x0393, 0x09f6,0x0324, 0x09f8,0x0049, 0x09f8,0x00a9, 0x09f8,0x011d, + 0x09fe,0x001f, 0x09fe,0x0029, 0x09fe,0x0033, 0x09fe,0x003d, 0x09fe,0x0085, + 0x09fe,0x008f, 0x09fe,0x00d3, 0x0a00,0x003d, 0x0a06,0x012d, 0x0a0e,0x00b3, + 0x0a10,0x000b, 0x0a10,0x0387, 0x0a16,0x0059, 0x0a18,0x0009, 0x0a1e,0x0043, + 0x0a24,0x0085, 0x0a2a,0x0009, 0x0a2d,0x0008, 0x0a32,0x028a, 0x0a32,0x02a7, + 0x0a31,0x031c, 0x0a35,0x032e, 0x0a39,0x0006, 0x0a3a,0x0105, 0x0a3a,0x024f, + 0x0a3c,0x0299, 0x0a42,0x01ed, 0x0a46,0x0299, 0x0a48,0x01ed, 0x0a4c,0x0059, + 0x0a52,0x000b, 0x0a52,0x0387, 0x0a56,0x000b, 0x0a5e,0x0009, 0x0a60,0x003d, + 0x0a66,0x0105, 0x0a6a,0x0195, 0x0a6c,0x000b, 0x0a76,0x0053, 0x0a78,0x0009, + 0x0a7a,0x008f, 0x0a82,0x0299, 0x0a86,0x01ed, 0x0a8a,0x0027, 0x0a8e,0x004b, + 0x0a92,0x003d, 0x0a95,0x0322, 0x0a99,0x0038, 0x0a99,0x0090, 0x0a9c,0x0061, + 0x0a9c,0x00c7, 0x0a9c,0x012d, 0x0a9c,0x016f, 0x0a9c,0x017d, 0x0a9c,0x02c9, + 0x0a9c,0x0383, 0x0aa1,0x0010, 0x0aa4,0x00b3, 0x0aa8,0x002f, 0x0aac,0x0027, + 0x0ab0,0x004b, 0x0ab4,0x0043, 0x0ab9,0x0090, 0x0abd,0x0010, 0x0ac4,0x0019, + 0x0acc,0x00f5, 0x0acc,0x022b, 0x0acc,0x037b, 0x0ad2,0x008f, 0x0ad2,0x01f1, + 0x0ad6,0x0324, 0x0ad9,0x0330, 0x0ade,0x008f, 0x0ade,0x01f1, 0x0ae0,0x017b, + 0x0ae4,0x008f, 0x0ae9,0x004e, 0x0aee,0x0027, 0x0af2,0x028a, 0x0af2,0x02a7, + 0x0af1,0x031c, 0x0af6,0x0027, 0x0af9,0x031c, 0x0afe,0x00e9, 0x0afe,0x02bb, + 0x0b02,0x000b, 0x0b06,0x00f5, 0x0b06,0x022b, 0x0b06,0x037b, 0x0b0a,0x003d, + 0x0000,0x0000 +}; + + diff --git a/src/opt/sim/module.make b/src/opt/sim/module.make new file mode 100644 index 00000000..54058402 --- /dev/null +++ b/src/opt/sim/module.make @@ -0,0 +1,10 @@ +SRC += src/opt/sim/simMan.c \ + src/opt/sim/simSat.c \ + src/opt/sim/simSeq.c \ + src/opt/sim/simSupp.c \ + src/opt/sim/simSwitch.c \ + src/opt/sim/simSym.c \ + src/opt/sim/simSymSat.c \ + src/opt/sim/simSymSim.c \ + src/opt/sim/simSymStr.c \ + src/opt/sim/simUtils.c diff --git a/src/opt/sim/sim.h b/src/opt/sim/sim.h new file mode 100644 index 00000000..7fcf5ae6 --- /dev/null +++ b/src/opt/sim/sim.h @@ -0,0 +1,233 @@ +/**CFile**************************************************************** + + FileName [sim.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Simulation package.] + + Synopsis [External declarations.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: sim.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef __SIM_H__ +#define __SIM_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + The ideas realized in this package are described in the paper: + "Detecting Symmetries in Boolean Functions using Circuit Representation, + Simulation, and Satisfiability". +*/ + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// BASIC TYPES /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Sym_Man_t_ Sym_Man_t; +struct Sym_Man_t_ +{ + // info about the network + Abc_Ntk_t * pNtk; // the network + Vec_Ptr_t * vNodes; // internal nodes in topological order + int nInputs; + int nOutputs; + // internal simulation information + int nSimWords; // the number of bits in simulation info + Vec_Ptr_t * vSim; // simulation info + // support information + Vec_Ptr_t * vSuppFun; // bit representation + Vec_Vec_t * vSupports; // integer representation + // symmetry info for each output + Vec_Ptr_t * vMatrSymms; // symmetric pairs + Vec_Ptr_t * vMatrNonSymms; // non-symmetric pairs + Vec_Int_t * vPairsTotal; // total pairs + Vec_Int_t * vPairsSym; // symmetric pairs + Vec_Int_t * vPairsNonSym; // non-symmetric pairs + // temporary simulation info + unsigned * uPatRand; + unsigned * uPatCol; + unsigned * uPatRow; + // temporary + Vec_Int_t * vVarsU; + Vec_Int_t * vVarsV; + int iOutput; + int iVar1; + int iVar2; + int iVar1Old; + int iVar2Old; + // internal data structures + int nSatRuns; + int nSatRunsSat; + int nSatRunsUnsat; + // pairs + int nPairsSymm; + int nPairsSymmStr; + int nPairsNonSymm; + int nPairsRem; + int nPairsTotal; + // runtime statistics + int timeStruct; + int timeCount; + int timeMatr; + int timeSim; + int timeFraig; + int timeSat; + int timeTotal; +}; + +typedef struct Sim_Man_t_ Sim_Man_t; +struct Sim_Man_t_ +{ + // info about the network + Abc_Ntk_t * pNtk; + int nInputs; + int nOutputs; + int fLightweight; + // internal simulation information + int nSimBits; // the number of bits in simulation info + int nSimWords; // the number of words in simulation info + Vec_Ptr_t * vSim0; // simulation info 1 + Vec_Ptr_t * vSim1; // simulation info 2 + // support information + int nSuppBits; // the number of bits in support info + int nSuppWords; // the number of words in support info + Vec_Ptr_t * vSuppStr; // structural supports + Vec_Ptr_t * vSuppFun; // functional supports + // simulation targets + Vec_Vec_t * vSuppTargs; // support targets + int iInput; // the input current processed + // internal data structures + Extra_MmFixed_t * pMmPat; + Vec_Ptr_t * vFifo; + Vec_Int_t * vDiffs; + int nSatRuns; + int nSatRunsSat; + int nSatRunsUnsat; + // runtime statistics + int timeSim; + int timeTrav; + int timeFraig; + int timeSat; + int timeTotal; +}; + +typedef struct Sim_Pat_t_ Sim_Pat_t; +struct Sim_Pat_t_ +{ + int Input; // the input which it has detected + int Output; // the output for which it was collected + unsigned * pData; // the simulation data +}; + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +#define SIM_NUM_WORDS(n) (((n)>>5) + (((n)&31) > 0)) +#define SIM_LAST_BITS(n) ((((n)&31) > 0)? (n)&31 : 32) + +#define SIM_MASK_FULL (0xFFFFFFFF) +#define SIM_MASK_BEG(n) (SIM_MASK_FULL >> (32-n)) +#define SIM_MASK_END(n) (SIM_MASK_FULL << (n)) +#define SIM_SET_0_FROM(m,n) ((m) & ~SIM_MASK_BEG(n)) +#define SIM_SET_1_FROM(m,n) ((m) | SIM_MASK_END(n)) + +// generating random unsigned (#define RAND_MAX 0x7fff) +#define SIM_RANDOM_UNSIGNED ((((unsigned)rand()) << 24) ^ (((unsigned)rand()) << 12) ^ ((unsigned)rand())) + +// macros to get hold of bits in a bit string +#define Sim_SetBit(p,i) ((p)[(i)>>5] |= (1<<((i) & 31))) +#define Sim_XorBit(p,i) ((p)[(i)>>5] ^= (1<<((i) & 31))) +#define Sim_HasBit(p,i) (((p)[(i)>>5] & (1<<((i) & 31))) > 0) + +// macros to get hold of the support info +#define Sim_SuppStrSetVar(vSupps,pNode,v) Sim_SetBit((unsigned*)(vSupps)->pArray[(pNode)->Id],(v)) +#define Sim_SuppStrHasVar(vSupps,pNode,v) Sim_HasBit((unsigned*)(vSupps)->pArray[(pNode)->Id],(v)) +#define Sim_SuppFunSetVar(vSupps,Output,v) Sim_SetBit((unsigned*)(vSupps)->pArray[Output],(v)) +#define Sim_SuppFunHasVar(vSupps,Output,v) Sim_HasBit((unsigned*)(vSupps)->pArray[Output],(v)) +#define Sim_SimInfoSetVar(vSupps,pNode,v) Sim_SetBit((unsigned*)(vSupps)->pArray[(pNode)->Id],(v)) +#define Sim_SimInfoHasVar(vSupps,pNode,v) Sim_HasBit((unsigned*)(vSupps)->pArray[(pNode)->Id],(v)) +#define Sim_SimInfoGet(vInfo,pNode) ((unsigned *)((vInfo)->pArray[(pNode)->Id])) + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +/*=== simMan.c ==========================================================*/ +extern Sym_Man_t * Sym_ManStart( Abc_Ntk_t * pNtk, int fVerbose ); +extern void Sym_ManStop( Sym_Man_t * p ); +extern void Sym_ManPrintStats( Sym_Man_t * p ); +extern Sim_Man_t * Sim_ManStart( Abc_Ntk_t * pNtk, int fLightweight ); +extern void Sim_ManStop( Sim_Man_t * p ); +extern void Sim_ManPrintStats( Sim_Man_t * p ); +extern Sim_Pat_t * Sim_ManPatAlloc( Sim_Man_t * p ); +extern void Sim_ManPatFree( Sim_Man_t * p, Sim_Pat_t * pPat ); +/*=== simSeq.c ==========================================================*/ +extern Vec_Ptr_t * Sim_SimulateSeqRandom( Abc_Ntk_t * pNtk, int nFrames, int nWords ); +extern Vec_Ptr_t * Sim_SimulateSeqModel( Abc_Ntk_t * pNtk, int nFrames, int * pModel ); +/*=== simSupp.c ==========================================================*/ +extern Vec_Ptr_t * Sim_ComputeStrSupp( Abc_Ntk_t * pNtk ); +extern Vec_Ptr_t * Sim_ComputeFunSupp( Abc_Ntk_t * pNtk, int fVerbose ); +/*=== simSym.c ==========================================================*/ +extern int Sim_ComputeTwoVarSymms( Abc_Ntk_t * pNtk, int fVerbose ); +/*=== simSymSat.c ==========================================================*/ +extern int Sim_SymmsGetPatternUsingSat( Sym_Man_t * p, unsigned * pPattern ); +/*=== simSymStr.c ==========================================================*/ +extern void Sim_SymmsStructCompute( Abc_Ntk_t * pNtk, Vec_Ptr_t * vMatrs, Vec_Ptr_t * vSuppFun ); +/*=== simSymSim.c ==========================================================*/ +extern void Sim_SymmsSimulate( Sym_Man_t * p, unsigned * pPatRand, Vec_Ptr_t * vMatrsNonSym ); +/*=== simUtil.c ==========================================================*/ +extern Vec_Ptr_t * Sim_UtilInfoAlloc( int nSize, int nWords, bool fClean ); +extern void Sim_UtilInfoFree( Vec_Ptr_t * p ); +extern void Sim_UtilInfoAdd( unsigned * pInfo1, unsigned * pInfo2, int nWords ); +extern void Sim_UtilInfoDetectDiffs( unsigned * pInfo1, unsigned * pInfo2, int nWords, Vec_Int_t * vDiffs ); +extern void Sim_UtilInfoDetectNews( unsigned * pInfo1, unsigned * pInfo2, int nWords, Vec_Int_t * vDiffs ); +extern void Sim_UtilInfoFlip( Sim_Man_t * p, Abc_Obj_t * pNode ); +extern bool Sim_UtilInfoCompare( Sim_Man_t * p, Abc_Obj_t * pNode ); +extern void Sim_UtilSimulate( Sim_Man_t * p, bool fFirst ); +extern void Sim_UtilSimulateNode( Sim_Man_t * p, Abc_Obj_t * pNode, bool fType, bool fType1, bool fType2 ); +extern void Sim_UtilSimulateNodeOne( Abc_Obj_t * pNode, Vec_Ptr_t * vSimInfo, int nSimWords, int nOffset ); +extern void Sim_UtilTransferNodeOne( Abc_Obj_t * pNode, Vec_Ptr_t * vSimInfo, int nSimWords, int nOffset, int fShift ); +extern int Sim_UtilCountSuppSizes( Sim_Man_t * p, int fStruct ); +extern int Sim_UtilCountOnes( unsigned * pSimInfo, int nSimWords ); +extern Vec_Int_t * Sim_UtilCountOnesArray( Vec_Ptr_t * vInfo, int nSimWords ); +extern void Sim_UtilSetRandom( unsigned * pPatRand, int nSimWords ); +extern void Sim_UtilSetCompl( unsigned * pPatRand, int nSimWords ); +extern void Sim_UtilSetConst( unsigned * pPatRand, int nSimWords, int fConst1 ); +extern int Sim_UtilInfoIsEqual( unsigned * pPats1, unsigned * pPats2, int nSimWords ); +extern int Sim_UtilInfoIsImp( unsigned * pPats1, unsigned * pPats2, int nSimWords ); +extern int Sim_UtilInfoIsClause( unsigned * pPats1, unsigned * pPats2, int nSimWords ); +extern int Sim_UtilCountAllPairs( Vec_Ptr_t * vSuppFun, int nSimWords, Vec_Int_t * vCounters ); +extern void Sim_UtilCountPairsAll( Sym_Man_t * p ); +extern int Sim_UtilMatrsAreDisjoint( Sym_Man_t * p ); + +#ifdef __cplusplus +} +#endif + +#endif + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + diff --git a/src/opt/sim/simMan.c b/src/opt/sim/simMan.c new file mode 100644 index 00000000..3b50ad84 --- /dev/null +++ b/src/opt/sim/simMan.c @@ -0,0 +1,288 @@ +/**CFile**************************************************************** + + FileName [simMan.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Network and node package.] + + Synopsis [Simulation manager.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: simMan.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "sim.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Starts the simulation manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Sym_Man_t * Sym_ManStart( Abc_Ntk_t * pNtk, int fVerbose ) +{ + Sym_Man_t * p; + int i, v; + // start the manager + p = ALLOC( Sym_Man_t, 1 ); + memset( p, 0, sizeof(Sym_Man_t) ); + p->pNtk = pNtk; + p->vNodes = Abc_NtkDfs( pNtk, 0 ); + p->nInputs = Abc_NtkCiNum(p->pNtk); + p->nOutputs = Abc_NtkCoNum(p->pNtk); + // internal simulation information + p->nSimWords = SIM_NUM_WORDS(p->nInputs); + p->vSim = Sim_UtilInfoAlloc( Abc_NtkObjNumMax(pNtk), p->nSimWords, 0 ); + // symmetry info for each output + p->vMatrSymms = Vec_PtrStart( p->nOutputs ); + p->vMatrNonSymms = Vec_PtrStart( p->nOutputs ); + p->vPairsTotal = Vec_IntStart( p->nOutputs ); + p->vPairsSym = Vec_IntStart( p->nOutputs ); + p->vPairsNonSym = Vec_IntStart( p->nOutputs ); + for ( i = 0; i < p->nOutputs; i++ ) + { + p->vMatrSymms->pArray[i] = Extra_BitMatrixStart( p->nInputs ); + p->vMatrNonSymms->pArray[i] = Extra_BitMatrixStart( p->nInputs ); + } + // temporary patterns + p->uPatRand = ALLOC( unsigned, p->nSimWords ); + p->uPatCol = ALLOC( unsigned, p->nSimWords ); + p->uPatRow = ALLOC( unsigned, p->nSimWords ); + p->vVarsU = Vec_IntStart( 100 ); + p->vVarsV = Vec_IntStart( 100 ); + // compute supports + p->vSuppFun = Sim_ComputeFunSupp( pNtk, fVerbose ); + p->vSupports = Vec_VecStart( p->nOutputs ); + for ( i = 0; i < p->nOutputs; i++ ) + for ( v = 0; v < p->nInputs; v++ ) + if ( Sim_SuppFunHasVar( p->vSuppFun, i, v ) ) + Vec_VecPush( p->vSupports, i, (void *)v ); + return p; +} + +/**Function************************************************************* + + Synopsis [Stops the simulation manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sym_ManStop( Sym_Man_t * p ) +{ + int i; + Sym_ManPrintStats( p ); + if ( p->vSuppFun ) Sim_UtilInfoFree( p->vSuppFun ); + if ( p->vSim ) Sim_UtilInfoFree( p->vSim ); + if ( p->vNodes ) Vec_PtrFree( p->vNodes ); + if ( p->vSupports ) Vec_VecFree( p->vSupports ); + for ( i = 0; i < p->nOutputs; i++ ) + { + Extra_BitMatrixStop( p->vMatrSymms->pArray[i] ); + Extra_BitMatrixStop( p->vMatrNonSymms->pArray[i] ); + } + Vec_IntFree( p->vVarsU ); + Vec_IntFree( p->vVarsV ); + Vec_PtrFree( p->vMatrSymms ); + Vec_PtrFree( p->vMatrNonSymms ); + Vec_IntFree( p->vPairsTotal ); + Vec_IntFree( p->vPairsSym ); + Vec_IntFree( p->vPairsNonSym ); + FREE( p->uPatRand ); + FREE( p->uPatCol ); + FREE( p->uPatRow ); + free( p ); +} + +/**Function************************************************************* + + Synopsis [Prints the manager statisticis.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sym_ManPrintStats( Sym_Man_t * p ) +{ +// printf( "Inputs = %5d. Outputs = %5d. Sim words = %5d.\n", +// Abc_NtkCiNum(p->pNtk), Abc_NtkCoNum(p->pNtk), p->nSimWords ); + printf( "Total symm = %8d.\n", p->nPairsSymm ); + printf( "Structural symm = %8d.\n", p->nPairsSymmStr ); + printf( "Total non-sym = %8d.\n", p->nPairsNonSymm ); + printf( "Total var pairs = %8d.\n", p->nPairsTotal ); + printf( "Sat runs SAT = %8d.\n", p->nSatRunsSat ); + printf( "Sat runs UNSAT = %8d.\n", p->nSatRunsUnsat ); + PRT( "Structural ", p->timeStruct ); + PRT( "Simulation ", p->timeSim ); + PRT( "Matrix ", p->timeMatr ); + PRT( "Counting ", p->timeCount ); + PRT( "Fraiging ", p->timeFraig ); + PRT( "SAT ", p->timeSat ); + PRT( "TOTAL ", p->timeTotal ); +} + + +/**Function************************************************************* + + Synopsis [Starts the simulation manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Sim_Man_t * Sim_ManStart( Abc_Ntk_t * pNtk, int fLightweight ) +{ + Sim_Man_t * p; + // start the manager + p = ALLOC( Sim_Man_t, 1 ); + memset( p, 0, sizeof(Sim_Man_t) ); + p->pNtk = pNtk; + p->nInputs = Abc_NtkCiNum(p->pNtk); + p->nOutputs = Abc_NtkCoNum(p->pNtk); + // internal simulation information + p->nSimBits = 2048; + p->nSimWords = SIM_NUM_WORDS(p->nSimBits); + p->vSim0 = Sim_UtilInfoAlloc( Abc_NtkObjNumMax(pNtk), p->nSimWords, 0 ); + p->fLightweight = fLightweight; + if (!p->fLightweight) { + p->vSim1 = Sim_UtilInfoAlloc( Abc_NtkObjNumMax(pNtk), p->nSimWords, 0 ); + // support information + p->nSuppBits = Abc_NtkCiNum(pNtk); + p->nSuppWords = SIM_NUM_WORDS(p->nSuppBits); + p->vSuppStr = Sim_ComputeStrSupp( pNtk ); + p->vSuppFun = Sim_UtilInfoAlloc( Abc_NtkCoNum(p->pNtk), p->nSuppWords, 1 ); + // other data + p->pMmPat = Extra_MmFixedStart( sizeof(Sim_Pat_t) + p->nSuppWords * sizeof(unsigned) ); + p->vFifo = Vec_PtrAlloc( 100 ); + p->vDiffs = Vec_IntAlloc( 100 ); + // allocate support targets (array of unresolved outputs for each input) + p->vSuppTargs = Vec_VecStart( p->nInputs ); + } + return p; +} + +/**Function************************************************************* + + Synopsis [Stops the simulation manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_ManStop( Sim_Man_t * p ) +{ + Sim_ManPrintStats( p ); + if ( p->vSim0 ) Sim_UtilInfoFree( p->vSim0 ); + if ( p->vSim1 ) Sim_UtilInfoFree( p->vSim1 ); + if ( p->vSuppStr ) Sim_UtilInfoFree( p->vSuppStr ); +// if ( p->vSuppFun ) Sim_UtilInfoFree( p->vSuppFun ); + if ( p->vSuppTargs ) Vec_VecFree( p->vSuppTargs ); + if ( p->pMmPat ) Extra_MmFixedStop( p->pMmPat ); + if ( p->vFifo ) Vec_PtrFree( p->vFifo ); + if ( p->vDiffs ) Vec_IntFree( p->vDiffs ); + free( p ); +} + +/**Function************************************************************* + + Synopsis [Prints the manager statisticis.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_ManPrintStats( Sim_Man_t * p ) +{ +// printf( "Inputs = %5d. Outputs = %5d. Sim words = %5d.\n", +// Abc_NtkCiNum(p->pNtk), Abc_NtkCoNum(p->pNtk), p->nSimWords ); + printf( "Total func supps = %8d.\n", Sim_UtilCountSuppSizes(p, 0) ); + printf( "Total struct supps = %8d.\n", Sim_UtilCountSuppSizes(p, 1) ); + printf( "Sat runs SAT = %8d.\n", p->nSatRunsSat ); + printf( "Sat runs UNSAT = %8d.\n", p->nSatRunsUnsat ); + PRT( "Simulation ", p->timeSim ); + PRT( "Traversal ", p->timeTrav ); + PRT( "Fraiging ", p->timeFraig ); + PRT( "SAT ", p->timeSat ); + PRT( "TOTAL ", p->timeTotal ); +} + + + +/**Function************************************************************* + + Synopsis [Returns one simulation pattern.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Sim_Pat_t * Sim_ManPatAlloc( Sim_Man_t * p ) +{ + Sim_Pat_t * pPat; + pPat = (Sim_Pat_t *)Extra_MmFixedEntryFetch( p->pMmPat ); + pPat->Output = -1; + pPat->pData = (unsigned *)((char *)pPat + sizeof(Sim_Pat_t)); + memset( pPat->pData, 0, p->nSuppWords * sizeof(unsigned) ); + return pPat; +} + +/**Function************************************************************* + + Synopsis [Returns one simulation pattern.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_ManPatFree( Sim_Man_t * p, Sim_Pat_t * pPat ) +{ + Extra_MmFixedEntryRecycle( p->pMmPat, (char *)pPat ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/sim/simSat.c b/src/opt/sim/simSat.c new file mode 100644 index 00000000..d514f7f2 --- /dev/null +++ b/src/opt/sim/simSat.c @@ -0,0 +1,48 @@ +/**CFile**************************************************************** + + FileName [simSat.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Network and node package.] + + Synopsis [Simulation to determine functional support.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: simSat.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "sim.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/sim/simSeq.c b/src/opt/sim/simSeq.c new file mode 100644 index 00000000..49fb939f --- /dev/null +++ b/src/opt/sim/simSeq.c @@ -0,0 +1,171 @@ +/**CFile**************************************************************** + + FileName [simSeq.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Network and node package.] + + Synopsis [Simulation for sequential circuits.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: simUtils.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "sim.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static void Sim_SimulateSeqFrame( Vec_Ptr_t * vInfo, Abc_Ntk_t * pNtk, int iFrames, int nWords, int fTransfer ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Simulates sequential circuit.] + + Description [Takes sequential circuit (pNtk). Simulates the given number + (nFrames) of the circuit with the given number of machine words (nWords) + of random simulation data, starting from the initial state. If the initial + state of some latches is a don't-care, uses random input for that latch.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Sim_SimulateSeqRandom( Abc_Ntk_t * pNtk, int nFrames, int nWords ) +{ + Vec_Ptr_t * vInfo; + Abc_Obj_t * pNode; + int i; + assert( Abc_NtkIsStrash(pNtk) ); + vInfo = Sim_UtilInfoAlloc( Abc_NtkObjNumMax(pNtk), nWords * nFrames, 0 ); + // set the constant data + pNode = Abc_AigConst1(pNtk); + Sim_UtilSetConst( Sim_SimInfoGet(vInfo,pNode), nWords * nFrames, 1 ); + // set the random PI data + Abc_NtkForEachPi( pNtk, pNode, i ) + Sim_UtilSetRandom( Sim_SimInfoGet(vInfo,pNode), nWords * nFrames ); + // set the initial state data + Abc_NtkForEachLatch( pNtk, pNode, i ) + if ( Abc_LatchIsInit0(pNode) ) + Sim_UtilSetConst( Sim_SimInfoGet(vInfo,pNode), nWords, 0 ); + else if ( Abc_LatchIsInit1(pNode) ) + Sim_UtilSetConst( Sim_SimInfoGet(vInfo,pNode), nWords, 1 ); + else + Sim_UtilSetRandom( Sim_SimInfoGet(vInfo,pNode), nWords ); + // simulate the nodes for the given number of timeframes + for ( i = 0; i < nFrames; i++ ) + Sim_SimulateSeqFrame( vInfo, pNtk, i, nWords, (int)(i < nFrames-1) ); + return vInfo; +} + +/**Function************************************************************* + + Synopsis [Simulates sequential circuit.] + + Description [Takes sequential circuit (pNtk). Simulates the given number + (nFrames) of the circuit with the given model. The model is assumed to + contain values of PIs for each frame. The latches are initialized to + the initial state. One word of data is simulated.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Sim_SimulateSeqModel( Abc_Ntk_t * pNtk, int nFrames, int * pModel ) +{ + Vec_Ptr_t * vInfo; + Abc_Obj_t * pNode; + unsigned * pUnsigned; + int i, k; + vInfo = Sim_UtilInfoAlloc( Abc_NtkObjNumMax(pNtk), nFrames, 0 ); + // set the constant data + pNode = Abc_AigConst1(pNtk); + Sim_UtilSetConst( Sim_SimInfoGet(vInfo,pNode), nFrames, 1 ); + // set the random PI data + Abc_NtkForEachPi( pNtk, pNode, i ) + { + pUnsigned = Sim_SimInfoGet(vInfo,pNode); + for ( k = 0; k < nFrames; k++ ) + pUnsigned[k] = pModel[k * Abc_NtkPiNum(pNtk) + i] ? ~((unsigned)0) : 0; + } + // set the initial state data + Abc_NtkForEachLatch( pNtk, pNode, i ) + { + pUnsigned = Sim_SimInfoGet(vInfo,pNode); + if ( Abc_LatchIsInit0(pNode) ) + pUnsigned[0] = 0; + else if ( Abc_LatchIsInit1(pNode) ) + pUnsigned[0] = ~((unsigned)0); + else + pUnsigned[0] = SIM_RANDOM_UNSIGNED; + } + // simulate the nodes for the given number of timeframes + for ( i = 0; i < nFrames; i++ ) + Sim_SimulateSeqFrame( vInfo, pNtk, i, 1, (int)(i < nFrames-1) ); +/* + // print the simulated values + for ( i = 0; i < nFrames; i++ ) + { + printf( "Frame %d : ", i+1 ); + Abc_NtkForEachPi( pNtk, pNode, k ) + printf( "%d", Sim_SimInfoGet(vInfo,pNode)[i] > 0 ); + printf( " " ); + Abc_NtkForEachLatch( pNtk, pNode, k ) + printf( "%d", Sim_SimInfoGet(vInfo,pNode)[i] > 0 ); + printf( " " ); + Abc_NtkForEachPo( pNtk, pNode, k ) + printf( "%d", Sim_SimInfoGet(vInfo,pNode)[i] > 0 ); + printf( "\n" ); + } + printf( "\n" ); +*/ + return vInfo; +} + +/**Function************************************************************* + + Synopsis [Simulates one frame of sequential circuit.] + + Description [Assumes that the latches and POs are already initialized. + In the end transfers the data to the latches of the next frame.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_SimulateSeqFrame( Vec_Ptr_t * vInfo, Abc_Ntk_t * pNtk, int iFrames, int nWords, int fTransfer ) +{ + Abc_Obj_t * pNode; + int i; + Abc_NtkForEachNode( pNtk, pNode, i ) + Sim_UtilSimulateNodeOne( pNode, vInfo, nWords, iFrames * nWords ); + Abc_NtkForEachPo( pNtk, pNode, i ) + Sim_UtilTransferNodeOne( pNode, vInfo, nWords, iFrames * nWords, 0 ); + if ( !fTransfer ) + return; + Abc_NtkForEachLatch( pNtk, pNode, i ) + Sim_UtilTransferNodeOne( pNode, vInfo, nWords, iFrames * nWords, 1 ); +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/sim/simSupp.c b/src/opt/sim/simSupp.c new file mode 100644 index 00000000..f7048f4a --- /dev/null +++ b/src/opt/sim/simSupp.c @@ -0,0 +1,597 @@ +/**CFile**************************************************************** + + FileName [simSupp.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Network and node package.] + + Synopsis [Simulation to determine functional support.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: simSupp.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "fraig.h" +#include "sim.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static int Sim_ComputeSuppRound( Sim_Man_t * p, bool fUseTargets ); +static int Sim_ComputeSuppRoundNode( Sim_Man_t * p, int iNumCi, bool fUseTargets ); +static void Sim_ComputeSuppSetTargets( Sim_Man_t * p ); + +static void Sim_UtilAssignRandom( Sim_Man_t * p ); +static void Sim_UtilAssignFromFifo( Sim_Man_t * p ); +static void Sim_SolveTargetsUsingSat( Sim_Man_t * p, int nCounters ); +static int Sim_SolveSuppModelVerify( Abc_Ntk_t * pNtk, int * pModel, int Input, int Output ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Computes structural supports.] + + Description [Supports are returned as an array of bit strings, one + for each CO.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Sim_ComputeStrSupp( Abc_Ntk_t * pNtk ) +{ + Vec_Ptr_t * vSuppStr; + Abc_Obj_t * pNode; + unsigned * pSimmNode, * pSimmNode1, * pSimmNode2; + int nSuppWords, i, k; + // allocate room for structural supports + nSuppWords = SIM_NUM_WORDS( Abc_NtkCiNum(pNtk) ); + vSuppStr = Sim_UtilInfoAlloc( Abc_NtkObjNumMax(pNtk), nSuppWords, 1 ); + // assign the structural support to the PIs + Abc_NtkForEachCi( pNtk, pNode, i ) + Sim_SuppStrSetVar( vSuppStr, pNode, i ); + // derive the structural supports of the internal nodes + Abc_NtkForEachNode( pNtk, pNode, i ) + { +// if ( Abc_NodeIsConst(pNode) ) +// continue; + pSimmNode = vSuppStr->pArray[ pNode->Id ]; + pSimmNode1 = vSuppStr->pArray[ Abc_ObjFaninId0(pNode) ]; + pSimmNode2 = vSuppStr->pArray[ Abc_ObjFaninId1(pNode) ]; + for ( k = 0; k < nSuppWords; k++ ) + pSimmNode[k] = pSimmNode1[k] | pSimmNode2[k]; + } + // set the structural supports of the PO nodes + Abc_NtkForEachCo( pNtk, pNode, i ) + { + pSimmNode = vSuppStr->pArray[ pNode->Id ]; + pSimmNode1 = vSuppStr->pArray[ Abc_ObjFaninId0(pNode) ]; + for ( k = 0; k < nSuppWords; k++ ) + pSimmNode[k] = pSimmNode1[k]; + } + return vSuppStr; +} + +/**Function************************************************************* + + Synopsis [Compute functional supports.] + + Description [Supports are returned as an array of bit strings, one + for each CO.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Sim_ComputeFunSupp( Abc_Ntk_t * pNtk, int fVerbose ) +{ + Sim_Man_t * p; + Vec_Ptr_t * vResult; + int nSolved, i, clk = clock(); + + srand( 0xABC ); + + // start the simulation manager + p = Sim_ManStart( pNtk, 0 ); + + // compute functional support using one round of random simulation + Sim_UtilAssignRandom( p ); + Sim_ComputeSuppRound( p, 0 ); + + // set the support targets + Sim_ComputeSuppSetTargets( p ); +if ( fVerbose ) + printf( "Number of support targets after simulation = %5d.\n", Vec_VecSizeSize(p->vSuppTargs) ); + if ( Vec_VecSizeSize(p->vSuppTargs) == 0 ) + goto exit; + + for ( i = 0; i < 1; i++ ) + { + // compute patterns using one round of random simulation + Sim_UtilAssignRandom( p ); + nSolved = Sim_ComputeSuppRound( p, 1 ); + if ( Vec_VecSizeSize(p->vSuppTargs) == 0 ) + goto exit; + +if ( fVerbose ) + printf( "Targets = %5d. Solved = %5d. Fifo = %5d.\n", + Vec_VecSizeSize(p->vSuppTargs), nSolved, Vec_PtrSize(p->vFifo) ); + } + + // try to solve the support targets + while ( Vec_VecSizeSize(p->vSuppTargs) > 0 ) + { + // solve targets until the first disproved one (which gives counter-example) + Sim_SolveTargetsUsingSat( p, p->nSimWords/p->nSuppWords ); + // compute additional functional support + Sim_UtilAssignFromFifo( p ); + nSolved = Sim_ComputeSuppRound( p, 1 ); + +if ( fVerbose ) + printf( "Targets = %5d. Solved = %5d. Fifo = %5d. SAT runs = %3d.\n", + Vec_VecSizeSize(p->vSuppTargs), nSolved, Vec_PtrSize(p->vFifo), p->nSatRuns ); + } + +exit: +p->timeTotal = clock() - clk; + vResult = p->vSuppFun; + // p->vSuppFun = NULL; + Sim_ManStop( p ); + return vResult; +} + +/**Function************************************************************* + + Synopsis [Computes functional support using one round of simulation.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Sim_ComputeSuppRound( Sim_Man_t * p, bool fUseTargets ) +{ + Vec_Int_t * vTargets; + int i, Counter = 0; + int clk; + // perform one round of random simulation +clk = clock(); + Sim_UtilSimulate( p, 0 ); +p->timeSim += clock() - clk; + // iterate through the CIs and detect COs that depend on them + for ( i = p->iInput; i < p->nInputs; i++ ) + { + vTargets = p->vSuppTargs->pArray[i]; + if ( fUseTargets && vTargets->nSize == 0 ) + continue; + Counter += Sim_ComputeSuppRoundNode( p, i, fUseTargets ); + } + return Counter; +} + +/**Function************************************************************* + + Synopsis [Computes functional support for one node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Sim_ComputeSuppRoundNode( Sim_Man_t * p, int iNumCi, bool fUseTargets ) +{ + int fVerbose = 0; + Sim_Pat_t * pPat; + Vec_Int_t * vTargets; + Vec_Vec_t * vNodesByLevel; + Abc_Obj_t * pNodeCi, * pNode; + int i, k, v, Output, LuckyPat, fType0, fType1; + int Counter = 0; + int fFirst = 1; + int clk; + // collect nodes by level in the TFO of the CI + // this proceduredoes not collect the CIs and COs + // but it increments TravId of the collected nodes and CIs/COs +clk = clock(); + pNodeCi = Abc_NtkCi( p->pNtk, iNumCi ); + vNodesByLevel = Abc_DfsLevelized( pNodeCi, 0 ); +p->timeTrav += clock() - clk; + // complement the simulation info of the selected CI + Sim_UtilInfoFlip( p, pNodeCi ); + // simulate the levelized structure of nodes + Vec_VecForEachEntry( vNodesByLevel, pNode, i, k ) + { + fType0 = Abc_NodeIsTravIdCurrent( Abc_ObjFanin0(pNode) ); + fType1 = Abc_NodeIsTravIdCurrent( Abc_ObjFanin1(pNode) ); +clk = clock(); + Sim_UtilSimulateNode( p, pNode, 1, fType0, fType1 ); +p->timeSim += clock() - clk; + } + // set the simulation info of the affected COs + if ( fUseTargets ) + { + vTargets = p->vSuppTargs->pArray[iNumCi]; + for ( i = vTargets->nSize - 1; i >= 0; i-- ) + { + // get the target output + Output = vTargets->pArray[i]; + // get the target node + pNode = Abc_ObjFanin0( Abc_NtkCo(p->pNtk, Output) ); + // the output should be in the cone + assert( Abc_NodeIsTravIdCurrent(pNode) ); + + // skip if the simulation info is equal + if ( Sim_UtilInfoCompare( p, pNode ) ) + continue; + + // otherwise, we solved a new target + Vec_IntRemove( vTargets, Output ); +if ( fVerbose ) + printf( "(%d,%d) ", iNumCi, Output ); + Counter++; + // make sure this variable is not yet detected + assert( !Sim_SuppFunHasVar(p->vSuppFun, Output, iNumCi) ); + // set this variable + Sim_SuppFunSetVar( p->vSuppFun, Output, iNumCi ); + + // detect the differences in the simulation info + Sim_UtilInfoDetectDiffs( p->vSim0->pArray[pNode->Id], p->vSim1->pArray[pNode->Id], p->nSimWords, p->vDiffs ); + // create new patterns + if ( !fFirst && p->vFifo->nSize > 1000 ) + continue; + + Vec_IntForEachEntry( p->vDiffs, LuckyPat, k ) + { + // set the new pattern + pPat = Sim_ManPatAlloc( p ); + pPat->Input = iNumCi; + pPat->Output = Output; + Abc_NtkForEachCi( p->pNtk, pNodeCi, v ) + if ( Sim_SimInfoHasVar( p->vSim0, pNodeCi, LuckyPat ) ) + Sim_SetBit( pPat->pData, v ); + Vec_PtrPush( p->vFifo, pPat ); + + fFirst = 0; + break; + } + } +if ( fVerbose && Counter ) +printf( "\n" ); + } + else + { + Abc_NtkForEachCo( p->pNtk, pNode, Output ) + { + if ( !Abc_NodeIsTravIdCurrent( pNode ) ) + continue; + if ( !Sim_UtilInfoCompare( p, Abc_ObjFanin0(pNode) ) ) + { + if ( !Sim_SuppFunHasVar(p->vSuppFun, Output, iNumCi) ) + { + Counter++; + Sim_SuppFunSetVar( p->vSuppFun, Output, iNumCi ); + } + } + } + } + Vec_VecFree( vNodesByLevel ); + return Counter; +} + +/**Function************************************************************* + + Synopsis [Sets the simulation targets.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_ComputeSuppSetTargets( Sim_Man_t * p ) +{ + Abc_Obj_t * pNode; + unsigned * pSuppStr, * pSuppFun; + int i, k, Num; + Abc_NtkForEachCo( p->pNtk, pNode, i ) + { + pSuppStr = p->vSuppStr->pArray[pNode->Id]; + pSuppFun = p->vSuppFun->pArray[i]; + // find vars in the structural support that are not in the functional support + Sim_UtilInfoDetectNews( pSuppFun, pSuppStr, p->nSuppWords, p->vDiffs ); + Vec_IntForEachEntry( p->vDiffs, Num, k ) + Vec_VecPush( p->vSuppTargs, Num, (void *)i ); + } +} + +/**Function************************************************************* + + Synopsis [Assigns random simulation info to the PIs.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_UtilAssignRandom( Sim_Man_t * p ) +{ + Abc_Obj_t * pNode; + unsigned * pSimInfo; + int i, k; + // assign the random/systematic simulation info to the PIs + Abc_NtkForEachCi( p->pNtk, pNode, i ) + { + pSimInfo = p->vSim0->pArray[pNode->Id]; + for ( k = 0; k < p->nSimWords; k++ ) + pSimInfo[k] = SIM_RANDOM_UNSIGNED; + } +} + +/**Function************************************************************* + + Synopsis [Sets the new patterns from fifo.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_UtilAssignFromFifo( Sim_Man_t * p ) +{ + int fUseOneWord = 0; + Abc_Obj_t * pNode; + Sim_Pat_t * pPat; + unsigned * pSimInfo; + int nWordsNew, iWord, iWordLim, i, w; + int iBeg, iEnd; + int Counter = 0; + // go through the patterns and fill in the dist-1 minterms for each + for ( iWord = 0; p->vFifo->nSize > 0; iWord = iWordLim ) + { + ++Counter; + // get the pattern + pPat = Vec_PtrPop( p->vFifo ); + if ( fUseOneWord ) + { + // get the first word of the next series + iWordLim = iWord + 1; + // set the pattern for all PIs from iBit to iWord + p->nInputs + iBeg = p->iInput; + iEnd = ABC_MIN( iBeg + 32, p->nInputs ); +// for ( i = iBeg; i < iEnd; i++ ) + Abc_NtkForEachCi( p->pNtk, pNode, i ) + { + pNode = Abc_NtkCi(p->pNtk,i); + pSimInfo = p->vSim0->pArray[pNode->Id]; + if ( Sim_HasBit(pPat->pData, i) ) + pSimInfo[iWord] = SIM_MASK_FULL; + else + pSimInfo[iWord] = 0; + // flip one bit + if ( i >= iBeg && i < iEnd ) + Sim_XorBit( pSimInfo + iWord, i-iBeg ); + } + } + else + { + // get the number of words for the remaining inputs + nWordsNew = p->nSuppWords; +// nWordsNew = SIM_NUM_WORDS( p->nInputs - p->iInput ); + // get the first word of the next series + iWordLim = (iWord + nWordsNew < p->nSimWords)? iWord + nWordsNew : p->nSimWords; + // set the pattern for all CIs from iWord to iWord + nWordsNew + Abc_NtkForEachCi( p->pNtk, pNode, i ) + { + pSimInfo = p->vSim0->pArray[pNode->Id]; + if ( Sim_HasBit(pPat->pData, i) ) + { + for ( w = iWord; w < iWordLim; w++ ) + pSimInfo[w] = SIM_MASK_FULL; + } + else + { + for ( w = iWord; w < iWordLim; w++ ) + pSimInfo[w] = 0; + } + Sim_XorBit( pSimInfo + iWord, i ); + // flip one bit +// if ( i >= p->iInput ) +// Sim_XorBit( pSimInfo + iWord, i-p->iInput ); + } + } + Sim_ManPatFree( p, pPat ); + // stop if we ran out of room for patterns + if ( iWordLim == p->nSimWords ) + break; +// if ( Counter == 1 ) +// break; + } +} + +/**Function************************************************************* + + Synopsis [Get the given number of counter-examples using SAT.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_SolveTargetsUsingSat( Sim_Man_t * p, int Limit ) +{ + Fraig_Params_t Params; + Fraig_Man_t * pMan; + Abc_Obj_t * pNodeCi; + Abc_Ntk_t * pMiter; + Sim_Pat_t * pPat; + void * pEntry; + int * pModel; + int RetValue, Output, Input, k, v; + int Counter = 0; + int clk; + + p->nSatRuns = 0; + // put targets into one array + Vec_VecForEachEntryReverse( p->vSuppTargs, pEntry, Input, k ) + { + p->nSatRuns++; + Output = (int)pEntry; + + // set up the miter for the two cofactors of this output w.r.t. this input + pMiter = Abc_NtkMiterForCofactors( p->pNtk, Output, Input, -1 ); + + // transform the miter into a fraig + Fraig_ParamsSetDefault( &Params ); + Params.nSeconds = ABC_INFINITY; + Params.fInternal = 1; +clk = clock(); + pMan = Abc_NtkToFraig( pMiter, &Params, 0, 0 ); +p->timeFraig += clock() - clk; +clk = clock(); + Fraig_ManProveMiter( pMan ); +p->timeSat += clock() - clk; + + // analyze the result + RetValue = Fraig_ManCheckMiter( pMan ); + assert( RetValue >= 0 ); + if ( RetValue == 1 ) // unsat + { + p->nSatRunsUnsat++; + pModel = NULL; + Vec_PtrRemove( p->vSuppTargs->pArray[Input], pEntry ); + } + else // sat + { + p->nSatRunsSat++; + pModel = Fraig_ManReadModel( pMan ); + assert( pModel != NULL ); + assert( Sim_SolveSuppModelVerify( p->pNtk, pModel, Input, Output ) ); + +//printf( "Solved by SAT (%d,%d).\n", Input, Output ); + // set the new pattern + pPat = Sim_ManPatAlloc( p ); + pPat->Input = Input; + pPat->Output = Output; + Abc_NtkForEachCi( p->pNtk, pNodeCi, v ) + if ( pModel[v] ) + Sim_SetBit( pPat->pData, v ); + Vec_PtrPush( p->vFifo, pPat ); +/* + // set the new pattern + pPat = Sim_ManPatAlloc( p ); + pPat->Input = Input; + pPat->Output = Output; + Abc_NtkForEachCi( p->pNtk, pNodeCi, v ) + if ( pModel[v] ) + Sim_SetBit( pPat->pData, v ); + Sim_XorBit( pPat->pData, Input ); // add this bit in the opposite polarity + Vec_PtrPush( p->vFifo, pPat ); +*/ + Counter++; + } + // delete the fraig manager + Fraig_ManFree( pMan ); + // delete the miter + Abc_NtkDelete( pMiter ); + + // makr the input, which we are processing + p->iInput = Input; + + // stop when we found enough patterns +// if ( Counter == Limit ) + if ( Counter == 1 ) + return; + } +} + + +/**Function************************************************************* + + Synopsis [Saves the counter example.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Sim_NtkSimTwoPats_rec( Abc_Obj_t * pNode ) +{ + int Value0, Value1; + if ( Abc_NodeIsTravIdCurrent( pNode ) ) + return (int)pNode->pCopy; + Abc_NodeSetTravIdCurrent( pNode ); + Value0 = Sim_NtkSimTwoPats_rec( Abc_ObjFanin0(pNode) ); + Value1 = Sim_NtkSimTwoPats_rec( Abc_ObjFanin1(pNode) ); + if ( Abc_ObjFaninC0(pNode) ) + Value0 = ~Value0; + if ( Abc_ObjFaninC1(pNode) ) + Value1 = ~Value1; + pNode->pCopy = (Abc_Obj_t *)(Value0 & Value1); + return Value0 & Value1; +} + +/**Function************************************************************* + + Synopsis [Verifies that pModel proves the presence of Input in the support of Output.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Sim_SolveSuppModelVerify( Abc_Ntk_t * pNtk, int * pModel, int Input, int Output ) +{ + Abc_Obj_t * pNode; + int RetValue, i; + // set the PI values + Abc_NtkIncrementTravId( pNtk ); + Abc_NtkForEachCi( pNtk, pNode, i ) + { + Abc_NodeSetTravIdCurrent( pNode ); + if ( pNode == Abc_NtkCi(pNtk,Input) ) + pNode->pCopy = (Abc_Obj_t *)1; + else if ( pModel[i] == 1 ) + pNode->pCopy = (Abc_Obj_t *)3; + else + pNode->pCopy = NULL; + } + // perform the traversal + RetValue = 3 & Sim_NtkSimTwoPats_rec( Abc_ObjFanin0( Abc_NtkCo(pNtk,Output) ) ); +// assert( RetValue == 1 || RetValue == 2 ); + return RetValue == 1 || RetValue == 2; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/sim/simSwitch.c b/src/opt/sim/simSwitch.c new file mode 100644 index 00000000..218d4d59 --- /dev/null +++ b/src/opt/sim/simSwitch.c @@ -0,0 +1,107 @@ +/**CFile**************************************************************** + + FileName [simSwitch.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Network and node package.] + + Synopsis [Computes switching activity of nodes in the ABC network.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: simSwitch.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "sim.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static void Sim_NodeSimulate( Abc_Obj_t * pNode, Vec_Ptr_t * vSimInfo, int nSimWords ); +static float Sim_ComputeSwitching( unsigned * pSimInfo, int nSimWords ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Computes switching activity using simulation.] + + Description [Computes switching activity, which is understood as the + probability of switching under random simulation. Assigns the + random simulation information at the CI and propagates it through + the internal nodes of the AIG.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Int_t * Sim_NtkComputeSwitching( Abc_Ntk_t * pNtk, int nPatterns ) +{ + Vec_Int_t * vSwitching; + float * pSwitching; + Vec_Ptr_t * vNodes; + Vec_Ptr_t * vSimInfo; + Abc_Obj_t * pNode; + unsigned * pSimInfo; + int nSimWords, i; + + // allocate space for simulation info of all nodes + nSimWords = SIM_NUM_WORDS(nPatterns); + vSimInfo = Sim_UtilInfoAlloc( Abc_NtkObjNumMax(pNtk), nSimWords, 0 ); + // assign the random simulation to the CIs + vSwitching = Vec_IntStart( Abc_NtkObjNumMax(pNtk) ); + pSwitching = (float *)vSwitching->pArray; + Abc_NtkForEachCi( pNtk, pNode, i ) + { + pSimInfo = Vec_PtrEntry(vSimInfo, pNode->Id); + Sim_UtilSetRandom( pSimInfo, nSimWords ); + pSwitching[pNode->Id] = Sim_ComputeSwitching( pSimInfo, nSimWords ); + } + // simulate the internal nodes + vNodes = Abc_AigDfs( pNtk, 1, 0 ); + Vec_PtrForEachEntry( vNodes, pNode, i ) + { + pSimInfo = Vec_PtrEntry(vSimInfo, pNode->Id); + Sim_UtilSimulateNodeOne( pNode, vSimInfo, nSimWords, 0 ); + pSwitching[pNode->Id] = Sim_ComputeSwitching( pSimInfo, nSimWords ); + } + Vec_PtrFree( vNodes ); + Sim_UtilInfoFree( vSimInfo ); + return vSwitching; +} + +/**Function************************************************************* + + Synopsis [Computes switching activity of one node.] + + Description [Uses the formula: Switching = 2 * nOnes * nZeros / (nTotal ^ 2) ] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +float Sim_ComputeSwitching( unsigned * pSimInfo, int nSimWords ) +{ + int nOnes, nTotal; + nTotal = 32 * nSimWords; + nOnes = Sim_UtilCountOnes( pSimInfo, nSimWords ); + return (float)2.0 * nOnes * (nTotal - nOnes) / nTotal / nTotal; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/sim/simSym.c b/src/opt/sim/simSym.c new file mode 100644 index 00000000..71de5b05 --- /dev/null +++ b/src/opt/sim/simSym.c @@ -0,0 +1,142 @@ +/**CFile**************************************************************** + + FileName [simSym.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Network and node package.] + + Synopsis [Simulation to determine two-variable symmetries.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: simSym.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "sim.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Computes two variable symmetries.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Sim_ComputeTwoVarSymms( Abc_Ntk_t * pNtk, int fVerbose ) +{ + Sym_Man_t * p; + Vec_Ptr_t * vResult; + int Result; + int i, clk, clkTotal = clock(); + + srand( 0xABC ); + + // start the simulation manager + p = Sym_ManStart( pNtk, fVerbose ); + p->nPairsTotal = p->nPairsRem = Sim_UtilCountAllPairs( p->vSuppFun, p->nSimWords, p->vPairsTotal ); + if ( fVerbose ) + printf( "Total = %8d. Sym = %8d. NonSym = %8d. Remaining = %8d.\n", + p->nPairsTotal, p->nPairsSymm, p->nPairsNonSymm, p->nPairsRem ); + + // detect symmetries using circuit structure +clk = clock(); + Sim_SymmsStructCompute( pNtk, p->vMatrSymms, p->vSuppFun ); +p->timeStruct = clock() - clk; + + Sim_UtilCountPairsAll( p ); + p->nPairsSymmStr = p->nPairsSymm; + if ( fVerbose ) + printf( "Total = %8d. Sym = %8d. NonSym = %8d. Remaining = %8d.\n", + p->nPairsTotal, p->nPairsSymm, p->nPairsNonSymm, p->nPairsRem ); + + // detect symmetries using simulation + for ( i = 1; i <= 1000; i++ ) + { + // simulate this pattern + Sim_UtilSetRandom( p->uPatRand, p->nSimWords ); + Sim_SymmsSimulate( p, p->uPatRand, p->vMatrNonSymms ); + if ( i % 50 != 0 ) + continue; + // check disjointness + assert( Sim_UtilMatrsAreDisjoint( p ) ); + // count the number of pairs + Sim_UtilCountPairsAll( p ); + if ( i % 500 != 0 ) + continue; + if ( fVerbose ) + printf( "Total = %8d. Sym = %8d. NonSym = %8d. Remaining = %8d.\n", + p->nPairsTotal, p->nPairsSymm, p->nPairsNonSymm, p->nPairsRem ); + } + + // detect symmetries using SAT + for ( i = 1; Sim_SymmsGetPatternUsingSat( p, p->uPatRand ); i++ ) + { + // simulate this pattern in four polarities + Sim_SymmsSimulate( p, p->uPatRand, p->vMatrNonSymms ); + Sim_XorBit( p->uPatRand, p->iVar1 ); + Sim_SymmsSimulate( p, p->uPatRand, p->vMatrNonSymms ); + Sim_XorBit( p->uPatRand, p->iVar2 ); + Sim_SymmsSimulate( p, p->uPatRand, p->vMatrNonSymms ); + Sim_XorBit( p->uPatRand, p->iVar1 ); + Sim_SymmsSimulate( p, p->uPatRand, p->vMatrNonSymms ); + Sim_XorBit( p->uPatRand, p->iVar2 ); +/* + // try the previuos pair + Sim_XorBit( p->uPatRand, p->iVar1Old ); + Sim_SymmsSimulate( p, p->uPatRand, p->vMatrNonSymms ); + Sim_XorBit( p->uPatRand, p->iVar2Old ); + Sim_SymmsSimulate( p, p->uPatRand, p->vMatrNonSymms ); + Sim_XorBit( p->uPatRand, p->iVar1Old ); + Sim_SymmsSimulate( p, p->uPatRand, p->vMatrNonSymms ); +*/ + if ( i % 10 != 0 ) + continue; + // check disjointness + assert( Sim_UtilMatrsAreDisjoint( p ) ); + // count the number of pairs + Sim_UtilCountPairsAll( p ); + if ( i % 50 != 0 ) + continue; + if ( fVerbose ) + printf( "Total = %8d. Sym = %8d. NonSym = %8d. Remaining = %8d.\n", + p->nPairsTotal, p->nPairsSymm, p->nPairsNonSymm, p->nPairsRem ); + } + + // count the number of pairs + Sim_UtilCountPairsAll( p ); + if ( fVerbose ) + printf( "Total = %8d. Sym = %8d. NonSym = %8d. Remaining = %8d.\n", + p->nPairsTotal, p->nPairsSymm, p->nPairsNonSymm, p->nPairsRem ); +// Sim_UtilCountPairsAllPrint( p ); + + Result = p->nPairsSymm; + vResult = p->vMatrSymms; +p->timeTotal = clock() - clkTotal; + // p->vMatrSymms = NULL; + Sym_ManStop( p ); + return Result; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/sim/simSymSat.c b/src/opt/sim/simSymSat.c new file mode 100644 index 00000000..7690a891 --- /dev/null +++ b/src/opt/sim/simSymSat.c @@ -0,0 +1,199 @@ +/**CFile**************************************************************** + + FileName [simSymSat.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Network and node package.] + + Synopsis [Satisfiability to determine two variable symmetries.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: simSymSat.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "sim.h" +#include "fraig.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static int Sim_SymmsSatProveOne( Sym_Man_t * p, int Out, int Var1, int Var2, unsigned * pPattern ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Tries to prove the remaining pairs using SAT.] + + Description [Continues to prove as long as it encounters symmetric pairs. + Returns 1 if a non-symmetric pair is found (which gives a counter-example). + Returns 0 if it finishes considering all pairs for all outputs.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Sim_SymmsGetPatternUsingSat( Sym_Man_t * p, unsigned * pPattern ) +{ + Vec_Int_t * vSupport; + Extra_BitMat_t * pMatSym, * pMatNonSym; + int Index1, Index2, Index3, IndexU, IndexV; + int v, u, i, k, b, out; + + // iterate through outputs + for ( out = p->iOutput; out < p->nOutputs; out++ ) + { + pMatSym = Vec_PtrEntry( p->vMatrSymms, out ); + pMatNonSym = Vec_PtrEntry( p->vMatrNonSymms, out ); + + // go through the remaining variable pairs + vSupport = Vec_VecEntry( p->vSupports, out ); + Vec_IntForEachEntry( vSupport, v, Index1 ) + Vec_IntForEachEntryStart( vSupport, u, Index2, Index1+1 ) + { + if ( Extra_BitMatrixLookup1( pMatSym, v, u ) || Extra_BitMatrixLookup1( pMatNonSym, v, u ) ) + continue; + p->nSatRuns++; + + // collect the support variables that are symmetric with u and v + Vec_IntClear( p->vVarsU ); + Vec_IntClear( p->vVarsV ); + Vec_IntForEachEntry( vSupport, b, Index3 ) + { + if ( Extra_BitMatrixLookup1( pMatSym, u, b ) ) + Vec_IntPush( p->vVarsU, b ); + if ( Extra_BitMatrixLookup1( pMatSym, v, b ) ) + Vec_IntPush( p->vVarsV, b ); + } + + if ( Sim_SymmsSatProveOne( p, out, v, u, pPattern ) ) + { // update the symmetric variable info + p->nSatRunsUnsat++; + Vec_IntForEachEntry( p->vVarsU, i, IndexU ) + Vec_IntForEachEntry( p->vVarsV, k, IndexV ) + { + Extra_BitMatrixInsert1( pMatSym, i, k ); // Theorem 1 + Extra_BitMatrixInsert2( pMatSym, i, k ); // Theorem 1 + Extra_BitMatrixOrTwo( pMatNonSym, i, k ); // Theorem 2 + } + } + else + { // update the assymmetric variable info + p->nSatRunsSat++; + Vec_IntForEachEntry( p->vVarsU, i, IndexU ) + Vec_IntForEachEntry( p->vVarsV, k, IndexV ) + { + Extra_BitMatrixInsert1( pMatNonSym, i, k ); // Theorem 3 + Extra_BitMatrixInsert2( pMatNonSym, i, k ); // Theorem 3 + } + + // remember the out + p->iOutput = out; + p->iVar1Old = p->iVar1; + p->iVar2Old = p->iVar2; + p->iVar1 = v; + p->iVar2 = u; + return 1; + + } + } + // make sure that the symmetry matrix contains only cliques + assert( Extra_BitMatrixIsClique( pMatSym ) ); + } + + // mark that we finished all outputs + p->iOutput = p->nOutputs; + return 0; +} + +/**Function************************************************************* + + Synopsis [Returns 1 if the variables are symmetric; 0 otherwise.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Sim_SymmsSatProveOne( Sym_Man_t * p, int Out, int Var1, int Var2, unsigned * pPattern ) +{ + Fraig_Params_t Params; + Fraig_Man_t * pMan; + Abc_Ntk_t * pMiter; + int RetValue, i, clk; + int * pModel; + + // get the miter for this problem + pMiter = Abc_NtkMiterForCofactors( p->pNtk, Out, Var1, Var2 ); + // transform the miter into a fraig + Fraig_ParamsSetDefault( &Params ); + Params.fInternal = 1; + Params.nPatsRand = 512; + Params.nPatsDyna = 512; + Params.nSeconds = ABC_INFINITY; + +clk = clock(); + pMan = Abc_NtkToFraig( pMiter, &Params, 0, 0 ); +p->timeFraig += clock() - clk; +clk = clock(); + Fraig_ManProveMiter( pMan ); +p->timeSat += clock() - clk; + + // analyze the result + RetValue = Fraig_ManCheckMiter( pMan ); +// assert( RetValue >= 0 ); + // save the pattern + if ( RetValue == 0 ) + { + // get the pattern + pModel = Fraig_ManReadModel( pMan ); + assert( pModel != NULL ); +//printf( "Disproved by SAT: out = %d pair = (%d, %d)\n", Out, Var1, Var2 ); + // transfer the model into the pattern + for ( i = 0; i < p->nSimWords; i++ ) + pPattern[i] = 0; + for ( i = 0; i < p->nInputs; i++ ) + if ( pModel[i] ) + Sim_SetBit( pPattern, i ); + // make sure these variables have the same value (1) + Sim_SetBit( pPattern, Var1 ); + Sim_SetBit( pPattern, Var2 ); + } + else if ( RetValue == -1 ) + { + // this should never happen; if it happens, such is life + // we are conservative and assume that there is no symmetry +//printf( "STRANGE THING: out = %d %s pair = (%d %s, %d %s)\n", +// Out, Abc_ObjName(Abc_NtkCo(p->pNtk,Out)), +// Var1, Abc_ObjName(Abc_NtkCi(p->pNtk,Var1)), +// Var2, Abc_ObjName(Abc_NtkCi(p->pNtk,Var2)) ); + memset( pPattern, 0, sizeof(unsigned) * p->nSimWords ); + RetValue = 0; + } + // delete the fraig manager + Fraig_ManFree( pMan ); + // delete the miter + Abc_NtkDelete( pMiter ); + return RetValue; +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/sim/simSymSim.c b/src/opt/sim/simSymSim.c new file mode 100644 index 00000000..2282825b --- /dev/null +++ b/src/opt/sim/simSymSim.c @@ -0,0 +1,173 @@ +/**CFile**************************************************************** + + FileName [simSymSim.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Network and node package.] + + Synopsis [Simulation to determine two-variable symmetries.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: simSymSim.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "sim.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static void Sim_SymmsCreateSquare( Sym_Man_t * p, unsigned * pPat ); +static void Sim_SymmsDeriveInfo( Sym_Man_t * p, unsigned * pPat, Abc_Obj_t * pNode, Vec_Ptr_t * vMatrsNonSym, int Output ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Detects non-symmetric pairs using one pattern.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_SymmsSimulate( Sym_Man_t * p, unsigned * pPat, Vec_Ptr_t * vMatrsNonSym ) +{ + Abc_Obj_t * pNode; + int i, nPairsTotal, nPairsSym, nPairsNonSym; + int clk; + + // create the simulation matrix + Sim_SymmsCreateSquare( p, pPat ); + // simulate each node in the DFS order +clk = clock(); + Vec_PtrForEachEntry( p->vNodes, pNode, i ) + { +// if ( Abc_NodeIsConst(pNode) ) +// continue; + Sim_UtilSimulateNodeOne( pNode, p->vSim, p->nSimWords, 0 ); + } +p->timeSim += clock() - clk; + // collect info into the CO matrices +clk = clock(); + Abc_NtkForEachCo( p->pNtk, pNode, i ) + { + pNode = Abc_ObjFanin0(pNode); +// if ( Abc_ObjIsCi(pNode) || Abc_AigNodeIsConst(pNode) ) +// continue; + nPairsTotal = Vec_IntEntry(p->vPairsTotal, i); + nPairsSym = Vec_IntEntry(p->vPairsSym, i); + nPairsNonSym = Vec_IntEntry(p->vPairsNonSym,i); + assert( nPairsTotal >= nPairsSym + nPairsNonSym ); + if ( nPairsTotal == nPairsSym + nPairsNonSym ) + continue; + Sim_SymmsDeriveInfo( p, pPat, pNode, vMatrsNonSym, i ); + } +p->timeMatr += clock() - clk; +} + +/**Function************************************************************* + + Synopsis [Creates the square matrix of simulation info.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_SymmsCreateSquare( Sym_Man_t * p, unsigned * pPat ) +{ + unsigned * pSimInfo; + Abc_Obj_t * pNode; + int i, w; + // for each PI var copy the pattern + Abc_NtkForEachCi( p->pNtk, pNode, i ) + { + pSimInfo = Vec_PtrEntry( p->vSim, pNode->Id ); + if ( Sim_HasBit(pPat, i) ) + { + for ( w = 0; w < p->nSimWords; w++ ) + pSimInfo[w] = SIM_MASK_FULL; + } + else + { + for ( w = 0; w < p->nSimWords; w++ ) + pSimInfo[w] = 0; + } + // flip one bit + Sim_XorBit( pSimInfo, i ); + } +} + +/**Function************************************************************* + + Synopsis [Transfers the info to the POs.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_SymmsDeriveInfo( Sym_Man_t * p, unsigned * pPat, Abc_Obj_t * pNode, Vec_Ptr_t * vMatrsNonSym, int Output ) +{ + Extra_BitMat_t * pMat; + Vec_Int_t * vSupport; + unsigned * pSupport; + unsigned * pSimInfo; + int i, w, Index; + // get the matrix, the support, and the simulation info + pMat = Vec_PtrEntry( vMatrsNonSym, Output ); + vSupport = Vec_VecEntry( p->vSupports, Output ); + pSupport = Vec_PtrEntry( p->vSuppFun, Output ); + pSimInfo = Vec_PtrEntry( p->vSim, pNode->Id ); + // generate vectors A1 and A2 + for ( w = 0; w < p->nSimWords; w++ ) + { + p->uPatCol[w] = pSupport[w] & pPat[w] & pSimInfo[w]; + p->uPatRow[w] = pSupport[w] & pPat[w] & ~pSimInfo[w]; + } + // add two dimensions + Vec_IntForEachEntry( vSupport, i, Index ) + if ( Sim_HasBit( p->uPatCol, i ) ) + Extra_BitMatrixOr( pMat, i, p->uPatRow ); + // add two dimensions + Vec_IntForEachEntry( vSupport, i, Index ) + if ( Sim_HasBit( p->uPatRow, i ) ) + Extra_BitMatrixOr( pMat, i, p->uPatCol ); + // generate vectors B1 and B2 + for ( w = 0; w < p->nSimWords; w++ ) + { + p->uPatCol[w] = pSupport[w] & ~pPat[w] & pSimInfo[w]; + p->uPatRow[w] = pSupport[w] & ~pPat[w] & ~pSimInfo[w]; + } + // add two dimensions + Vec_IntForEachEntry( vSupport, i, Index ) + if ( Sim_HasBit( p->uPatCol, i ) ) + Extra_BitMatrixOr( pMat, i, p->uPatRow ); + // add two dimensions + Vec_IntForEachEntry( vSupport, i, Index ) + if ( Sim_HasBit( p->uPatRow, i ) ) + Extra_BitMatrixOr( pMat, i, p->uPatCol ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/sim/simSymStr.c b/src/opt/sim/simSymStr.c new file mode 100644 index 00000000..d52c4328 --- /dev/null +++ b/src/opt/sim/simSymStr.c @@ -0,0 +1,488 @@ +/**CFile**************************************************************** + + FileName [simSymStr.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Network and node package.] + + Synopsis [Structural detection of symmetries.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: simSymStr.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "sim.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +#define SIM_READ_SYMMS(pNode) ((Vec_Int_t *)pNode->pCopy) +#define SIM_SET_SYMMS(pNode,vVect) (pNode->pCopy = (Abc_Obj_t *)(vVect)) + +static void Sim_SymmsStructComputeOne( Abc_Ntk_t * pNtk, Abc_Obj_t * pNode, int * pMap ); +static void Sim_SymmsBalanceCollect_rec( Abc_Obj_t * pNode, Vec_Ptr_t * vNodes ); +static void Sim_SymmsPartitionNodes( Vec_Ptr_t * vNodes, Vec_Ptr_t * vNodesPis0, Vec_Ptr_t * vNodesPis1, Vec_Ptr_t * vNodesOther ); +static void Sim_SymmsAppendFromGroup( Abc_Ntk_t * pNtk, Vec_Ptr_t * vNodesPi, Vec_Ptr_t * vNodesOther, Vec_Int_t * vSymms, int * pMap ); +static void Sim_SymmsAppendFromNode( Abc_Ntk_t * pNtk, Vec_Int_t * vSymms0, Vec_Ptr_t * vNodesOther, Vec_Ptr_t * vNodesPi0, Vec_Ptr_t * vNodesPi1, Vec_Int_t * vSymms, int * pMap ); +static int Sim_SymmsIsCompatibleWithNodes( Abc_Ntk_t * pNtk, unsigned uSymm, Vec_Ptr_t * vNodesOther, int * pMap ); +static int Sim_SymmsIsCompatibleWithGroup( unsigned uSymm, Vec_Ptr_t * vNodesPi, int * pMap ); +static void Sim_SymmsPrint( Vec_Int_t * vSymms ); +static void Sim_SymmsTrans( Vec_Int_t * vSymms ); +static void Sim_SymmsTransferToMatrix( Extra_BitMat_t * pMatSymm, Vec_Int_t * vSymms, unsigned * pSupport ); +static int * Sim_SymmsCreateMap( Abc_Ntk_t * pNtk ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Computes symmetries for a single output function.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_SymmsStructCompute( Abc_Ntk_t * pNtk, Vec_Ptr_t * vMatrs, Vec_Ptr_t * vSuppFun ) +{ + Vec_Ptr_t * vNodes; + Abc_Obj_t * pTemp; + int * pMap, i; + + assert( Abc_NtkCiNum(pNtk) + 10 < (1<<16) ); + + // get the structural support + pNtk->vSupps = Sim_ComputeStrSupp( pNtk ); + // set elementary info for the CIs + Abc_NtkForEachCi( pNtk, pTemp, i ) + SIM_SET_SYMMS( pTemp, Vec_IntAlloc(0) ); + // create the map of CI ids into their numbers + pMap = Sim_SymmsCreateMap( pNtk ); + // collect the nodes in the TFI cone of this output + vNodes = Abc_NtkDfs( pNtk, 0 ); + Vec_PtrForEachEntry( vNodes, pTemp, i ) + { +// if ( Abc_NodeIsConst(pTemp) ) +// continue; + Sim_SymmsStructComputeOne( pNtk, pTemp, pMap ); + } + // collect the results for the COs; + Abc_NtkForEachCo( pNtk, pTemp, i ) + { +//printf( "Output %d:\n", i ); + pTemp = Abc_ObjFanin0(pTemp); + if ( Abc_ObjIsCi(pTemp) || Abc_AigNodeIsConst(pTemp) ) + continue; + Sim_SymmsTransferToMatrix( Vec_PtrEntry(vMatrs, i), SIM_READ_SYMMS(pTemp), Vec_PtrEntry(vSuppFun, i) ); + } + // clean the intermediate results + Sim_UtilInfoFree( pNtk->vSupps ); + pNtk->vSupps = NULL; + Abc_NtkForEachCi( pNtk, pTemp, i ) + Vec_IntFree( SIM_READ_SYMMS(pTemp) ); + Vec_PtrForEachEntry( vNodes, pTemp, i ) +// if ( !Abc_NodeIsConst(pTemp) ) + Vec_IntFree( SIM_READ_SYMMS(pTemp) ); + Vec_PtrFree( vNodes ); + free( pMap ); +} + +/**Function************************************************************* + + Synopsis [Recursively computes symmetries. ] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_SymmsStructComputeOne( Abc_Ntk_t * pNtk, Abc_Obj_t * pNode, int * pMap ) +{ + Vec_Ptr_t * vNodes, * vNodesPi0, * vNodesPi1, * vNodesOther; + Vec_Int_t * vSymms; + Abc_Obj_t * pTemp; + int i; + + // allocate the temporary arrays + vNodes = Vec_PtrAlloc( 10 ); + vNodesPi0 = Vec_PtrAlloc( 10 ); + vNodesPi1 = Vec_PtrAlloc( 10 ); + vNodesOther = Vec_PtrAlloc( 10 ); + + // collect the fanins of the implication supergate + Sim_SymmsBalanceCollect_rec( pNode, vNodes ); + + // sort the nodes in the implication supergate + Sim_SymmsPartitionNodes( vNodes, vNodesPi0, vNodesPi1, vNodesOther ); + + // start the resulting set + vSymms = Vec_IntAlloc( 10 ); + // generate symmetries from the groups + Sim_SymmsAppendFromGroup( pNtk, vNodesPi0, vNodesOther, vSymms, pMap ); + Sim_SymmsAppendFromGroup( pNtk, vNodesPi1, vNodesOther, vSymms, pMap ); + // add symmetries from other inputs + for ( i = 0; i < vNodesOther->nSize; i++ ) + { + pTemp = Abc_ObjRegular(vNodesOther->pArray[i]); + Sim_SymmsAppendFromNode( pNtk, SIM_READ_SYMMS(pTemp), vNodesOther, vNodesPi0, vNodesPi1, vSymms, pMap ); + } + Vec_PtrFree( vNodes ); + Vec_PtrFree( vNodesPi0 ); + Vec_PtrFree( vNodesPi1 ); + Vec_PtrFree( vNodesOther ); + + // set the symmetry at the node + SIM_SET_SYMMS( pNode, vSymms ); +} + + +/**Function************************************************************* + + Synopsis [Returns the array of nodes to be combined into one multi-input AND-gate.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_SymmsBalanceCollect_rec( Abc_Obj_t * pNode, Vec_Ptr_t * vNodes ) +{ + // if the new node is complemented, another gate begins + if ( Abc_ObjIsComplement(pNode) ) + { + Vec_PtrPushUnique( vNodes, pNode ); + return; + } + // if pNew is the PI node, return + if ( Abc_ObjIsCi(pNode) ) + { + Vec_PtrPushUnique( vNodes, pNode ); + return; + } + // go through the branches + Sim_SymmsBalanceCollect_rec( Abc_ObjChild0(pNode), vNodes ); + Sim_SymmsBalanceCollect_rec( Abc_ObjChild1(pNode), vNodes ); +} + +/**Function************************************************************* + + Synopsis [Divides PI variables into groups.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_SymmsPartitionNodes( Vec_Ptr_t * vNodes, Vec_Ptr_t * vNodesPis0, + Vec_Ptr_t * vNodesPis1, Vec_Ptr_t * vNodesOther ) +{ + Abc_Obj_t * pNode; + int i; + Vec_PtrForEachEntry( vNodes, pNode, i ) + { + if ( !Abc_ObjIsCi(Abc_ObjRegular(pNode)) ) + Vec_PtrPush( vNodesOther, pNode ); + else if ( Abc_ObjIsComplement(pNode) ) + Vec_PtrPush( vNodesPis0, pNode ); + else + Vec_PtrPush( vNodesPis1, pNode ); + } +} + +/**Function************************************************************* + + Synopsis [Makes the product of two partitions.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_SymmsAppendFromGroup( Abc_Ntk_t * pNtk, Vec_Ptr_t * vNodesPi, Vec_Ptr_t * vNodesOther, Vec_Int_t * vSymms, int * pMap ) +{ + Abc_Obj_t * pNode1, * pNode2; + unsigned uSymm; + int i, k; + + if ( vNodesPi->nSize == 0 ) + return; + + // go through the pairs + for ( i = 0; i < vNodesPi->nSize; i++ ) + for ( k = i+1; k < vNodesPi->nSize; k++ ) + { + // get the two PI nodes + pNode1 = Abc_ObjRegular(vNodesPi->pArray[i]); + pNode2 = Abc_ObjRegular(vNodesPi->pArray[k]); + assert( pMap[pNode1->Id] != pMap[pNode2->Id] ); + assert( pMap[pNode1->Id] >= 0 ); + assert( pMap[pNode2->Id] >= 0 ); + // generate symmetry + if ( pMap[pNode1->Id] < pMap[pNode2->Id] ) + uSymm = ((pMap[pNode1->Id] << 16) | pMap[pNode2->Id]); + else + uSymm = ((pMap[pNode2->Id] << 16) | pMap[pNode1->Id]); + // check if symmetry belongs + if ( Sim_SymmsIsCompatibleWithNodes( pNtk, uSymm, vNodesOther, pMap ) ) + Vec_IntPushUnique( vSymms, (int)uSymm ); + } +} + +/**Function************************************************************* + + Synopsis [Add the filters symmetries from the nodes.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_SymmsAppendFromNode( Abc_Ntk_t * pNtk, Vec_Int_t * vSymms0, Vec_Ptr_t * vNodesOther, + Vec_Ptr_t * vNodesPi0, Vec_Ptr_t * vNodesPi1, Vec_Int_t * vSymms, int * pMap ) +{ + unsigned uSymm; + int i; + + if ( vSymms0->nSize == 0 ) + return; + + // go through the pairs + for ( i = 0; i < vSymms0->nSize; i++ ) + { + uSymm = (unsigned)vSymms0->pArray[i]; + // check if symmetry belongs + if ( Sim_SymmsIsCompatibleWithNodes( pNtk, uSymm, vNodesOther, pMap ) && + Sim_SymmsIsCompatibleWithGroup( uSymm, vNodesPi0, pMap ) && + Sim_SymmsIsCompatibleWithGroup( uSymm, vNodesPi1, pMap ) ) + Vec_IntPushUnique( vSymms, (int)uSymm ); + } +} + +/**Function************************************************************* + + Synopsis [Returns 1 if symmetry is compatible with the group of nodes.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Sim_SymmsIsCompatibleWithNodes( Abc_Ntk_t * pNtk, unsigned uSymm, Vec_Ptr_t * vNodesOther, int * pMap ) +{ + Vec_Int_t * vSymmsNode; + Abc_Obj_t * pNode; + int i, s, Ind1, Ind2, fIsVar1, fIsVar2; + + if ( vNodesOther->nSize == 0 ) + return 1; + + // get the indices of the PI variables + Ind1 = (uSymm & 0xffff); + Ind2 = (uSymm >> 16); + + // go through the nodes + // if they do not belong to a support, it is okay + // if one belongs, the other does not belong, quit + // if they belong, but are not part of symmetry, quit + for ( i = 0; i < vNodesOther->nSize; i++ ) + { + pNode = Abc_ObjRegular(vNodesOther->pArray[i]); + fIsVar1 = Sim_SuppStrHasVar( pNtk->vSupps, pNode, Ind1 ); + fIsVar2 = Sim_SuppStrHasVar( pNtk->vSupps, pNode, Ind2 ); + + if ( !fIsVar1 && !fIsVar2 ) + continue; + if ( fIsVar1 ^ fIsVar2 ) + return 0; + // both belong + // check if there is a symmetry + vSymmsNode = SIM_READ_SYMMS( pNode ); + for ( s = 0; s < vSymmsNode->nSize; s++ ) + if ( uSymm == (unsigned)vSymmsNode->pArray[s] ) + break; + if ( s == vSymmsNode->nSize ) + return 0; + } + return 1; +} + +/**Function************************************************************* + + Synopsis [Returns 1 if symmetry is compatible with the group of PIs.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Sim_SymmsIsCompatibleWithGroup( unsigned uSymm, Vec_Ptr_t * vNodesPi, int * pMap ) +{ + Abc_Obj_t * pNode; + int i, Ind1, Ind2, fHasVar1, fHasVar2; + + if ( vNodesPi->nSize == 0 ) + return 1; + + // get the indices of the PI variables + Ind1 = (uSymm & 0xffff); + Ind2 = (uSymm >> 16); + + // go through the PI nodes + fHasVar1 = fHasVar2 = 0; + for ( i = 0; i < vNodesPi->nSize; i++ ) + { + pNode = Abc_ObjRegular(vNodesPi->pArray[i]); + if ( pMap[pNode->Id] == Ind1 ) + fHasVar1 = 1; + else if ( pMap[pNode->Id] == Ind2 ) + fHasVar2 = 1; + } + return fHasVar1 == fHasVar2; +} + + + +/**Function************************************************************* + + Synopsis [Improvements due to transitivity.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_SymmsTrans( Vec_Int_t * vSymms ) +{ + unsigned uSymm, uSymma, uSymmr; + int i, Ind1, Ind2; + int k, Ind1a, Ind2a; + int j; + int nTrans = 0; + + for ( i = 0; i < vSymms->nSize; i++ ) + { + uSymm = (unsigned)vSymms->pArray[i]; + Ind1 = (uSymm & 0xffff); + Ind2 = (uSymm >> 16); + // find other symmetries that have Ind1 + for ( k = i+1; k < vSymms->nSize; k++ ) + { + uSymma = (unsigned)vSymms->pArray[k]; + if ( uSymma == uSymm ) + continue; + Ind1a = (uSymma & 0xffff); + Ind2a = (uSymma >> 16); + if ( Ind1a == Ind1 ) + { + // find the symmetry (Ind2,Ind2a) + if ( Ind2 < Ind2a ) + uSymmr = ((Ind2 << 16) | Ind2a); + else + uSymmr = ((Ind2a << 16) | Ind2); + for ( j = 0; j < vSymms->nSize; j++ ) + if ( uSymmr == (unsigned)vSymms->pArray[j] ) + break; + if ( j == vSymms->nSize ) + nTrans++; + } + } + + } + printf( "Trans = %d.\n", nTrans ); +} + + +/**Function************************************************************* + + Synopsis [Transfers from the vector to the matrix.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_SymmsTransferToMatrix( Extra_BitMat_t * pMatSymm, Vec_Int_t * vSymms, unsigned * pSupport ) +{ + int i, Ind1, Ind2, nInputs; + unsigned uSymm; + // add diagonal elements + nInputs = Extra_BitMatrixReadSize( pMatSymm ); + for ( i = 0; i < nInputs; i++ ) + Extra_BitMatrixInsert1( pMatSymm, i, i ); + // add non-diagonal elements + for ( i = 0; i < vSymms->nSize; i++ ) + { + uSymm = (unsigned)vSymms->pArray[i]; + Ind1 = (uSymm & 0xffff); + Ind2 = (uSymm >> 16); +//printf( "%d,%d ", Ind1, Ind2 ); + // skip variables that are not in the true support + assert( Sim_HasBit(pSupport, Ind1) == Sim_HasBit(pSupport, Ind2) ); + if ( !Sim_HasBit(pSupport, Ind1) || !Sim_HasBit(pSupport, Ind2) ) + continue; + Extra_BitMatrixInsert1( pMatSymm, Ind1, Ind2 ); + Extra_BitMatrixInsert2( pMatSymm, Ind1, Ind2 ); + } +} + +/**Function************************************************************* + + Synopsis [Mapping of indices into numbers.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int * Sim_SymmsCreateMap( Abc_Ntk_t * pNtk ) +{ + int * pMap; + Abc_Obj_t * pNode; + int i; + pMap = ALLOC( int, Abc_NtkObjNumMax(pNtk) ); + for ( i = 0; i < Abc_NtkObjNumMax(pNtk); i++ ) + pMap[i] = -1; + Abc_NtkForEachCi( pNtk, pNode, i ) + pMap[pNode->Id] = i; + return pMap; +} + + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/sim/simUtils.c b/src/opt/sim/simUtils.c new file mode 100644 index 00000000..b0660001 --- /dev/null +++ b/src/opt/sim/simUtils.c @@ -0,0 +1,711 @@ +/**CFile**************************************************************** + + FileName [simUtils.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Network and node package.] + + Synopsis [Various simulation utilities.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: simUtils.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "sim.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static int bit_count[256] = { + 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8 +}; + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Allocates simulation information for all nodes.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Sim_UtilInfoAlloc( int nSize, int nWords, bool fClean ) +{ + Vec_Ptr_t * vInfo; + int i; + assert( nSize > 0 && nWords > 0 ); + vInfo = Vec_PtrAlloc( nSize ); + vInfo->pArray[0] = ALLOC( unsigned, nSize * nWords ); + if ( fClean ) + memset( vInfo->pArray[0], 0, sizeof(unsigned) * nSize * nWords ); + for ( i = 1; i < nSize; i++ ) + vInfo->pArray[i] = ((unsigned *)vInfo->pArray[i-1]) + nWords; + vInfo->nSize = nSize; + return vInfo; +} + +/**Function************************************************************* + + Synopsis [Allocates simulation information for all nodes.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_UtilInfoFree( Vec_Ptr_t * p ) +{ + free( p->pArray[0] ); + Vec_PtrFree( p ); +} + +/**Function************************************************************* + + Synopsis [Adds the second supp-info the first.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_UtilInfoAdd( unsigned * pInfo1, unsigned * pInfo2, int nWords ) +{ + int w; + for ( w = 0; w < nWords; w++ ) + pInfo1[w] |= pInfo2[w]; +} + +/**Function************************************************************* + + Synopsis [Returns the positions where pInfo2 is 1 while pInfo1 is 0.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_UtilInfoDetectDiffs( unsigned * pInfo1, unsigned * pInfo2, int nWords, Vec_Int_t * vDiffs ) +{ + int w, b; + unsigned uMask; + vDiffs->nSize = 0; + for ( w = 0; w < nWords; w++ ) + if ( uMask = (pInfo2[w] ^ pInfo1[w]) ) + for ( b = 0; b < 32; b++ ) + if ( uMask & (1 << b) ) + Vec_IntPush( vDiffs, 32*w + b ); +} + +/**Function************************************************************* + + Synopsis [Returns the positions where pInfo2 is 1 while pInfo1 is 0.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_UtilInfoDetectNews( unsigned * pInfo1, unsigned * pInfo2, int nWords, Vec_Int_t * vDiffs ) +{ + int w, b; + unsigned uMask; + vDiffs->nSize = 0; + for ( w = 0; w < nWords; w++ ) + if ( uMask = (pInfo2[w] & ~pInfo1[w]) ) + for ( b = 0; b < 32; b++ ) + if ( uMask & (1 << b) ) + Vec_IntPush( vDiffs, 32*w + b ); +} + +/**Function************************************************************* + + Synopsis [Flips the simulation info of the node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_UtilInfoFlip( Sim_Man_t * p, Abc_Obj_t * pNode ) +{ + unsigned * pSimInfo1, * pSimInfo2; + int k; + pSimInfo1 = p->vSim0->pArray[pNode->Id]; + pSimInfo2 = p->vSim1->pArray[pNode->Id]; + for ( k = 0; k < p->nSimWords; k++ ) + pSimInfo2[k] = ~pSimInfo1[k]; +} + +/**Function************************************************************* + + Synopsis [Returns 1 if the simulation infos are equal.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +bool Sim_UtilInfoCompare( Sim_Man_t * p, Abc_Obj_t * pNode ) +{ + unsigned * pSimInfo1, * pSimInfo2; + int k; + pSimInfo1 = p->vSim0->pArray[pNode->Id]; + pSimInfo2 = p->vSim1->pArray[pNode->Id]; + for ( k = 0; k < p->nSimWords; k++ ) + if ( pSimInfo2[k] != pSimInfo1[k] ) + return 0; + return 1; +} + +/**Function************************************************************* + + Synopsis [Simulates the internal nodes.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_UtilSimulate( Sim_Man_t * p, bool fType ) +{ + Abc_Obj_t * pNode; + int i; + // simulate the internal nodes + Abc_NtkForEachNode( p->pNtk, pNode, i ) + Sim_UtilSimulateNode( p, pNode, fType, fType, fType ); + // assign simulation info of the CO nodes + Abc_NtkForEachCo( p->pNtk, pNode, i ) + Sim_UtilSimulateNode( p, pNode, fType, fType, fType ); +} + +/**Function************************************************************* + + Synopsis [Simulates one node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_UtilSimulateNode( Sim_Man_t * p, Abc_Obj_t * pNode, bool fType, bool fType1, bool fType2 ) +{ + unsigned * pSimmNode, * pSimmNode1, * pSimmNode2; + int k, fComp1, fComp2; + // simulate the internal nodes + if ( Abc_ObjIsNode(pNode) ) + { + if ( fType ) + pSimmNode = p->vSim1->pArray[ pNode->Id ]; + else + pSimmNode = p->vSim0->pArray[ pNode->Id ]; + + if ( fType1 ) + pSimmNode1 = p->vSim1->pArray[ Abc_ObjFaninId0(pNode) ]; + else + pSimmNode1 = p->vSim0->pArray[ Abc_ObjFaninId0(pNode) ]; + + if ( fType2 ) + pSimmNode2 = p->vSim1->pArray[ Abc_ObjFaninId1(pNode) ]; + else + pSimmNode2 = p->vSim0->pArray[ Abc_ObjFaninId1(pNode) ]; + + fComp1 = Abc_ObjFaninC0(pNode); + fComp2 = Abc_ObjFaninC1(pNode); + if ( fComp1 && fComp2 ) + for ( k = 0; k < p->nSimWords; k++ ) + pSimmNode[k] = ~pSimmNode1[k] & ~pSimmNode2[k]; + else if ( fComp1 && !fComp2 ) + for ( k = 0; k < p->nSimWords; k++ ) + pSimmNode[k] = ~pSimmNode1[k] & pSimmNode2[k]; + else if ( !fComp1 && fComp2 ) + for ( k = 0; k < p->nSimWords; k++ ) + pSimmNode[k] = pSimmNode1[k] & ~pSimmNode2[k]; + else // if ( fComp1 && fComp2 ) + for ( k = 0; k < p->nSimWords; k++ ) + pSimmNode[k] = pSimmNode1[k] & pSimmNode2[k]; + } + else + { + assert( Abc_ObjFaninNum(pNode) == 1 ); + if ( fType ) + pSimmNode = p->vSim1->pArray[ pNode->Id ]; + else + pSimmNode = p->vSim0->pArray[ pNode->Id ]; + + if ( fType1 ) + pSimmNode1 = p->vSim1->pArray[ Abc_ObjFaninId0(pNode) ]; + else + pSimmNode1 = p->vSim0->pArray[ Abc_ObjFaninId0(pNode) ]; + + fComp1 = Abc_ObjFaninC0(pNode); + if ( fComp1 ) + for ( k = 0; k < p->nSimWords; k++ ) + pSimmNode[k] = ~pSimmNode1[k]; + else + for ( k = 0; k < p->nSimWords; k++ ) + pSimmNode[k] = pSimmNode1[k]; + } +} + +/**Function************************************************************* + + Synopsis [Simulates one node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_UtilSimulateNodeOne( Abc_Obj_t * pNode, Vec_Ptr_t * vSimInfo, int nSimWords, int nOffset ) +{ + unsigned * pSimmNode, * pSimmNode1, * pSimmNode2; + int k, fComp1, fComp2; + // simulate the internal nodes + assert( Abc_ObjIsNode(pNode) ); + pSimmNode = Vec_PtrEntry(vSimInfo, pNode->Id); + pSimmNode1 = Vec_PtrEntry(vSimInfo, Abc_ObjFaninId0(pNode)); + pSimmNode2 = Vec_PtrEntry(vSimInfo, Abc_ObjFaninId1(pNode)); + pSimmNode += nOffset; + pSimmNode1 += nOffset; + pSimmNode2 += nOffset; + fComp1 = Abc_ObjFaninC0(pNode); + fComp2 = Abc_ObjFaninC1(pNode); + if ( fComp1 && fComp2 ) + for ( k = 0; k < nSimWords; k++ ) + pSimmNode[k] = ~pSimmNode1[k] & ~pSimmNode2[k]; + else if ( fComp1 && !fComp2 ) + for ( k = 0; k < nSimWords; k++ ) + pSimmNode[k] = ~pSimmNode1[k] & pSimmNode2[k]; + else if ( !fComp1 && fComp2 ) + for ( k = 0; k < nSimWords; k++ ) + pSimmNode[k] = pSimmNode1[k] & ~pSimmNode2[k]; + else // if ( fComp1 && fComp2 ) + for ( k = 0; k < nSimWords; k++ ) + pSimmNode[k] = pSimmNode1[k] & pSimmNode2[k]; +} + +/**Function************************************************************* + + Synopsis [Simulates one node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_UtilTransferNodeOne( Abc_Obj_t * pNode, Vec_Ptr_t * vSimInfo, int nSimWords, int nOffset, int fShift ) +{ + unsigned * pSimmNode, * pSimmNode1; + int k, fComp1; + // simulate the internal nodes + assert( Abc_ObjIsCo(pNode) ); + pSimmNode = Vec_PtrEntry(vSimInfo, pNode->Id); + pSimmNode1 = Vec_PtrEntry(vSimInfo, Abc_ObjFaninId0(pNode)); + pSimmNode += nOffset + (fShift > 0)*nSimWords; + pSimmNode1 += nOffset; + fComp1 = Abc_ObjFaninC0(pNode); + if ( fComp1 ) + for ( k = 0; k < nSimWords; k++ ) + pSimmNode[k] = ~pSimmNode1[k]; + else + for ( k = 0; k < nSimWords; k++ ) + pSimmNode[k] = pSimmNode1[k]; +} + +/**Function************************************************************* + + Synopsis [Returns 1 if the simulation infos are equal.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Sim_UtilCountSuppSizes( Sim_Man_t * p, int fStruct ) +{ + Abc_Obj_t * pNode, * pNodeCi; + int i, v, Counter; + Counter = 0; + if ( fStruct ) + { + Abc_NtkForEachCo( p->pNtk, pNode, i ) + Abc_NtkForEachCi( p->pNtk, pNodeCi, v ) + Counter += Sim_SuppStrHasVar( p->vSuppStr, pNode, v ); + } + else + { + Abc_NtkForEachCo( p->pNtk, pNode, i ) + Abc_NtkForEachCi( p->pNtk, pNodeCi, v ) + Counter += Sim_SuppFunHasVar( p->vSuppFun, i, v ); + } + return Counter; +} + +/**Function************************************************************* + + Synopsis [Counts the number of 1's in the bitstring.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Sim_UtilCountOnes( unsigned * pSimInfo, int nSimWords ) +{ + unsigned char * pBytes; + int nOnes, nBytes, i; + pBytes = (unsigned char *)pSimInfo; + nBytes = 4 * nSimWords; + nOnes = 0; + for ( i = 0; i < nBytes; i++ ) + nOnes += bit_count[ pBytes[i] ]; + return nOnes; +} + +/**Function************************************************************* + + Synopsis [Counts the number of 1's in the bitstring.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Int_t * Sim_UtilCountOnesArray( Vec_Ptr_t * vInfo, int nSimWords ) +{ + Vec_Int_t * vCounters; + unsigned * pSimInfo; + int i; + vCounters = Vec_IntStart( Vec_PtrSize(vInfo) ); + Vec_PtrForEachEntry( vInfo, pSimInfo, i ) + Vec_IntWriteEntry( vCounters, i, Sim_UtilCountOnes(pSimInfo, nSimWords) ); + return vCounters; +} + +/**Function************************************************************* + + Synopsis [Returns random patterns.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_UtilSetRandom( unsigned * pPatRand, int nSimWords ) +{ + int k; + for ( k = 0; k < nSimWords; k++ ) + pPatRand[k] = SIM_RANDOM_UNSIGNED; +} + +/**Function************************************************************* + + Synopsis [Returns complemented patterns.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_UtilSetCompl( unsigned * pPatRand, int nSimWords ) +{ + int k; + for ( k = 0; k < nSimWords; k++ ) + pPatRand[k] = ~pPatRand[k]; +} + +/**Function************************************************************* + + Synopsis [Returns constant patterns.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_UtilSetConst( unsigned * pPatRand, int nSimWords, int fConst1 ) +{ + int k; + for ( k = 0; k < nSimWords; k++ ) + pPatRand[k] = 0; + if ( fConst1 ) + Sim_UtilSetCompl( pPatRand, nSimWords ); +} + +/**Function************************************************************* + + Synopsis [Returns 1 if equal.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Sim_UtilInfoIsEqual( unsigned * pPats1, unsigned * pPats2, int nSimWords ) +{ + int k; + for ( k = 0; k < nSimWords; k++ ) + if ( pPats1[k] != pPats2[k] ) + return 0; + return 1; +} + +/**Function************************************************************* + + Synopsis [Returns 1 if Node1 implies Node2.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Sim_UtilInfoIsImp( unsigned * pPats1, unsigned * pPats2, int nSimWords ) +{ + int k; + for ( k = 0; k < nSimWords; k++ ) + if ( pPats1[k] & ~pPats2[k] ) + return 0; + return 1; +} + +/**Function************************************************************* + + Synopsis [Returns 1 if Node1 v Node2 is always true.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Sim_UtilInfoIsClause( unsigned * pPats1, unsigned * pPats2, int nSimWords ) +{ + int k; + for ( k = 0; k < nSimWords; k++ ) + if ( ~pPats1[k] & ~pPats2[k] ) + return 0; + return 1; +} + +/**Function************************************************************* + + Synopsis [Counts the total number of pairs.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Sim_UtilCountAllPairs( Vec_Ptr_t * vSuppFun, int nSimWords, Vec_Int_t * vCounters ) +{ + unsigned * pSupp; + int Counter, nOnes, nPairs, i; + Counter = 0; + Vec_PtrForEachEntry( vSuppFun, pSupp, i ) + { + nOnes = Sim_UtilCountOnes( pSupp, nSimWords ); + nPairs = nOnes * (nOnes - 1) / 2; + Vec_IntWriteEntry( vCounters, i, nPairs ); + Counter += nPairs; + } + return Counter; +} + +/**Function************************************************************* + + Synopsis [Counts the number of entries in the array of matrices.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Sim_UtilCountPairsOne( Extra_BitMat_t * pMat, Vec_Int_t * vSupport ) +{ + int i, k, Index1, Index2; + int Counter = 0; +// int Counter2; + Vec_IntForEachEntry( vSupport, i, Index1 ) + Vec_IntForEachEntryStart( vSupport, k, Index2, Index1+1 ) + Counter += Extra_BitMatrixLookup1( pMat, i, k ); +// Counter2 = Extra_BitMatrixCountOnesUpper(pMat); +// assert( Counter == Counter2 ); + return Counter; +} + +/**Function************************************************************* + + Synopsis [Counts the number of entries in the array of matrices.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Sim_UtilCountPairsOnePrint( Extra_BitMat_t * pMat, Vec_Int_t * vSupport ) +{ + int i, k, Index1, Index2; + Vec_IntForEachEntry( vSupport, i, Index1 ) + Vec_IntForEachEntryStart( vSupport, k, Index2, Index1+1 ) + if ( Extra_BitMatrixLookup1( pMat, i, k ) ) + printf( "(%d,%d) ", i, k ); + return 0; +} + +/**Function************************************************************* + + Synopsis [Counts the number of entries in the array of matrices.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_UtilCountPairsAllPrint( Sym_Man_t * p ) +{ + int i, clk; +clk = clock(); + for ( i = 0; i < p->nOutputs; i++ ) + { + printf( "Output %2d :", i ); + Sim_UtilCountPairsOnePrint( Vec_PtrEntry(p->vMatrSymms, i), Vec_VecEntry(p->vSupports, i) ); + printf( "\n" ); + } +p->timeCount += clock() - clk; +} + +/**Function************************************************************* + + Synopsis [Counts the number of entries in the array of matrices.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Sim_UtilCountPairsAll( Sym_Man_t * p ) +{ + int nPairsTotal, nPairsSym, nPairsNonSym, i, clk; +clk = clock(); + p->nPairsSymm = 0; + p->nPairsNonSymm = 0; + for ( i = 0; i < p->nOutputs; i++ ) + { + nPairsTotal = Vec_IntEntry(p->vPairsTotal, i); + nPairsSym = Vec_IntEntry(p->vPairsSym, i); + nPairsNonSym = Vec_IntEntry(p->vPairsNonSym,i); + assert( nPairsTotal >= nPairsSym + nPairsNonSym ); + if ( nPairsTotal == nPairsSym + nPairsNonSym ) + { + p->nPairsSymm += nPairsSym; + p->nPairsNonSymm += nPairsNonSym; + continue; + } + nPairsSym = Sim_UtilCountPairsOne( Vec_PtrEntry(p->vMatrSymms, i), Vec_VecEntry(p->vSupports, i) ); + nPairsNonSym = Sim_UtilCountPairsOne( Vec_PtrEntry(p->vMatrNonSymms,i), Vec_VecEntry(p->vSupports, i) ); + assert( nPairsTotal >= nPairsSym + nPairsNonSym ); + Vec_IntWriteEntry( p->vPairsSym, i, nPairsSym ); + Vec_IntWriteEntry( p->vPairsNonSym, i, nPairsNonSym ); + p->nPairsSymm += nPairsSym; + p->nPairsNonSymm += nPairsNonSym; +// printf( "%d ", nPairsTotal - nPairsSym - nPairsNonSym ); + } +//printf( "\n" ); + p->nPairsRem = p->nPairsTotal-p->nPairsSymm-p->nPairsNonSymm; +p->timeCount += clock() - clk; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Sim_UtilMatrsAreDisjoint( Sym_Man_t * p ) +{ + int i; + for ( i = 0; i < p->nOutputs; i++ ) + if ( !Extra_BitMatrixIsDisjoint( Vec_PtrEntry(p->vMatrSymms,i), Vec_PtrEntry(p->vMatrNonSymms,i) ) ) + return 0; + return 1; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + -- cgit v1.2.3