/**Function************************************************************* Synopsis [Converts the network from AIG to BDD representation.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_MfsConvertHopToAig( Abc_Obj_t * pObjOld, Aig_Man_t * pMan ) { Hop_Man_t * pHopMan; Hop_Obj_t * pRoot; Abc_Obj_t * pFanin; int i; // get the local AIG pHopMan = (Hop_Man_t *)pObjOld->pNtk->pManFunc; pRoot = (Hop_Obj_t *)pObjOld->pData; // check the case of a constant if ( Hop_ObjIsConst1( Hop_Regular(pRoot) ) ) { pObjOld->pCopy = (Abc_Obj_t *)Aig_NotCond( Aig_ManConst1(pMan), Hop_IsComplement(pRoot) ); pObjOld->pNext = pObjOld->pCopy; return; } // assign the fanin nodes Abc_ObjForEachFanin( pObjOld, pFanin, i ) Hop_ManPi(pHopMan, i)->pData = pFanin->pCopy; // construct the AIG Abc_MfsConvertHopToAig_rec( Hop_Regular(pRoot), pMan ); pObjOld->pCopy = (Abc_Obj_t *)Aig_NotCond( (Aig_Obj_t *)Hop_Regular(pRoot)->pData, Hop_IsComplement(pRoot) ); Hop_ConeUnmark_rec( Hop_Regular(pRoot) ); // assign the fanin nodes Abc_ObjForEachFanin( pObjOld, pFanin, i ) Hop_ManPi(pHopMan, i)->pData = pFanin->pNext; // construct the AIG Abc_MfsConvertHopToAig_rec( Hop_Regular(pRoot), pMan ); pObjOld->pNext = (Abc_Obj_t *)Aig_NotCond( (Aig_Obj_t *)Hop_Regular(pRoot)->pData, Hop_IsComplement(pRoot) ); Hop_ConeUnmark_rec( Hop_Regular(pRoot) ); }
/**Function************************************************************* Synopsis [Transform the netlist into a logic network.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Abc_Ntk_t * Abc_NtkToLogic( Abc_Ntk_t * pNtk ) { Abc_Ntk_t * pNtkNew; Abc_Obj_t * pObj, * pFanin; int i, k; // consider the case of the AIG if ( Abc_NtkIsStrash(pNtk) ) return Abc_NtkAigToLogicSop( pNtk ); assert( Abc_NtkIsNetlist(pNtk) ); // consider simple case when there is hierarchy // assert( pNtk->pDesign == NULL ); assert( Abc_NtkWhiteboxNum(pNtk) == 0 ); assert( Abc_NtkBlackboxNum(pNtk) == 0 ); // start the network pNtkNew = Abc_NtkStartFrom( pNtk, ABC_NTK_LOGIC, pNtk->ntkFunc ); // duplicate the nodes Abc_NtkForEachNode( pNtk, pObj, i ) Abc_NtkDupObj(pNtkNew, pObj, 0); // reconnect the internal nodes in the new network Abc_NtkForEachNode( pNtk, pObj, i ) Abc_ObjForEachFanin( pObj, pFanin, k ) Abc_ObjAddFanin( pObj->pCopy, Abc_ObjFanin0(pFanin)->pCopy ); // collect the CO nodes Abc_NtkFinalize( pNtk, pNtkNew ); // fix the problem with CO pointing directly to CIs Abc_NtkLogicMakeSimpleCos( pNtkNew, 0 ); // duplicate EXDC if ( pNtk->pExdc ) pNtkNew->pExdc = Abc_NtkToLogic( pNtk->pExdc ); if ( !Abc_NtkCheck( pNtkNew ) ) fprintf( stdout, "Abc_NtkToLogic(): Network check has failed.\n" ); return pNtkNew; }
/**Function************************************************************* Synopsis [Write one network.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Io_NtkWriteEqnOne( FILE * pFile, Abc_Ntk_t * pNtk ) { Vec_Vec_t * vLevels; ProgressBar * pProgress; Abc_Obj_t * pNode, * pFanin; int i, k; // write the PIs fprintf( pFile, "INORDER =" ); Io_NtkWriteEqnCis( pFile, pNtk ); fprintf( pFile, ";\n" ); // write the POs fprintf( pFile, "OUTORDER =" ); Io_NtkWriteEqnCos( pFile, pNtk ); fprintf( pFile, ";\n" ); // write each internal node vLevels = Vec_VecAlloc( 10 ); pProgress = Extra_ProgressBarStart( stdout, Abc_NtkObjNumMax(pNtk) ); Abc_NtkForEachNode( pNtk, pNode, i ) { Extra_ProgressBarUpdate( pProgress, i, NULL ); fprintf( pFile, "%s = ", Abc_ObjName(Abc_ObjFanout0(pNode)) ); // set the input names Abc_ObjForEachFanin( pNode, pFanin, k ) Hop_IthVar((Hop_Man_t *)pNtk->pManFunc, k)->pData = Abc_ObjName(pFanin); // write the formula Hop_ObjPrintEqn( pFile, (Hop_Obj_t *)pNode->pData, vLevels, 0 ); fprintf( pFile, ";\n" ); }
ABC_NAMESPACE_IMPL_START //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// /**Function************************************************************* Synopsis [Converts old ABC network into new ABC network.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Nwk_Man_t * Abc_NtkToNtkNew( Abc_Ntk_t * pNtk ) { Vec_Ptr_t * vNodes; Nwk_Man_t * pNtkNew; Nwk_Obj_t * pObjNew; Abc_Obj_t * pObj, * pFanin; int i, k; if ( !Abc_NtkIsLogic(pNtk) ) { fprintf( stdout, "This is not a logic network.\n" ); return 0; } // convert into the AIG if ( !Abc_NtkToAig(pNtk) ) { fprintf( stdout, "Converting to AIGs has failed.\n" ); return 0; } assert( Abc_NtkHasAig(pNtk) ); // construct the network pNtkNew = Nwk_ManAlloc(); pNtkNew->pName = Extra_UtilStrsav( pNtk->pName ); pNtkNew->pSpec = Extra_UtilStrsav( pNtk->pSpec ); Abc_NtkForEachCi( pNtk, pObj, i ) pObj->pCopy = (Abc_Obj_t *)Nwk_ManCreateCi( pNtkNew, Abc_ObjFanoutNum(pObj) ); vNodes = Abc_NtkDfs( pNtk, 1 ); Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i ) { pObjNew = Nwk_ManCreateNode( pNtkNew, Abc_ObjFaninNum(pObj), Abc_ObjFanoutNum(pObj) ); Abc_ObjForEachFanin( pObj, pFanin, k ) Nwk_ObjAddFanin( pObjNew, (Nwk_Obj_t *)pFanin->pCopy ); pObjNew->pFunc = Hop_Transfer( (Hop_Man_t *)pNtk->pManFunc, pNtkNew->pManHop, (Hop_Obj_t *)pObj->pData, Abc_ObjFaninNum(pObj) ); pObj->pCopy = (Abc_Obj_t *)pObjNew; }
/**Function************************************************************* Synopsis [Gets fanin node names.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Vec_Ptr_t * Abc_NodeGetFaninNames( Abc_Obj_t * pNode ) { Vec_Ptr_t * vNodes; Abc_Obj_t * pFanin; int i; vNodes = Vec_PtrAlloc( 100 ); Abc_ObjForEachFanin( pNode, pFanin, i ) Vec_PtrPush( vNodes, Abc_UtilStrsav(Abc_ObjName(pFanin)) ); return vNodes; }
ABC_NAMESPACE_IMPL_START //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// #ifdef ABC_USE_CUDD /**Function************************************************************* Synopsis [Reorders BDD of the local function of the node.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_NodeBddReorder( reo_man * p, Abc_Obj_t * pNode ) { Abc_Obj_t * pFanin; DdNode * bFunc; int * pOrder, i; // create the temporary array for the variable order pOrder = ABC_ALLOC( int, Abc_ObjFaninNum(pNode) ); for ( i = 0; i < Abc_ObjFaninNum(pNode); i++ ) pOrder[i] = -1; // reorder the BDD bFunc = Extra_Reorder( p, (DdManager *)pNode->pNtk->pManFunc, (DdNode *)pNode->pData, pOrder ); Cudd_Ref( bFunc ); Cudd_RecursiveDeref( (DdManager *)pNode->pNtk->pManFunc, (DdNode *)pNode->pData ); pNode->pData = bFunc; // update the fanin order Abc_ObjForEachFanin( pNode, pFanin, i ) pOrder[i] = pNode->vFanins.pArray[ pOrder[i] ]; Abc_ObjForEachFanin( pNode, pFanin, i ) pNode->vFanins.pArray[i] = pOrder[i]; ABC_FREE( pOrder ); }
/**Function************************************************************* Synopsis [Derives GIA manager using special pins to denote box boundaries.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Gia_Man_t * Abc_NtkTestPinDeriveGia( Abc_Ntk_t * pNtk, int fWhiteBoxOnly, int fVerbose ) { Gia_Man_t * pTemp; Gia_Man_t * pGia = NULL; Vec_Ptr_t * vNodes; Abc_Obj_t * pObj, * pFanin; int i, k, iPinLit = 0; // prepare logic network assert( Abc_NtkIsLogic(pNtk) ); Abc_NtkToAig( pNtk ); // construct GIA Abc_NtkFillTemp( pNtk ); pGia = Gia_ManStart( Abc_NtkObjNumMax(pNtk) ); Gia_ManHashAlloc( pGia ); // create primary inputs Abc_NtkForEachCi( pNtk, pObj, i ) pObj->iTemp = Gia_ManAppendCi(pGia); // create internal nodes in a topologic order from white boxes vNodes = Abc_NtkDfs( pNtk, 0 ); Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i ) { // input side if ( !fWhiteBoxOnly || Abc_NodeIsWhiteBox(pObj) ) { // create special pintype for this node iPinLit = Gia_ManAppendPinType( pGia, 1 ); // create input pins Abc_ObjForEachFanin( pObj, pFanin, k ) pFanin->iTemp = Gia_ManAppendAnd( pGia, pFanin->iTemp, iPinLit ); } // perform GIA construction pObj->iTemp = Abc_NtkTestTimNodeStrash( pGia, pObj ); // output side if ( !fWhiteBoxOnly || Abc_NodeIsWhiteBox(pObj) ) { // create special pintype for this node iPinLit = Gia_ManAppendPinType( pGia, 1 ); // create output pins pObj->iTemp = Gia_ManAppendAnd( pGia, pObj->iTemp, iPinLit ); } } Vec_PtrFree( vNodes ); // create primary outputs Abc_NtkForEachCo( pNtk, pObj, i ) pObj->iTemp = Gia_ManAppendCo( pGia, Abc_ObjFanin0(pObj)->iTemp ); // finalize GIA Gia_ManHashStop( pGia ); Gia_ManSetRegNum( pGia, 0 ); // clean up GIA pGia = Gia_ManCleanup( pTemp = pGia ); Gia_ManStop( pTemp ); return pGia; }
/**Function************************************************************* Synopsis [Collect nodes reachable from this box.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_NtkTestTimCollectCone_rec( Abc_Obj_t * pObj, Vec_Ptr_t * vNodes ) { Abc_Obj_t * pFanin; int i; if ( Abc_NodeIsTravIdCurrent( pObj ) ) return; Abc_NodeSetTravIdCurrent( pObj ); if ( Abc_ObjIsCi(pObj) ) return; assert( Abc_ObjIsNode( pObj ) ); Abc_ObjForEachFanin( pObj, pFanin, i ) Abc_NtkTestTimCollectCone_rec( pFanin, vNodes ); Vec_PtrPush( vNodes, pObj ); }
ABC_NAMESPACE_IMPL_START //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// /**Function************************************************************* Synopsis [Marks and collects the TFI cone of the node.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_MfsWinMarkTfi_rec( Abc_Obj_t * pObj, Vec_Ptr_t * vCone ) { Abc_Obj_t * pFanin; int i; if ( Abc_NodeIsTravIdCurrent(pObj) ) return; Abc_NodeSetTravIdCurrent( pObj ); if ( Abc_ObjIsCi(pObj) ) { Vec_PtrPush( vCone, pObj ); return; } assert( Abc_ObjIsNode(pObj) ); // visit the fanins of the node Abc_ObjForEachFanin( pObj, pFanin, i ) Abc_MfsWinMarkTfi_rec( pFanin, vCone ); Vec_PtrPush( vCone, pObj ); }
/**Function************************************************************* Synopsis [Derive BDD of the characteristic function.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ DdNode * Abc_ResBuildBdd( Abc_Ntk_t * pNtk, DdManager * dd ) { Vec_Ptr_t * vNodes, * vBdds, * vLocals; Abc_Obj_t * pObj, * pFanin; DdNode * bFunc, * bPart, * bTemp, * bVar; int i, k; assert( Abc_NtkIsSopLogic(pNtk) ); assert( Abc_NtkCoNum(pNtk) <= 3 ); vBdds = Vec_PtrStart( Abc_NtkObjNumMax(pNtk) ); Abc_NtkForEachCi( pNtk, pObj, i ) Vec_PtrWriteEntry( vBdds, Abc_ObjId(pObj), Cudd_bddIthVar(dd, i) ); // create internal node BDDs vNodes = Abc_NtkDfs( pNtk, 0 ); vLocals = Vec_PtrAlloc( 6 ); Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i ) { if ( Abc_ObjFaninNum(pObj) == 0 ) { bFunc = Cudd_NotCond( Cudd_ReadOne(dd), Abc_SopIsConst0((char *)pObj->pData) ); Cudd_Ref( bFunc ); Vec_PtrWriteEntry( vBdds, Abc_ObjId(pObj), bFunc ); continue; } Vec_PtrClear( vLocals ); Abc_ObjForEachFanin( pObj, pFanin, k ) Vec_PtrPush( vLocals, Vec_PtrEntry(vBdds, Abc_ObjId(pFanin)) ); bFunc = Abc_ConvertSopToBdd( dd, (char *)pObj->pData, (DdNode **)Vec_PtrArray(vLocals) ); Cudd_Ref( bFunc ); Vec_PtrWriteEntry( vBdds, Abc_ObjId(pObj), bFunc ); } Vec_PtrFree( vLocals ); // create char function bFunc = Cudd_ReadOne( dd ); Cudd_Ref( bFunc ); Abc_NtkForEachCo( pNtk, pObj, i ) { bVar = Cudd_bddIthVar( dd, i + Abc_NtkCiNum(pNtk) ); bTemp = (DdNode *)Vec_PtrEntry( vBdds, Abc_ObjFaninId0(pObj) ); bPart = Cudd_bddXnor( dd, bTemp, bVar ); Cudd_Ref( bPart ); bFunc = Cudd_bddAnd( dd, bTemp = bFunc, bPart ); Cudd_Ref( bFunc ); Cudd_RecursiveDeref( dd, bTemp ); Cudd_RecursiveDeref( dd, bPart ); }
/**Function************************************************************* Synopsis [Updates placement after one step of rewriting.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_PlaceUpdate( Vec_Ptr_t * vAddedCells, Vec_Ptr_t * vUpdatedNets ) { Abc_Obj_t * pObj, * pFanin; int i, k; Vec_Ptr_t * vCells, * vNets; // start the arrays of new cells and nets vCells = Vec_PtrAlloc( 16 ); vNets = Vec_PtrAlloc( 32 ); // go through the new nodes Vec_PtrForEachEntry( Abc_Obj_t *, vAddedCells, pObj, i ) { assert( !Abc_ObjIsComplement(pObj) ); Abc_PlaceCreateCell( pObj, 1 ); Abc_PlaceUpdateNet( pObj ); // add the new cell and its fanin nets to temporary storage Vec_PtrPush( vCells, &(cells[pObj->Id]) ); Abc_ObjForEachFanin( pObj, pFanin, k ) Vec_PtrPushUnique( vNets, &(nets[pFanin->Id]) ); }
int Abc_NtkTestTimNodeStrash( Gia_Man_t * pGia, Abc_Obj_t * pNode ) { Hop_Man_t * pMan; Hop_Obj_t * pRoot; Abc_Obj_t * pFanin; int i; assert( Abc_ObjIsNode(pNode) ); assert( Abc_NtkIsAigLogic(pNode->pNtk) ); // get the local AIG manager and the local root node pMan = (Hop_Man_t *)pNode->pNtk->pManFunc; pRoot = (Hop_Obj_t *)pNode->pData; // check the constant case if ( Abc_NodeIsConst(pNode) || Hop_Regular(pRoot) == Hop_ManConst1(pMan) ) return !Hop_IsComplement(pRoot); // set elementary variables Abc_ObjForEachFanin( pNode, pFanin, i ) Hop_IthVar(pMan, i)->iData = pFanin->iTemp; // strash the AIG of this node Abc_NtkTestTimNodeStrash_rec( pGia, Hop_Regular(pRoot) ); Hop_ConeUnmark_rec( Hop_Regular(pRoot) ); // return the final node with complement if needed return Abc_LitNotCond( Hop_Regular(pRoot)->iData, Hop_IsComplement(pRoot) ); }
/**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( Abc_Obj_t *, p->vLeaves, pObj, i ) pObj->pCopy = Abc_NtkCreatePi( pAig ); Vec_PtrForEachEntry( Abc_Obj_t *, p->vBranches, pObj, i ) pObj->pCopy = Abc_NtkCreatePi( pAig ); // go through the nodes in the topological order Vec_PtrForEachEntry( Abc_Obj_t *, 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( Abc_Obj_t *, 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( Abc_Obj_t *, p->vNodes, pObj, i ) { if ( Abc_NodeIsTravIdCurrent(pObj) ) pObj->pCopy = Abc_ConvertAigToAig( pAig, pObj ); } // collect the POs Vec_PtrForEachEntry( Abc_Obj_t *, p->vRoots, pObj, i ) Vec_PtrWriteEntry( vPairs, 2 * i + 1, pObj->pCopy ); // add the miter pMiter = Abc_AigMiter( (Abc_Aig_t *)pAig->pManFunc, vPairs, 0 ); 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( Abc_Obj_t *, 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; }
ABC_NAMESPACE_IMPL_START // For description of Binary BLIF format, refer to "abc/src/aig/bbl/bblif.h" //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// /**Fnction************************************************************* Synopsis [Construct manager from the ABC network.] Description [In the ABC network each object has a unique integer ID. This ID is used when we construct objects of the BBLIF manager corresponding to each object of the ABC network. The objects can be added to the manager in any order (although below they are added in the topological order), but by the time fanin/fanout connections are created, corresponding objects are already constructed. In the end the checking procedure is called.] SideEffects [] SeeAlso [] ***********************************************************************/ Bbl_Man_t * Bbl_ManFromAbc( Abc_Ntk_t * pNtk ) { Bbl_Man_t * p; Vec_Ptr_t * vNodes; Abc_Obj_t * pObj, * pFanin; int i, k; assert( Abc_NtkIsSopLogic(pNtk) ); // start the data manager p = Bbl_ManStart( Abc_NtkName(pNtk) ); // collect internal nodes to be added vNodes = Abc_NtkDfs( pNtk, 0 ); // create combinational inputs Abc_NtkForEachCi( pNtk, pObj, i ) Bbl_ManCreateObject( p, BBL_OBJ_CI, Abc_ObjId(pObj), 0, NULL ); // create internal nodes Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i ) Bbl_ManCreateObject( p, BBL_OBJ_NODE, Abc_ObjId(pObj), Abc_ObjFaninNum(pObj), (char *)pObj->pData ); // create combinational outputs Abc_NtkForEachCo( pNtk, pObj, i ) Bbl_ManCreateObject( p, BBL_OBJ_CO, Abc_ObjId(pObj), 1, NULL ); // create fanin/fanout connections for internal nodes Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i ) Abc_ObjForEachFanin( pObj, pFanin, k ) Bbl_ManAddFanin( p, Abc_ObjId(pObj), Abc_ObjId(pFanin) ); // create fanin/fanout connections for combinational outputs Abc_NtkForEachCo( pNtk, pObj, i ) Abc_ObjForEachFanin( pObj, pFanin, k ) Bbl_ManAddFanin( p, Abc_ObjId(pObj), Abc_ObjId(pFanin) ); Vec_PtrFree( vNodes ); // sanity check Bbl_ManCheck( p ); return p; }