/**CFile**************************************************************** FileName [fretInit.c] SystemName [ABC: Logic synthesis and verification system.] PackageName [Flow-based retiming package.] Synopsis [Initialization for retiming package.] Author [Aaron Hurst] Affiliation [UC Berkeley] Date [Ver. 1.0. Started - January 1, 2008.] Revision [$Id: fretInit.c,v 1.00 2008/01/01 00:00:00 ahurst Exp $] ***********************************************************************/ #include "abc.h" #include "vec.h" #include "ioAbc.h" #include "fretime.h" #include "mio.h" #include "hop.h" #undef DEBUG_PRINT_INIT_NTK //////////////////////////////////////////////////////////////////////// /// FUNCTION PROTOTYPES /// //////////////////////////////////////////////////////////////////////// static void Abc_FlowRetime_UpdateForwardInit_rec( Abc_Obj_t * pObj ); static void Abc_FlowRetime_VerifyBackwardInit( Abc_Ntk_t * pNtk ); static void Abc_FlowRetime_VerifyBackwardInit_rec( Abc_Obj_t * pObj ); static Abc_Obj_t* Abc_FlowRetime_UpdateBackwardInit_rec( Abc_Obj_t *pOrigObj ); static void Abc_FlowRetime_SimulateNode( Abc_Obj_t * pObj ); static void Abc_FlowRetime_SimulateSop( Abc_Obj_t * pObj, char *pSop ); static void Abc_FlowRetime_SetInitToOrig( Abc_Obj_t *pInit, Abc_Obj_t *pOrig ); static void Abc_FlowRetime_GetInitToOrig( Abc_Obj_t *pInit, Abc_Obj_t **pOrig, int *lag ); static void Abc_FlowRetime_ClearInitToOrig( Abc_Obj_t *pInit ); extern void * Abc_FrameReadLibGen(); extern void Abc_NtkMarkCone_rec( Abc_Obj_t * pObj, int fForward ); //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// /**Function************************************************************* Synopsis [Updates initial state information.] Description [Assumes latch boxes in original position, latches in new positions.] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_FlowRetime_InitState( Abc_Ntk_t * pNtk ) { if (!pManMR->fComputeInitState) return; if (pManMR->fIsForward) Abc_FlowRetime_UpdateForwardInit( pNtk ); else { Abc_FlowRetime_UpdateBackwardInit( pNtk ); } } /**Function************************************************************* Synopsis [Prints initial state information.] Description [Prints distribution of 0,1,and X initial states.] SideEffects [] SeeAlso [] ***********************************************************************/ inline int Abc_FlowRetime_ObjFirstNonLatchBox( Abc_Obj_t * pOrigObj, Abc_Obj_t ** pResult ) { int lag = 0; Abc_Ntk_t *pNtk; *pResult = pOrigObj; pNtk = Abc_ObjNtk( pOrigObj ); Abc_NtkIncrementTravId( pNtk ); while( Abc_ObjIsBo(*pResult) || Abc_ObjIsLatch(*pResult) || Abc_ObjIsBi(*pResult) ) { assert(Abc_ObjFaninNum(*pResult)); *pResult = Abc_ObjFanin0(*pResult); if (Abc_NodeIsTravIdCurrent(*pResult)) return -1; Abc_NodeSetTravIdCurrent(*pResult); if (Abc_ObjIsLatch(*pResult)) ++lag; } return lag; } /**Function************************************************************* Synopsis [Prints initial state information.] Description [Prints distribution of 0,1,and X initial states.] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_FlowRetime_PrintInitStateInfo( Abc_Ntk_t * pNtk ) { int i, n0=0, n1=0, nDC=0, nOther=0; Abc_Obj_t *pLatch; Abc_NtkForEachLatch( pNtk, pLatch, i ) { if (Abc_LatchIsInit0(pLatch)) n0++; else if (Abc_LatchIsInit1(pLatch)) n1++; else if (Abc_LatchIsInitDc(pLatch)) nDC++; else nOther++; } printf("\tinitial states {0,1,x} = {%d, %d, %d}", n0, n1, nDC); if (nOther) printf(" + %d UNKNOWN", nOther); printf("\n"); } /**Function************************************************************* Synopsis [Computes initial state after forward retiming.] Description [Assumes box outputs in old positions stored w/ init values. Uses three-value simulation to preserve don't cares.] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_FlowRetime_UpdateForwardInit( Abc_Ntk_t * pNtk ) { Abc_Obj_t *pObj, *pFanin; int i; vprintf("\t\tupdating init state\n"); Abc_NtkIncrementTravId( pNtk ); Abc_NtkForEachLatch( pNtk, pObj, i ) { pFanin = Abc_ObjFanin0(pObj); Abc_FlowRetime_UpdateForwardInit_rec( pFanin ); if (FTEST(pFanin, INIT_0)) Abc_LatchSetInit0( pObj ); else if (FTEST(pFanin, INIT_1)) Abc_LatchSetInit1( pObj ); else Abc_LatchSetInitDc( pObj ); } } void Abc_FlowRetime_UpdateForwardInit_rec( Abc_Obj_t * pObj ) { Abc_Obj_t *pNext; int i; assert(!Abc_ObjIsPi(pObj)); // should never reach the inputs if (Abc_ObjIsBo(pObj)) return; // visited? if (Abc_NodeIsTravIdCurrent(pObj)) return; Abc_NodeSetTravIdCurrent(pObj); Abc_ObjForEachFanin( pObj, pNext, i ) { Abc_FlowRetime_UpdateForwardInit_rec( pNext ); } Abc_FlowRetime_SimulateNode( pObj ); } /**Function************************************************************* Synopsis [Recursively evaluates HOP netlist.] Description [Exponential. There aren't enough flags on a HOP node.] SideEffects [] SeeAlso [] ***********************************************************************/ static void Abc_FlowRetime_EvalHop_rec( Hop_Man_t *pHop, Hop_Obj_t *pObj, int *f, int *dc ) { int f1, dc1, f2, dc2; Hop_Obj_t *pReg = Hop_Regular(pObj); // const 0 if (Hop_ObjIsConst1(pReg)) { *f = 1; *f ^= (pReg == pObj ? 1 : 0); *dc = 0; return; } // PI if (Hop_ObjIsPi(pReg)) { *f = pReg->fMarkA; *f ^= (pReg == pObj ? 1 : 0); *dc = pReg->fMarkB; return; } // PO if (Hop_ObjIsPo(pReg)) { assert( pReg == pObj ); Abc_FlowRetime_EvalHop_rec(pHop, Hop_ObjChild0(pReg), f, dc); return; } // AND if (Hop_ObjIsAnd(pReg)) { Abc_FlowRetime_EvalHop_rec(pHop, Hop_ObjChild0(pReg), &f1, &dc1); Abc_FlowRetime_EvalHop_rec(pHop, Hop_ObjChild1(pReg), &f2, &dc2); *dc = (dc1 & f2) | (dc2 & f1) | (dc1 & dc2); *f = f1 & f2; *f ^= (pReg == pObj ? 1 : 0); return; } assert(0); } /**Function************************************************************* Synopsis [Sets initial value flags.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ static inline void Abc_FlowRetime_SetInitValue( Abc_Obj_t * pObj, int val, int dc ) { // store init value FUNSET(pObj, INIT_CARE); if (!dc){ if (val) { FSET(pObj, INIT_1); } else { FSET(pObj, INIT_0); } } } /**Function************************************************************* Synopsis [Propogates initial state through a logic node.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_FlowRetime_SimulateNode( Abc_Obj_t * pObj ) { Abc_Ntk_t *pNtk = Abc_ObjNtk(pObj); Abc_Obj_t * pFanin; int i, rAnd, rVar, dcAnd, dcVar; DdManager * dd = pNtk->pManFunc; DdNode *pBdd = pObj->pData, *pVar; Hop_Man_t *pHop = pNtk->pManFunc; assert(!Abc_ObjIsLatch(pObj)); assert(Abc_ObjRegular(pObj)); // (i) constant nodes if (Abc_NtkIsStrash(pNtk) && Abc_AigNodeIsConst(pObj)) { Abc_FlowRetime_SetInitValue(pObj, 1, 0); return; } if (!Abc_NtkIsStrash( pNtk ) && Abc_ObjIsNode(pObj)) { if (Abc_NodeIsConst0(pObj)) { Abc_FlowRetime_SetInitValue(pObj, 0, 0); return; } else if (Abc_NodeIsConst1(pObj)) { Abc_FlowRetime_SetInitValue(pObj, 1, 0); return; } } // (ii) terminal nodes if (!Abc_ObjIsNode(pObj)) { pFanin = Abc_ObjFanin0(pObj); Abc_FlowRetime_SetInitValue(pObj, (FTEST(pFanin, INIT_1) ? 1 : 0) ^ pObj->fCompl0, !FTEST(pFanin, INIT_CARE)); return; } // (iii) logic nodes // ------ SOP network if ( Abc_NtkHasSop( pNtk )) { Abc_FlowRetime_SimulateSop( pObj, (char *)Abc_ObjData(pObj) ); return; } // ------ BDD network else if ( Abc_NtkHasBdd( pNtk )) { assert(dd); assert(pBdd); // cofactor for 0,1 inputs // do nothing for X values Abc_ObjForEachFanin(pObj, pFanin, i) { pVar = Cudd_bddIthVar( dd, i ); if (FTEST(pFanin, INIT_CARE)) { if (FTEST(pFanin, INIT_0)) pBdd = Cudd_Cofactor( dd, pBdd, Cudd_Not(pVar) ); else pBdd = Cudd_Cofactor( dd, pBdd, pVar ); } } // if function has not been reduced to // a constant, propagate an X rVar = (pBdd == Cudd_ReadOne(dd)); dcVar = !Cudd_IsConstant(pBdd); Abc_FlowRetime_SetInitValue(pObj, rVar, dcVar); return; } // ------ AIG logic network else if ( Abc_NtkHasAig( pNtk ) && !Abc_NtkIsStrash( pNtk )) { assert(Abc_ObjIsNode(pObj)); assert(pObj->pData); assert(Abc_ObjFaninNum(pObj) <= Hop_ManPiNum(pHop) ); // set vals at inputs Abc_ObjForEachFanin(pObj, pFanin, i) { Hop_ManPi(pHop, i)->fMarkA = FTEST(pFanin, INIT_1)?1:0; Hop_ManPi(pHop, i)->fMarkB = FTEST(pFanin, INIT_CARE)?1:0; } Abc_FlowRetime_EvalHop_rec( pHop, pObj->pData, &rVar, &dcVar ); Abc_FlowRetime_SetInitValue(pObj, rVar, dcVar); // clear flags Abc_ObjForEachFanin(pObj, pFanin, i) { Hop_ManPi(pHop, i)->fMarkA = 0; Hop_ManPi(pHop, i)->fMarkB = 0; } return; } // ------ strashed network else if ( Abc_NtkIsStrash( pNtk )) { assert(Abc_ObjType(pObj) == ABC_OBJ_NODE); dcAnd = 0, rAnd = 1; pFanin = Abc_ObjFanin0(pObj); dcAnd |= FTEST(pFanin, INIT_CARE) ? 0 : 1; rVar = FTEST(pFanin, INIT_0) ? 0 : 1; if (pObj->fCompl0) rVar ^= 1; // complimented? rAnd &= rVar; pFanin = Abc_ObjFanin1(pObj); dcAnd |= FTEST(pFanin, INIT_CARE) ? 0 : 1; rVar = FTEST(pFanin, INIT_0) ? 0 : 1; if (pObj->fCompl1) rVar ^= 1; // complimented? rAnd &= rVar; if (!rAnd) dcAnd = 0; /* controlling value */ Abc_FlowRetime_SetInitValue(pObj, rAnd, dcAnd); return; } // ------ MAPPED network else if ( Abc_NtkHasMapping( pNtk )) { Abc_FlowRetime_SimulateSop( pObj, (char *)Mio_GateReadSop(pObj->pData) ); return; } assert(0); } /**Function************************************************************* Synopsis [Propogates initial state through a SOP node.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_FlowRetime_SimulateSop( Abc_Obj_t * pObj, char *pSop ) { Abc_Obj_t * pFanin; char *pCube; int i, j, rAnd, rOr, rVar, dcAnd, dcOr, v; assert( pSop && !Abc_SopIsExorType(pSop) ); rOr = 0, dcOr = 0; i = Abc_SopGetVarNum(pSop); Abc_SopForEachCube( pSop, i, pCube ) { rAnd = 1, dcAnd = 0; Abc_CubeForEachVar( pCube, v, j ) { pFanin = Abc_ObjFanin(pObj, j); if ( v == '0' ) rVar = FTEST(pFanin, INIT_0) ? 1 : 0; else if ( v == '1' ) rVar = FTEST(pFanin, INIT_1) ? 1 : 0; else continue; if (FTEST(pFanin, INIT_CARE)) rAnd &= rVar; else dcAnd = 1; } if (!rAnd) dcAnd = 0; /* controlling value */ if (dcAnd) dcOr = 1; else rOr |= rAnd; } if (rOr) dcOr = 0; /* controlling value */ // complement the result if necessary if ( !Abc_SopGetPhase(pSop) ) rOr ^= 1; Abc_FlowRetime_SetInitValue(pObj, rOr, dcOr); } /**Function************************************************************* Synopsis [Sets up backward initial state computation.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_FlowRetime_SetupBackwardInit( Abc_Ntk_t * pNtk ) { Abc_Obj_t *pLatch, *pObj, *pPi; int i; Vec_Ptr_t *vObj = Vec_PtrAlloc(100); // create the network used for the initial state computation if (Abc_NtkIsStrash(pNtk)) { pManMR->pInitNtk = Abc_NtkAlloc( ABC_NTK_LOGIC, ABC_FUNC_SOP, 1 ); } else if (Abc_NtkHasMapping(pNtk)) pManMR->pInitNtk = Abc_NtkAlloc( pNtk->ntkType, ABC_FUNC_SOP, 1 ); else pManMR->pInitNtk = Abc_NtkAlloc( pNtk->ntkType, pNtk->ntkFunc, 1 ); // mitre inputs Abc_NtkForEachLatch( pNtk, pLatch, i ) { // map latch to initial state network pPi = Abc_NtkCreatePi( pManMR->pInitNtk ); // DEBUG // printf("setup : mapping latch %d to PI %d\n", pLatch->Id, pPi->Id); // has initial state requirement? if (Abc_LatchIsInit0(pLatch)) { pObj = Abc_NtkCreateNodeInv( pManMR->pInitNtk, pPi ); Vec_PtrPush(vObj, pObj); } else if (Abc_LatchIsInit1(pLatch)) { Vec_PtrPush(vObj, pPi); } Abc_ObjSetData( pLatch, pPi ); // if not verifying init state // FDATA(pLatch)->pInitObj = pPi; // if verifying init state } // are there any nodes not DC? if (!Vec_PtrSize(vObj)) { pManMR->fSolutionIsDc = 1; return; } else pManMR->fSolutionIsDc = 0; // mitre output // create n-input AND gate pObj = Abc_NtkCreateNodeAnd( pManMR->pInitNtk, vObj ); Abc_ObjAddFanin( Abc_NtkCreatePo( pManMR->pInitNtk ), pObj ); Vec_PtrFree( vObj ); } /**Function************************************************************* Synopsis [Solves backward initial state computation.] Description [] SideEffects [Sets object copies in init ntk.] SeeAlso [] ***********************************************************************/ int Abc_FlowRetime_SolveBackwardInit( Abc_Ntk_t * pNtk ) { int i; Abc_Obj_t *pObj, *pInitObj; Vec_Ptr_t *vDelete = Vec_PtrAlloc(0); Abc_Ntk_t *pSatNtk; int result; assert(pManMR->pInitNtk); // is the solution entirely DC's? if (pManMR->fSolutionIsDc) { Vec_PtrFree(vDelete); Abc_NtkForEachLatch( pNtk, pObj, i ) Abc_LatchSetInitDc( pObj ); vprintf("\tno init state computation: all-don't-care solution\n"); return 1; } // check that network is combinational Abc_NtkForEachObj( pManMR->pInitNtk, pObj, i ) { assert(!Abc_ObjIsLatch(pObj)); assert(!Abc_ObjIsBo(pObj)); assert(!Abc_ObjIsBi(pObj)); } // delete superfluous nodes while(Vec_PtrSize( vDelete )) { pObj = (Abc_Obj_t *)Vec_PtrPop( vDelete ); Abc_NtkDeleteObj( pObj ); } Vec_PtrFree(vDelete); // do some final cleanup on the network Abc_NtkAddDummyPoNames(pManMR->pInitNtk); Abc_NtkAddDummyPiNames(pManMR->pInitNtk); if (Abc_NtkIsLogic(pManMR->pInitNtk)) Abc_NtkCleanup(pManMR->pInitNtk, 0); #if defined(DEBUG_PRINT_INIT_NTK) Abc_NtkLevelReverse( pManMR->pInitNtk ); Abc_NtkForEachObj( pManMR->pInitNtk, pObj, i ) if (Abc_ObjLevel( pObj ) < 2) Abc_ObjPrint(stdout, pObj); #endif vprintf("\tsolving for init state (%d nodes)... ", Abc_NtkObjNum(pManMR->pInitNtk)); fflush(stdout); // convert SOPs to BDD if (Abc_NtkHasSop(pManMR->pInitNtk)) Abc_NtkSopToBdd( pManMR->pInitNtk ); // convert AIGs to BDD if (Abc_NtkHasAig(pManMR->pInitNtk)) Abc_NtkAigToBdd( pManMR->pInitNtk ); pSatNtk = pManMR->pInitNtk; // solve result = Abc_NtkMiterSat( pSatNtk, (sint64)500000, (sint64)50000000, 0, NULL, NULL ); if (!result) { vprintf("SUCCESS\n"); } else { vprintf("FAILURE\n"); return 0; } // clear initial values, associate PIs to latches Abc_NtkForEachPi( pManMR->pInitNtk, pInitObj, i ) Abc_ObjSetCopy( pInitObj, NULL ); Abc_NtkForEachLatch( pNtk, pObj, i ) { pInitObj = Abc_ObjData( pObj ); assert( Abc_ObjIsPi( pInitObj )); Abc_ObjSetCopy( pInitObj, pObj ); Abc_LatchSetInitNone( pObj ); // DEBUG // printf("solve : getting latch %d from PI %d\n", pObj->Id, pInitObj->Id); } // copy solution from PIs to latches assert(pManMR->pInitNtk->pModel); Abc_NtkForEachPi( pManMR->pInitNtk, pInitObj, i ) { if ((pObj = Abc_ObjCopy( pInitObj ))) { if ( pManMR->pInitNtk->pModel[i] ) Abc_LatchSetInit1( pObj ); else Abc_LatchSetInit0( pObj ); } } #if defined(DEBUG_CHECK) // check that all latches have initial state Abc_NtkForEachLatch( pNtk, pObj, i ) assert( !Abc_LatchIsInitNone( pObj ) ); #endif return 1; } /**Function************************************************************* Synopsis [Updates backward initial state computation problem.] Description [Assumes box outputs in old positions stored w/ init values.] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_FlowRetime_UpdateBackwardInit( Abc_Ntk_t * pNtk ) { Abc_Obj_t *pOrigObj, *pInitObj; Vec_Ptr_t *vBo = Vec_PtrAlloc(100); Vec_Ptr_t *vPi = Vec_PtrAlloc(100); Abc_Ntk_t *pInitNtk = pManMR-> pInitNtk; Abc_Obj_t *pBuf; int i; // remove PIs from network (from BOs) Abc_NtkForEachObj( pNtk, pOrigObj, i ) if (Abc_ObjIsBo(pOrigObj)) { pInitObj = FDATA(pOrigObj)->pInitObj; assert(Abc_ObjIsPi(pInitObj)); // DEBUG // printf("update : freeing PI %d\n", pInitObj->Id); // create a buffer instead pBuf = Abc_NtkCreateNodeBuf( pInitNtk, NULL ); Abc_FlowRetime_ClearInitToOrig( pBuf ); Abc_ObjBetterTransferFanout( pInitObj, pBuf, 0 ); FDATA(pOrigObj)->pInitObj = pBuf; pOrigObj->fMarkA = 1; Vec_PtrPush(vBo, pOrigObj); Vec_PtrPush(vPi, pInitObj); } // check that PIs are all free Abc_NtkForEachPi( pInitNtk, pInitObj, i) { assert( Abc_ObjFanoutNum( pInitObj ) == 0); } // add PIs to to latches Abc_NtkForEachLatch( pNtk, pOrigObj, i ) { assert(Vec_PtrSize(vPi) > 0); pInitObj = Vec_PtrPop(vPi); // DEBUG // printf("update : mapping latch %d to PI %d\n", pOrigObj->Id, pInitObj->Id); pOrigObj->fMarkA = pOrigObj->fMarkB = 1; FDATA(pOrigObj)->pInitObj = pInitObj; Abc_ObjSetData(pOrigObj, pInitObj); } // recursively build init network Vec_PtrForEachEntry( vBo, pOrigObj, i ) Abc_FlowRetime_UpdateBackwardInit_rec( pOrigObj ); // clear flags Abc_NtkForEachObj( pNtk, pOrigObj, i ) pOrigObj->fMarkA = pOrigObj->fMarkB = 0; // deallocate Vec_PtrFree( vBo ); Vec_PtrFree( vPi ); } /**Function************************************************************* Synopsis [Creates a corresponding node in the init state network] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Abc_Obj_t *Abc_FlowRetime_CopyNodeToInitNtk( Abc_Obj_t *pOrigObj ) { Abc_Ntk_t *pNtk = pManMR->pNtk; Abc_Ntk_t *pInitNtk = pManMR->pInitNtk; Abc_Obj_t *pInitObj; void *pData; int fCompl[2]; assert(pOrigObj); // what we do depends on the ntk types of original / init networks... // (0) convert BI/BO nodes to buffers if (Abc_ObjIsBi( pOrigObj ) || Abc_ObjIsBo( pOrigObj ) ) { pInitObj = Abc_NtkCreateNodeBuf( pInitNtk, NULL ); Abc_FlowRetime_ClearInitToOrig( pInitObj ); return pInitObj; } // (i) strash node -> SOP node if (Abc_NtkIsStrash( pNtk )) { if (Abc_AigNodeIsConst( pOrigObj )) { return Abc_NtkCreateNodeConst1( pInitNtk ); } if (!Abc_ObjIsNode( pOrigObj )) { assert(Abc_ObjFaninNum(pOrigObj) == 1); pInitObj = Abc_NtkCreateNodeBuf( pInitNtk, NULL ); Abc_FlowRetime_ClearInitToOrig( pInitObj ); return pInitObj; } assert( Abc_ObjIsNode(pOrigObj) ); pInitObj = Abc_NtkCreateObj( pInitNtk, ABC_OBJ_NODE ); fCompl[0] = pOrigObj->fCompl0 ? 1 : 0; fCompl[1] = pOrigObj->fCompl1 ? 1 : 0; pData = Abc_SopCreateAnd( pInitNtk->pManFunc, 2, fCompl ); assert(pData); pInitObj->pData = Abc_SopRegister( pInitNtk->pManFunc, pData ); } // (ii) mapped node -> SOP node else if (Abc_NtkHasMapping( pNtk )) { if (!pOrigObj->pData) { // assume terminal... assert(Abc_ObjFaninNum(pOrigObj) == 1); pInitObj = Abc_NtkCreateNodeBuf( pInitNtk, NULL ); Abc_FlowRetime_ClearInitToOrig( pInitObj ); return pInitObj; } pInitObj = Abc_NtkCreateObj( pInitNtk, Abc_ObjType(pOrigObj) ); pData = Mio_GateReadSop(pOrigObj->pData); assert( Abc_SopGetVarNum(pData) == Abc_ObjFaninNum(pOrigObj) ); pInitObj->pData = Abc_SopRegister( pInitNtk->pManFunc, pData ); } // (iii) otherwise, duplicate obj else { pInitObj = Abc_NtkDupObj( pInitNtk, pOrigObj, 0 ); // copy phase pInitObj->fPhase = pOrigObj->fPhase; } assert(pInitObj); return pInitObj; } /**Function************************************************************* Synopsis [Updates backward initial state computation problem.] Description [Creates a duplicate node in the initial state network corresponding to a node in the original circuit. If fRecurse is set, the procedure recurses on and connects the new node to its fan-ins. A latch in the original circuit corresponds to a PI in the initial state network. An existing PI may be supplied by pUseThisPi, and if the node is a latch, it will be used; otherwise the PI is saved in the list vOtherPis and subsequently used for another latch.] SideEffects [Nodes that have a corresponding initial state node are marked with fMarkA. Nodes that have been fully connected in the initial state network are marked with fMarkB.] SeeAlso [] ***********************************************************************/ Abc_Obj_t* Abc_FlowRetime_UpdateBackwardInit_rec( Abc_Obj_t *pOrigObj) { Abc_Obj_t *pOrigFanin, *pInitFanin, *pInitObj; int i; assert(pOrigObj); // should never reach primary IOs assert(!Abc_ObjIsPi(pOrigObj)); assert(!Abc_ObjIsPo(pOrigObj)); // skip bias nodes if (FTEST(pOrigObj, BIAS_NODE)) return NULL; // does an init node already exist? if(!pOrigObj->fMarkA) { pInitObj = Abc_FlowRetime_CopyNodeToInitNtk( pOrigObj ); Abc_FlowRetime_SetInitToOrig( pInitObj, pOrigObj ); FDATA(pOrigObj)->pInitObj = pInitObj; pOrigObj->fMarkA = 1; } else { pInitObj = FDATA(pOrigObj)->pInitObj; } assert(pInitObj); // have we already connected this object? if (!pOrigObj->fMarkB) { // create and/or connect fanins Abc_ObjForEachFanin( pOrigObj, pOrigFanin, i ) { // should not reach BOs (i.e. the start of the next frame) // the new latch bounday should lie before it assert(!Abc_ObjIsBo( pOrigFanin )); pInitFanin = Abc_FlowRetime_UpdateBackwardInit_rec( pOrigFanin ); Abc_ObjAddFanin( pInitObj, pInitFanin ); } pOrigObj->fMarkB = 1; } return pInitObj; } /**Function************************************************************* Synopsis [Verifies backward init state computation.] Description [This procedure requires the BOs to store the original latch values and the latches to store the new values: both in the INIT_0 and INIT_1 flags in the Flow_Data structure. (This is not currently the case in the rest of the code.) Also, can not verify backward state computations that span multiple combinational frames.] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_FlowRetime_VerifyBackwardInit( Abc_Ntk_t * pNtk ) { Abc_Obj_t *pObj, *pFanin; int i; vprintf("\t\tupdating init state\n"); Abc_NtkIncrementTravId( pNtk ); Abc_NtkForEachObj( pNtk, pObj, i ) if (Abc_ObjIsBo( pObj )) { pFanin = Abc_ObjFanin0(pObj); Abc_FlowRetime_VerifyBackwardInit_rec( pFanin ); if (FTEST(pObj, INIT_CARE)) { if(FTEST(pObj, INIT_CARE) != FTEST(pFanin, INIT_CARE)) { printf("ERROR: expected val=%d care=%d and got val=%d care=%d\n", FTEST(pObj, INIT_1)?1:0, FTEST(pObj, INIT_CARE)?1:0, FTEST(pFanin, INIT_1)?1:0, FTEST(pFanin, INIT_CARE)?1:0 ); } } } } void Abc_FlowRetime_VerifyBackwardInit_rec( Abc_Obj_t * pObj ) { Abc_Obj_t *pNext; int i; assert(!Abc_ObjIsBo(pObj)); // should never reach the inputs assert(!Abc_ObjIsPi(pObj)); // should never reach the inputs // visited? if (Abc_NodeIsTravIdCurrent(pObj)) return; Abc_NodeSetTravIdCurrent(pObj); if (Abc_ObjIsLatch(pObj)) { FUNSET(pObj, INIT_CARE); if (Abc_LatchIsInit0(pObj)) FSET(pObj, INIT_0); else if (Abc_LatchIsInit1(pObj)) FSET(pObj, INIT_1); return; } Abc_ObjForEachFanin( pObj, pNext, i ) { Abc_FlowRetime_VerifyBackwardInit_rec( pNext ); } Abc_FlowRetime_SimulateNode( pObj ); } /**Function************************************************************* Synopsis [Constrains backward retiming for initializability.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ bool Abc_FlowRetime_PartialSat(Vec_Ptr_t *vNodes, int cut) { Abc_Ntk_t *pPartNtk, *pInitNtk = pManMR->pInitNtk; Abc_Obj_t *pObj, *pNext, *pPartObj, *pPartNext, *pPo; int i, j, result; assert( Abc_NtkPoNum( pInitNtk ) == 1 ); pPartNtk = Abc_NtkAlloc( pInitNtk->ntkType, pInitNtk->ntkFunc, 0 ); // copy network Vec_PtrForEachEntry( vNodes, pObj, i ) { pObj->Level = i; assert(!Abc_ObjIsPo( pObj )); if (i < cut && !pObj->fMarkA) { pPartObj = Abc_NtkCreatePi( pPartNtk ); Abc_ObjSetCopy( pObj, pPartObj ); } else { // copy node pPartObj = Abc_NtkDupObj( pPartNtk, pObj, 0 ); // copy complementation pPartObj->fPhase = pObj->fPhase; // connect fanins Abc_ObjForEachFanin( pObj, pNext, j ) { pPartNext = Abc_ObjCopy( pNext ); assert(pPartNext); Abc_ObjAddFanin( pPartObj, pPartNext ); } } assert(pObj->pCopy == pPartObj); } // create PO pPo = Abc_NtkCreatePo( pPartNtk ); pNext = Abc_ObjFanin0( Abc_NtkPo( pInitNtk, 0 ) ); pPartNext = Abc_ObjCopy( pNext ); assert( pPartNext ); Abc_ObjAddFanin( pPo, pPartNext ); // check network #if defined(DEBUG_CHECK) Abc_NtkAddDummyPoNames(pPartNtk); Abc_NtkAddDummyPiNames(pPartNtk); Abc_NtkCheck( pPartNtk ); #endif result = Abc_NtkMiterSat( pPartNtk, (sint64)500000, (sint64)50000000, 0, NULL, NULL ); Abc_NtkDelete( pPartNtk ); return !result; } /**Function************************************************************* Synopsis [Constrains backward retiming for initializability.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_FlowRetime_ConstrainInit( ) { Vec_Ptr_t *vNodes; int low, high, mid; int i, n, lag; Abc_Obj_t *pObj = NULL, *pOrigObj; InitConstraint_t *pConstraint = ALLOC( InitConstraint_t, 1 ); memset( pConstraint, 0, sizeof(InitConstraint_t) ); assert(pManMR->pInitNtk); vprintf("\tsearch for initial state conflict...\n"); vNodes = Abc_NtkDfs(pManMR->pInitNtk, 0); n = Vec_PtrSize(vNodes); // also add PIs to vNodes Abc_NtkForEachPi(pManMR->pInitNtk, pObj, i) Vec_PtrPush(vNodes, pObj); Vec_PtrReorder(vNodes, n); #if defined(DEBUG_CHECK) assert(!Abc_FlowRetime_PartialSat( vNodes, 0 )); #endif // grow initialization constraint do { vprintf("\t\t"); // find element to add to set... low = 0, high = Vec_PtrSize(vNodes); while (low != high-1) { mid = (low + high) >> 1; if (!Abc_FlowRetime_PartialSat( vNodes, mid )) { low = mid; vprintf("-"); } else { high = mid; vprintf("*"); } fflush(stdout); } #if defined(DEBUG_CHECK) assert(Abc_FlowRetime_PartialSat( vNodes, high )); assert(!Abc_FlowRetime_PartialSat( vNodes, low )); #endif // mark its TFO pObj = Vec_PtrEntry( vNodes, low ); Abc_NtkMarkCone_rec( pObj, 1 ); vprintf(" conflict term = %d ", low); #if 0 printf("init ------\n"); Abc_ObjPrint(stdout, pObj); printf("\n"); Abc_ObjPrintNeighborhood( pObj, 1 ); printf("------\n"); #endif // add node to constraint Abc_FlowRetime_GetInitToOrig( pObj, &pOrigObj, &lag ); assert(pOrigObj); vprintf(" <=> %d/%d\n", Abc_ObjId(pOrigObj), lag); #if 0 printf("orig ------\n"); Abc_ObjPrint(stdout, pOrigObj); printf("\n"); Abc_ObjPrintNeighborhood( pOrigObj, 1 ); printf("------\n"); #endif Vec_IntPush( &pConstraint->vNodes, Abc_ObjId(pOrigObj) ); Vec_IntPush( &pConstraint->vLags, lag ); } while (Abc_FlowRetime_PartialSat( vNodes, Vec_PtrSize(vNodes) )); pConstraint->pBiasNode = NULL; // add constraint Vec_PtrPush( pManMR->vInitConstraints, pConstraint ); // clear marks Abc_NtkForEachObj( pManMR->pInitNtk, pObj, i) pObj->fMarkA = 0; // free Vec_PtrFree( vNodes ); } /**Function************************************************************* Synopsis [Removes nodes to bias against uninitializable cuts.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_FlowRetime_RemoveInitBias( ) { // Abc_Ntk_t *pNtk = pManMR->pNtk; Abc_Obj_t *pBiasNode; InitConstraint_t *pConstraint; int i; Vec_PtrForEachEntry( pManMR->vInitConstraints, pConstraint, i ) { pBiasNode = pConstraint->pBiasNode; pConstraint->pBiasNode = NULL; if (pBiasNode) Abc_NtkDeleteObj(pBiasNode); } } /**Function************************************************************* Synopsis [Connects the bias node to one of the constraint vertices.] Description [ACK! Currently this is dumb dumb hack. What should we do with biases that belong on BOs? These move through the circuit. Currently, the bias gets marked on the fan-in of BO and the bias gets implemented on every BO fan-out of a node.] SideEffects [] SeeAlso [] ***********************************************************************/ static void Abc_FlowRetime_ConnectBiasNode(Abc_Obj_t *pBiasNode, Abc_Obj_t *pObj, int biasLag) { Abc_Obj_t *pCur, *pNext; int i; int lag; Vec_Ptr_t *vNodes = Vec_PtrAlloc(1); Vec_Int_t *vLags = Vec_IntAlloc(1); Abc_Ntk_t *pNtk = Abc_ObjNtk( pObj ); Vec_PtrPush( vNodes, pObj ); Vec_IntPush( vLags, 0 ); Abc_NtkIncrementTravId( pNtk ); while (Vec_PtrSize( vNodes )) { pCur = Vec_PtrPop( vNodes ); lag = Vec_IntPop( vLags ); if (Abc_NodeIsTravIdCurrent( pCur )) continue; Abc_NodeSetTravIdCurrent( pCur ); if (!Abc_ObjIsLatch(pCur) && !Abc_ObjIsBo(pCur) && Abc_FlowRetime_GetLag(pObj)+lag == biasLag ) { // printf("biasing : "); // Abc_ObjPrint(stdout, pCur ); #if 1 FSET( pCur, BLOCK ); #else Abc_ObjAddFanin( pCur, pBiasNode ); #endif } Abc_ObjForEachFanout( pCur, pNext, i ) { if (Abc_ObjIsBi(pNext) || Abc_ObjIsLatch(pNext) || Abc_ObjIsBo(pNext) || Abc_ObjIsBo(pCur)) { Vec_PtrPush( vNodes, pNext ); Vec_IntPush( vLags, lag - Abc_ObjIsLatch(pNext) ? 1 : 0 ); } } } Vec_PtrFree( vNodes ); Vec_IntFree( vLags ); } /**Function************************************************************* Synopsis [Adds nodes to bias against uninitializable cuts.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_FlowRetime_AddInitBias( ) { Abc_Ntk_t *pNtk = pManMR->pNtk; Abc_Obj_t *pBiasNode, *pObj; InitConstraint_t *pConstraint; int i, j, id; const int nConstraints = Vec_PtrSize( pManMR->vInitConstraints ); pManMR->pDataArray = REALLOC( Flow_Data_t, pManMR->pDataArray, pManMR->nNodes + (nConstraints*(pManMR->iteration+1)) ); memset(pManMR->pDataArray + pManMR->nNodes, 0, sizeof(Flow_Data_t)*(nConstraints*(pManMR->iteration+1))); vprintf("\t\tcreating %d bias structures\n", nConstraints); Vec_PtrForEachEntry( pManMR->vInitConstraints, pConstraint, i ) { if (pConstraint->pBiasNode) continue; // printf("\t\t\tbias %d...\n", i); pBiasNode = Abc_NtkCreateBlackbox( pNtk ); Vec_IntForEachEntry( &pConstraint->vNodes, id, j ) { pObj = Abc_NtkObj(pNtk, id); Abc_FlowRetime_ConnectBiasNode(pBiasNode, pObj, Vec_IntEntry(&pConstraint->vLags, j)); } // pConstraint->pBiasNode = pBiasNode; } } /**Function************************************************************* Synopsis [Clears mapping from init node to original node.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_FlowRetime_ClearInitToOrig( Abc_Obj_t *pInit ) { int id = Abc_ObjId( pInit ); // grow data structure if necessary if (id >= pManMR->sizeInitToOrig) { int oldSize = pManMR->sizeInitToOrig; pManMR->sizeInitToOrig = 1.5*id + 10; pManMR->pInitToOrig = realloc(pManMR->pInitToOrig, sizeof(NodeLag_t)*pManMR->sizeInitToOrig); memset( &(pManMR->pInitToOrig[oldSize]), 0, sizeof(NodeLag_t)*(pManMR->sizeInitToOrig-oldSize) ); } assert( pManMR->pInitToOrig ); pManMR->pInitToOrig[id].id = -1; } /**Function************************************************************* Synopsis [Sets mapping from init node to original node.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_FlowRetime_SetInitToOrig( Abc_Obj_t *pInit, Abc_Obj_t *pOrig) { int lag; int id = Abc_ObjId( pInit ); // grow data structure if necessary if (id >= pManMR->sizeInitToOrig) { int oldSize = pManMR->sizeInitToOrig; pManMR->sizeInitToOrig = 1.5*id + 10; pManMR->pInitToOrig = realloc(pManMR->pInitToOrig, sizeof(NodeLag_t)*pManMR->sizeInitToOrig); memset( &(pManMR->pInitToOrig[oldSize]), 0, sizeof(NodeLag_t)*(pManMR->sizeInitToOrig-oldSize) ); } assert( pManMR->pInitToOrig ); // ignore BI, BO, and latch nodes if (Abc_ObjIsBo(pOrig) || Abc_ObjIsBi(pOrig) || Abc_ObjIsLatch(pOrig)) { Abc_FlowRetime_ClearInitToOrig(pInit); return; } // move out of latch boxes lag = Abc_FlowRetime_ObjFirstNonLatchBox(pOrig, &pOrig); pManMR->pInitToOrig[id].id = Abc_ObjId(pOrig); pManMR->pInitToOrig[id].lag = Abc_FlowRetime_GetLag(pOrig) + lag; } /**Function************************************************************* Synopsis [Gets mapping from init node to original node.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_FlowRetime_GetInitToOrig( Abc_Obj_t *pInit, Abc_Obj_t **pOrig, int *lag ) { int id = Abc_ObjId( pInit ); int origId; assert(id < pManMR->sizeInitToOrig); origId = pManMR->pInitToOrig[id].id; if (origId < 0) { assert(Abc_ObjFaninNum(pInit)); Abc_FlowRetime_GetInitToOrig( Abc_ObjFanin0(pInit), pOrig, lag); return; } *pOrig = Abc_NtkObj(pManMR->pNtk, origId); *lag = pManMR->pInitToOrig[id].lag; }