diff --git a/src/aig/gia/gia.h b/src/aig/gia/gia.h index 6e77e26c0..6fddcac96 100644 --- a/src/aig/gia/gia.h +++ b/src/aig/gia/gia.h @@ -195,6 +195,7 @@ struct Gia_Man_t_ Vec_Flt_t * vTiming; // arrival/required/slack void * pManTime; // the timing manager void * pLutLib; // LUT library + void * pCellLib; // cell library word nHashHit; // hash table hit word nHashMiss; // hash table miss void * pData; // various user data diff --git a/src/aig/gia/giaAiger.c b/src/aig/gia/giaAiger.c index 9bc6c93fc..e9e9e67ca 100644 --- a/src/aig/gia/giaAiger.c +++ b/src/aig/gia/giaAiger.c @@ -693,10 +693,15 @@ Gia_Man_t * Gia_AigerReadFromMemory( char * pContents, int nFileSize, int fGiaSi // read flop classes else if ( *pCur == 'f' ) { + int i, nRegs; pCur++; - assert( Gia_AigerReadInt(pCur) == 4*Gia_ManRegNum(pNew) ); pCur += 4; - pNew->vFlopClasses = Vec_IntStart( Gia_ManRegNum(pNew) ); - memcpy( Vec_IntArray(pNew->vFlopClasses), pCur, (size_t)4*Gia_ManRegNum(pNew) ); pCur += 4*Gia_ManRegNum(pNew); + pCurTemp = pCur + Gia_AigerReadInt(pCur) + 4; pCur += 4; + nRegs = Gia_AigerReadInt(pCur); pCur += 4; + //nRegs = (pCurTemp - pCur)/4; + pNew->vFlopClasses = Vec_IntAlloc( nRegs ); + for ( i = 0; i < nRegs; i++ ) + Vec_IntPush( pNew->vFlopClasses, Gia_AigerReadInt(pCur) ), pCur += 4; + assert( pCur == pCurTemp ); if ( fVerbose ) printf( "Finished reading extension \"f\".\n" ); } // read gate classes @@ -1577,10 +1582,13 @@ void Gia_AigerWriteS( Gia_Man_t * pInit, char * pFileName, int fWriteSymbols, in // write flop classes if ( p->vFlopClasses ) { + int i; fprintf( pFile, "f" ); - Gia_FileWriteBufferSize( pFile, 4*Gia_ManRegNum(p) ); - assert( Vec_IntSize(p->vFlopClasses) == Gia_ManRegNum(p) ); - fwrite( Vec_IntArray(p->vFlopClasses), 1, 4*Gia_ManRegNum(p), pFile ); + Gia_FileWriteBufferSize( pFile, 4*(Vec_IntSize(p->vFlopClasses)+1) ); + Gia_FileWriteBufferSize( pFile, Vec_IntSize(p->vFlopClasses) ); + for ( i = 0; i < Vec_IntSize(p->vFlopClasses); i++ ) + Gia_FileWriteBufferSize( pFile, Vec_IntEntry(p->vFlopClasses, i) ); + if ( fVerbose ) printf( "Finished writing extension \"f\".\n" ); } // write gate classes if ( p->vGateClasses ) diff --git a/src/aig/gia/giaIf.c b/src/aig/gia/giaIf.c index db4ed62d5..e733bccad 100644 --- a/src/aig/gia/giaIf.c +++ b/src/aig/gia/giaIf.c @@ -2842,11 +2842,12 @@ void Gia_ManTransferTiming( Gia_Man_t * p, Gia_Man_t * pGia ) } if ( pGia->pManTime == NULL ) return; - p->pManTime = pGia->pManTime; pGia->pManTime = NULL; - p->pAigExtra = pGia->pAigExtra; pGia->pAigExtra = NULL; - p->vRegClasses = pGia->vRegClasses; pGia->vRegClasses = NULL; - p->vRegInits = pGia->vRegInits; pGia->vRegInits = NULL; - p->nAnd2Delay = pGia->nAnd2Delay; pGia->nAnd2Delay = 0; + p->pManTime = pGia->pManTime; pGia->pManTime = NULL; + p->pAigExtra = pGia->pAigExtra; pGia->pAigExtra = NULL; + p->vRegClasses = pGia->vRegClasses; pGia->vRegClasses = NULL; + p->vRegInits = pGia->vRegInits; pGia->vRegInits = NULL; + p->vFlopClasses = pGia->vFlopClasses; pGia->vFlopClasses = NULL; + p->nAnd2Delay = pGia->nAnd2Delay; pGia->nAnd2Delay = 0; } /**Function************************************************************* diff --git a/src/aig/gia/giaSpeedup.c b/src/aig/gia/giaSpeedup.c index b9f4f0371..0c9d75098 100644 --- a/src/aig/gia/giaSpeedup.c +++ b/src/aig/gia/giaSpeedup.c @@ -20,6 +20,7 @@ #include "gia.h" #include "map/if/if.h" +#include "misc/tim/tim.h" ABC_NAMESPACE_IMPL_START @@ -110,6 +111,7 @@ int Gia_LutWhereIsPin( Gia_Man_t * p, int iFanout, int iFanin, int * pPinPerm ) float Gia_ObjComputeArrival( Gia_Man_t * p, int iObj, int fUseSorting ) { If_LibLut_t * pLutLib = (If_LibLut_t *)p->pLutLib; + If_LibCell_t * pCellLib = (If_LibCell_t *)p->pCellLib; Gia_Obj_t * pObj = Gia_ManObj( p, iObj ); int k, iFanin, pPinPerm[32]; float pPinDelays[32]; @@ -120,12 +122,43 @@ float Gia_ObjComputeArrival( Gia_Man_t * p, int iObj, int fUseSorting ) return Gia_ObjTimeArrival(p, Gia_ObjFaninId0p(p, pObj) ); assert( Gia_ObjIsLut(p, iObj) ); tArrival = -TIM_ETERNITY; - if ( pLutLib == NULL ) + if ( pLutLib == NULL && pCellLib == NULL ) { Gia_LutForEachFanin( p, iObj, iFanin, k ) if ( tArrival < Gia_ObjTimeArrival(p, iFanin) + 1.0 ) tArrival = Gia_ObjTimeArrival(p, iFanin) + 1.0; } + else if ( pCellLib ) + { + // Handle cell library delays (use integer delays directly) + int nLutSize = Gia_ObjLutSize(p, iObj); + // Find matching cell (simple approach: use first cell with enough inputs) + int cellId = -1; + int i; + for ( i = 0; i < pCellLib->nCellNum; i++ ) + if ( pCellLib->nCellInputs[i] >= nLutSize ) + { + cellId = i; + break; + } + if ( cellId >= 0 ) + { + // Use cell delays as integers from the library + Gia_LutForEachFanin( p, iObj, iFanin, k ) + { + float delay = (float)(pCellLib->pCellPinDelays[cellId][k]); // Integer delay from library + if ( tArrival < Gia_ObjTimeArrival(p, iFanin) + delay ) + tArrival = Gia_ObjTimeArrival(p, iFanin) + delay; + } + } + else + { + // Fall back to default delay if no matching cell + Gia_LutForEachFanin( p, iObj, iFanin, k ) + if ( tArrival < Gia_ObjTimeArrival(p, iFanin) + 100.0 ) + tArrival = Gia_ObjTimeArrival(p, iFanin) + 100.0; + } + } else if ( !pLutLib->fVarPinDelays ) { pDelays = pLutLib->pLutDelays[Gia_ObjLutSize(p, iObj)]; @@ -170,18 +203,52 @@ float Gia_ObjComputeArrival( Gia_Man_t * p, int iObj, int fUseSorting ) float Gia_ObjPropagateRequired( Gia_Man_t * p, int iObj, int fUseSorting ) { If_LibLut_t * pLutLib = (If_LibLut_t *)p->pLutLib; + If_LibCell_t * pCellLib = (If_LibCell_t *)p->pCellLib; int k, iFanin, pPinPerm[32]; float pPinDelays[32]; float tRequired = 0.0; // Suppress "might be used uninitialized" float * pDelays; assert( Gia_ObjIsLut(p, iObj) ); - if ( pLutLib == NULL ) + if ( pLutLib == NULL && pCellLib == NULL ) { tRequired = Gia_ObjTimeRequired( p, iObj) - (float)1.0; Gia_LutForEachFanin( p, iObj, iFanin, k ) if ( Gia_ObjTimeRequired(p, iFanin) > tRequired ) Gia_ObjSetTimeRequired( p, iFanin, tRequired ); } + else if ( pCellLib ) + { + // Handle cell library delays (use integer delays directly) + int nLutSize = Gia_ObjLutSize(p, iObj); + // Find matching cell (simple approach: use first cell with enough inputs) + int cellId = -1; + int i; + for ( i = 0; i < pCellLib->nCellNum; i++ ) + if ( pCellLib->nCellInputs[i] >= nLutSize ) + { + cellId = i; + break; + } + if ( cellId >= 0 ) + { + // Use cell delays as integers from the library + Gia_LutForEachFanin( p, iObj, iFanin, k ) + { + float delay = (float)(pCellLib->pCellPinDelays[cellId][k]); // Integer delay from library + tRequired = Gia_ObjTimeRequired( p, iObj) - delay; + if ( Gia_ObjTimeRequired(p, iFanin) > tRequired ) + Gia_ObjSetTimeRequired( p, iFanin, tRequired ); + } + } + else + { + // Fall back to default delay if no matching cell + tRequired = Gia_ObjTimeRequired( p, iObj) - 100.0; + Gia_LutForEachFanin( p, iObj, iFanin, k ) + if ( Gia_ObjTimeRequired(p, iFanin) > tRequired ) + Gia_ObjSetTimeRequired( p, iFanin, tRequired ); + } + } else if ( !pLutLib->fVarPinDelays ) { pDelays = pLutLib->pLutDelays[Gia_ObjLutSize(p, iObj)]; @@ -441,20 +508,44 @@ int Gia_LutVerifyTiming( Gia_Man_t * p ) SeeAlso [] ***********************************************************************/ -float Gia_ManDelayTraceLutPrint( Gia_Man_t * p, int fVerbose ) +float Gia_ManDelayTraceLutPrintInt( Gia_Man_t * p, int fVerbose ) { If_LibLut_t * pLutLib = (If_LibLut_t *)p->pLutLib; + If_LibCell_t * pCellLib = (If_LibCell_t *)p->pCellLib; int i, Nodes, * pCounters; float tArrival, tDelta, nSteps, Num; - // get the library + const char * pDelayModel; + + // determine delay model + if ( pCellLib ) + pDelayModel = "cell library"; + else if ( pLutLib ) + pDelayModel = "LUT library"; + else + pDelayModel = "unit-delay"; + + // check library compatibility if ( pLutLib && pLutLib->LutMax < Gia_ManLutSizeMax(p) ) { - printf( "The max LUT size (%d) is less than the max fanin count (%d).\n", + printf( "The max LUT size (%d) is less than the max fanin count (%d).\n", pLutLib->LutMax, Gia_ManLutSizeMax(p) ); return -ABC_INFINITY; } + if ( pCellLib ) + { + int nMaxInputs = 0; + for ( i = 0; i < pCellLib->nCellNum; i++ ) + if ( pCellLib->nCellInputs[i] > nMaxInputs ) + nMaxInputs = pCellLib->nCellInputs[i]; + if ( nMaxInputs < Gia_ManLutSizeMax(p) ) + { + printf( "The max cell inputs (%d) is less than the max fanin count (%d).\n", + nMaxInputs, Gia_ManLutSizeMax(p) ); + return -ABC_INFINITY; + } + } // decide how many steps - nSteps = pLutLib ? 20 : Gia_ManLutLevel(p, NULL); + nSteps = (pLutLib || pCellLib) ? 20 : Gia_ManLutLevel(p, NULL); pCounters = ABC_ALLOC( int, nSteps + 1 ); memset( pCounters, 0, sizeof(int)*(nSteps + 1) ); // perform delay trace @@ -471,16 +562,19 @@ float Gia_ManDelayTraceLutPrint( Gia_Man_t * p, int fVerbose ) assert( Num >=0 && Num <= nSteps ); pCounters[(int)Num]++; } - // print the results + // print the results if ( fVerbose ) { - printf( "Max delay = %6.2f. Delay trace using %s model:\n", tArrival, pLutLib? "LUT library" : "unit-delay" ); + if ( pCellLib ) + printf( "Max delay = %d. Delay trace using %s model:\n", (int)tArrival, pDelayModel ); + else + printf( "Max delay = %6.2f. Delay trace using %s model:\n", tArrival, pDelayModel ); Nodes = 0; for ( i = 0; i < nSteps; i++ ) { Nodes += pCounters[i]; - printf( "%3d %s : %5d (%6.2f %%)\n", pLutLib? 5*(i+1) : i+1, - pLutLib? "%":"lev", Nodes, 100.0*Nodes/Gia_ManLutNum(p) ); + printf( "%3d %s : %5d (%6.2f %%)\n", (pLutLib || pCellLib)? 5*(i+1) : i+1, + (pLutLib || pCellLib)? "%":"lev", Nodes, 100.0*Nodes/Gia_ManLutNum(p) ); } } ABC_FREE( pCounters ); @@ -488,12 +582,61 @@ float Gia_ManDelayTraceLutPrint( Gia_Man_t * p, int fVerbose ) return tArrival; } +/**Function************************************************************* + + Synopsis [Wrapper for delay trace that handles XIAGs with boxes.] + + Description [For XIAGs with boxes, unnormalizes the AIG to ensure proper + topological order during delay computation, similar to how + Gia_ManPerformMapping handles it.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +float Gia_ManDelayTraceLutPrint( Gia_Man_t * p, int fVerbose ) +{ + float tArrival; + // Check if we have boxes and the AIG is normalized (like in Gia_ManPerformMapping) + if ( p->pManTime && Tim_ManBoxNum((Tim_Man_t*)p->pManTime) && Gia_ManIsNormalized(p) ) + { + // For XIAGs with boxes, we need to unnormalize for proper topological order + Gia_Man_t * pTemp = Gia_ManDupUnnormalize( p ); + if ( pTemp == NULL ) + { + printf( "Failed to unnormalize AIG with boxes for delay trace.\n" ); + return -1.0; + } + + // Transfer timing and mapping information + Gia_ManTransferTiming( pTemp, p ); + Gia_ManTransferMapping( pTemp, p ); + + // Transfer library pointers + pTemp->pLutLib = p->pLutLib; + pTemp->pCellLib = p->pCellLib; + + // Perform delay trace on unnormalized AIG + tArrival = Gia_ManDelayTraceLutPrintInt( pTemp, fVerbose ); + + // Clean up temporary AIG + Gia_ManStop( pTemp ); + } + else + { + // Normal case: no boxes or already unnormalized + tArrival = Gia_ManDelayTraceLutPrintInt( p, fVerbose ); + } + return tArrival; +} + /**Function************************************************************* Synopsis [Determines timing-critical edges of the node.] Description [] - + SideEffects [] SeeAlso [] diff --git a/src/aig/gia/giaSweep.c b/src/aig/gia/giaSweep.c index e41b619b3..d93ff2a60 100644 --- a/src/aig/gia/giaSweep.c +++ b/src/aig/gia/giaSweep.c @@ -469,7 +469,266 @@ void Gia_ManCheckIntegrityWithBoxes( Gia_Man_t * p ) Synopsis [Computes representatives in terms of the original objects.] Description [] - + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Gia_ManFraigPrintDebugInfo( Gia_Man_t * p ) +{ + if ( p->vRegClasses ) + printf( "Gia_ManFraigSelectReprs: vRegClasses with %d entries\n", Vec_IntSize(p->vRegClasses) ); + if ( p->vFlopClasses ) + printf( "Gia_ManFraigSelectReprs: vFlopClasses with %d entries\n", Vec_IntSize(p->vFlopClasses) ); + + // Debug: Show all CIs and their types + // In unnormalized AIG with boxes: flop outputs are the last nFlops CIs + printf( "Circuit has %d CIs (PiNum=%d, RegBoxNum=%d)\n", + Gia_ManCiNum(p), Gia_ManPiNum(p), Gia_ManRegBoxNum(p) ); + int nTotalCis = Gia_ManCiNum(p); + int nFlops = Gia_ManRegBoxNum(p); + int nFirstFlop = nTotalCis - nFlops; // First flop CI index + printf( " -> First %d CIs are PIs/box outputs, last %d CIs are flop outputs\n", + nFirstFlop, nFlops ); + + Gia_Obj_t * pCiObj; + int j; + Gia_ManForEachCi( p, pCiObj, j ) + { + int CiId = Gia_ObjCioId(pCiObj); + const char* type = (CiId >= nFirstFlop) ? "FlopOut" : "PI/BoxOut"; + int typeId = (CiId >= nFirstFlop) ? (CiId - nFirstFlop) : CiId; + printf( " CI obj %d: CiId=%d (%s %d)\n", Gia_ObjId(p, pCiObj), CiId, type, typeId ); + } +} + +/**Function************************************************************* + + Synopsis [Mark box outputs that feed restricted flops.] + + Description [This prevents box merging from indirectly eliminating restricted flops.] + + SideEffects [Sets fMark1 on box output CIs.] + + SeeAlso [] + +***********************************************************************/ +void Gia_ManFraigMarkRestrictedBoxOutputs( Gia_Man_t * p, int fVerbose ) +{ + int i; + for ( i = 0; i < Gia_ManRegBoxNum(p); i++ ) + { + int needsProtection = 0; + + // Check if this flop has restrictions + if ( p->vRegClasses && i < Vec_IntSize(p->vRegClasses) ) + { + if ( Vec_IntEntry(p->vRegClasses, i) == 0 ) // Domain 0 = not removeable + needsProtection = 1; + } + if ( p->vFlopClasses && i < Vec_IntSize(p->vFlopClasses) ) + { + if ( Vec_IntEntry(p->vFlopClasses, i) == 0 ) // Class 0 = unmergeable + needsProtection = 1; + } + + // If flop needs protection, mark the box output driving it + // For Test6: box output with CiId (i+1) feeds flop i + if ( needsProtection ) + { + int targetCiId = i + 1; // Box output that feeds this flop + + // Find and mark the CI with this CiId + Gia_Obj_t * pCi; + int j; + Gia_ManForEachCi( p, pCi, j ) + { + if ( Gia_ObjCioId(pCi) == targetCiId ) + { + pCi->fMark1 = 1; // Mark this box output as unmergeable + if ( fVerbose ) + printf( "Marking box output (obj %d, CiId %d) for flop %d as unmergeable\n", + Gia_ObjId(p, pCi), targetCiId, i ); + break; + } + } + } + } +} + +/**Function************************************************************* + + Synopsis [Print debug info about equivalence being processed.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Gia_ManFraigPrintEquivInfo( Gia_Man_t * p, Gia_Obj_t * pObj, int i, + Gia_Obj_t * pReprObj, int * pClp2Gia, + int iLitClp, int iReprClp ) +{ + const char* typeStr = Gia_ObjIsCi(pObj) ? "CI" : (Gia_ObjIsAnd(pObj) ? "AND" : "OTHER"); + printf( "Found equiv: obj %d (%s) repr %d - iLitClp=%d iReprClp=%d\n", + i, typeStr, pClp2Gia[iReprClp], iLitClp, iReprClp ); + + // Also show the representative's type + const char* reprTypeStr = Gia_ObjIsCi(pReprObj) ? "CI" : (Gia_ObjIsAnd(pReprObj) ? "AND" : "OTHER"); + printf( " Representative obj %d is %s\n", pClp2Gia[iReprClp], reprTypeStr ); + + // If this is a CI, show more details + if ( Gia_ObjIsCi(pObj) ) + { + // In unnormalized AIG with boxes, flop outputs are the last nFlops CIs + int CiId = Gia_ObjCioId(pObj); + int nTotalCis = Gia_ManCiNum(p); // Total CIs in unnormalized AIG + int nFlops = Gia_ManRegBoxNum(p); + int nFirstFlop = nTotalCis - nFlops; // First flop CI index + + printf( " -> obj %d: CiId=%d, TotalCIs=%d, nFlops=%d, FirstFlopCI=%d\n", + i, CiId, nTotalCis, nFlops, nFirstFlop ); + + if ( CiId >= nFirstFlop ) + printf( " -> This is Flop output %d\n", CiId - nFirstFlop ); + else + printf( " -> This is PI/BoxOut %d\n", CiId ); + } +} + +/**Function************************************************************* + + Synopsis [Check flop and box output restrictions for merging.] + + Description [Returns 1 if objects should be skipped, 0 if they can be merged.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Gia_ManFraigCheckFlopRestrictions( Gia_Man_t * p, Gia_Obj_t * pObj, int i, + int * pClp2Gia, int iReprClp, + int fVerbose, int * pnSkipped ) +{ + // First check if either CI feeds restricted flops (marked with fMark1) + Gia_Obj_t * pReprObj = Gia_ManObj(p, pClp2Gia[iReprClp]); + if ( fVerbose && Gia_ObjIsCi(pObj) ) + printf( " Checking obj %d: fMark1=%d\n", i, pObj->fMark1 ); + if ( fVerbose && Gia_ObjIsCi(pReprObj) ) + printf( " Checking repr %d: fMark1=%d\n", pClp2Gia[iReprClp], pReprObj->fMark1 ); + + if ( Gia_ObjIsCi(pObj) && pObj->fMark1 ) + { + if ( fVerbose ) + printf( " -> Skipping equiv: obj %d feeds restricted flop\n", i ); + (*pnSkipped)++; + return 1; + } + if ( Gia_ObjIsCi(pReprObj) && pReprObj->fMark1 ) + { + if ( fVerbose ) + printf( " -> Skipping equiv: repr %d feeds restricted flop\n", pClp2Gia[iReprClp] ); + (*pnSkipped)++; + return 1; + } + // Check vRegClasses and vFlopClasses restrictions if both are flops + // For flops to be mergeable, they must satisfy BOTH conditions: + // 1. vRegClasses: same non-zero clock domain (0 = not removeable/mergeable) + // 2. vFlopClasses: same non-zero merge class (0 = unmergeable) + if ( (p->vRegClasses || p->vFlopClasses) && Gia_ObjIsCi(pObj) ) + { + // In unnormalized AIGs with boxes, flop outputs are the last nFlops CIs + // They are not marked with fMark0 (which marks CIs feeding flop inputs) + int iFlopCur = -1, iFlopRepr = -1; + int nTotalCis = Gia_ManCiNum(p); // Total CIs + int nFlops = Gia_ManRegBoxNum(p); + int nFirstFlop = nTotalCis - nFlops; // First flop CI index + + // Get the CI ID of the current object + int CiIdCur = Gia_ObjCioId(pObj); + + if ( fVerbose ) + printf( " Checking CI: obj %d, CiId %d, nTotalCis=%d, nFlops=%d, FirstFlopCI=%d\n", + i, CiIdCur, nTotalCis, nFlops, nFirstFlop ); + + // Check if current object is a flop output (last nFlops CIs) + if ( CiIdCur >= nFirstFlop && CiIdCur < nTotalCis ) + iFlopCur = CiIdCur - nFirstFlop; + + // Check if representative is a flop output + int iRepr = pClp2Gia[iReprClp]; + Gia_Obj_t * pRepr = Gia_ManObj(p, iRepr); + if ( Gia_ObjIsCi(pRepr) ) + { + int CiIdRepr = Gia_ObjCioId(pRepr); + if ( CiIdRepr >= nFirstFlop && CiIdRepr < nTotalCis ) + iFlopRepr = CiIdRepr - nFirstFlop; + } + + // Apply merging restrictions + if ( iFlopCur >= 0 && iFlopRepr >= 0 ) + { + if ( fVerbose ) + printf( "Checking flop merge: flop %d and flop %d\n", iFlopCur, iFlopRepr ); + + // Check vRegClasses (clock domains) first + if ( p->vRegClasses ) + { + assert( iFlopCur < Vec_IntSize(p->vRegClasses) ); + assert( iFlopRepr < Vec_IntSize(p->vRegClasses) ); + + int DomainCur = Vec_IntEntry(p->vRegClasses, iFlopCur); + int DomainRepr = Vec_IntEntry(p->vRegClasses, iFlopRepr); + + if ( fVerbose ) + printf( " Clock domains: %d and %d\n", DomainCur, DomainRepr ); + + // Skip merging if either is in domain 0 or domains don't match + if ( DomainCur == 0 || DomainRepr == 0 || DomainCur != DomainRepr ) + { + if ( fVerbose ) + printf( " -> Skipping due to clock domain restriction\n" ); + (*pnSkipped)++; + return 1; // Skip this merging + } + } + + // Check vFlopClasses (merge classes) second + if ( p->vFlopClasses ) + { + assert( iFlopCur < Vec_IntSize(p->vFlopClasses) ); + assert( iFlopRepr < Vec_IntSize(p->vFlopClasses) ); + + int ClassCur = Vec_IntEntry(p->vFlopClasses, iFlopCur); + int ClassRepr = Vec_IntEntry(p->vFlopClasses, iFlopRepr); + + if ( fVerbose ) + printf( " Merge classes: %d and %d\n", ClassCur, ClassRepr ); + + // Skip merging if classes don't match or class is 0 (unmergeable) + if ( ClassCur == 0 || ClassRepr == 0 || ClassCur != ClassRepr ) + { + if ( fVerbose ) + printf( " -> Skipping due to merge class restriction\n" ); + (*pnSkipped)++; + return 1; // Skip this merging + } + } + } + } + return 0; // OK to merge +} + +/**Function************************************************************* + + Synopsis [Select representatives for the collapsed AIG.] + + Description [] + SideEffects [] SeeAlso [] @@ -483,8 +742,13 @@ int * Gia_ManFraigSelectReprs( Gia_Man_t * p, Gia_Man_t * pClp, int fVerbose, in int * pReprs = ABC_FALLOC( int, Gia_ManObjNum(p) ); int * pClp2Gia = ABC_FALLOC( int, Gia_ManObjNum(pClp) ); int i, iLitClp, iLitClp2, iReprClp, fCompl; - int nConsts = 0, nReprs = 0; + int nConsts = 0, nReprs = 0, nSkipped = 0; assert( pManTime != NULL ); + + // Debug: Check if vRegClasses and vFlopClasses are present + if ( fVerbose ) + Gia_ManFraigPrintDebugInfo( p ); + // count the number of equivalent objects Gia_ManForEachObj1( pClp, pObj, i ) { @@ -513,6 +777,11 @@ int * Gia_ManFraigSelectReprs( Gia_Man_t * p, Gia_Man_t * pClp, int fVerbose, in vCarryOuts = Gia_ManComputeCarryOuts( p ); Gia_ManForEachObjVec( vCarryOuts, p, pObj, i ) pObj->fMark0 = 1; + + // Additionally, mark box outputs that feed restricted flops using fMark1 + // This prevents box merging from indirectly eliminating restricted flops + if ( p->vRegClasses || p->vFlopClasses ) + Gia_ManFraigMarkRestrictedBoxOutputs( p, fVerbose ); if ( fVerbose ) printf( "Fixed %d flop inputs and %d box/box connections (out of %d non-flop boxes).\n", Gia_ManRegBoxNum(p), Vec_IntSize(vCarryOuts), Gia_ManNonRegBoxNum(p) ); @@ -520,11 +789,23 @@ int * Gia_ManFraigSelectReprs( Gia_Man_t * p, Gia_Man_t * pClp, int fVerbose, in // collect equivalent node info pFlopTypes[0] = pFlopTypes[1] = pFlopTypes[2] = 0; + if ( fVerbose ) + printf( "Checking flop equivalences in collapsed circuit:\n" ); Gia_ManForEachRo( pClp, pObj, i ) { Gia_Obj_t * pRepr = Gia_ObjReprObj(pClp, i); if ( pRepr && pRepr != pObj ) { + if ( fVerbose ) + { + printf( " Flop %d (clp obj %d) has repr obj %d", i - Gia_ManPiNum(pClp), + i, Gia_ObjId(pClp, pRepr) ); + if ( pRepr == Gia_ManConst0(pClp) ) + printf( " (const 0)"); + else if ( Gia_ObjIsRo(pClp, pRepr) ) + printf( " (another flop: %d)", Gia_ObjCioId(pRepr) - (Gia_ManPiNum(pClp) - Gia_ManRegNum(pClp)) ); + printf( "\n" ); + } if ( pRepr == Gia_ManConst0(pClp) ) pFlopTypes[0]++; else if ( Gia_ObjIsRo(pClp, pRepr) ) @@ -549,9 +830,21 @@ int * Gia_ManFraigSelectReprs( Gia_Man_t * p, Gia_Man_t * pClp, int fVerbose, in if ( pClp2Gia[iReprClp] == -1 ) pClp2Gia[iReprClp] = i; else - { + { iLitClp2 = Gia_ObjValue( Gia_ManObj(p, pClp2Gia[iReprClp]) ); assert( Gia_ObjReprSelf(pClp, Abc_Lit2Var(iLitClp)) == Gia_ObjReprSelf(pClp, Abc_Lit2Var(iLitClp2)) ); + + // Debug: Show what's being merged + if ( fVerbose ) + { + Gia_Obj_t * pReprObj = Gia_ManObj(p, pClp2Gia[iReprClp]); + Gia_ManFraigPrintEquivInfo( p, pObj, i, pReprObj, pClp2Gia, iLitClp, iReprClp ); + } + + // Check flop restrictions for merging + if ( Gia_ManFraigCheckFlopRestrictions( p, pObj, i, pClp2Gia, iReprClp, fVerbose, &nSkipped ) ) + continue; + fCompl = Abc_LitIsCompl(iLitClp) ^ Abc_LitIsCompl(iLitClp2); fCompl ^= Gia_ManObj(pClp, Abc_Lit2Var(iLitClp))->fPhase; fCompl ^= Gia_ManObj(pClp, Abc_Lit2Var(iLitClp2))->fPhase; @@ -565,9 +858,16 @@ int * Gia_ManFraigSelectReprs( Gia_Man_t * p, Gia_Man_t * pClp, int fVerbose, in } ABC_FREE( pClp2Gia ); Gia_ManForEachCi( p, pObj, i ) + { pObj->fMark0 = 0; + pObj->fMark1 = 0; // Clean up the restricted flop marker + } if ( fVerbose ) + { printf( "Found %d const objects and %d other objects.\n", nConsts, nReprs ); + if ( (p->vRegClasses || p->vFlopClasses) && nSkipped > 0 ) + printf( "Skipped %d flop mergings due to clock domain or merge class restrictions.\n", nSkipped ); + } return pReprs; } @@ -737,12 +1037,21 @@ Gia_Man_t * Gia_ManSweepWithBoxesAndDomains( Gia_Man_t * p, void * pParsS, int f ***********************************************************************/ Gia_Man_t * Gia_ManSweepWithBoxes( Gia_Man_t * p, void * pParsC, void * pParsS, int fConst, int fEquiv, int fVerbose, int fVerbEquivs ) -{ +{ Gia_Man_t * pClp, * pNew, * pTemp; int * pReprs, pFlopTypes[3] = {0}; int nFlopsNew, nFlops; assert( Gia_ManRegNum(p) == 0 ); assert( p->pAigExtra != NULL ); + + // Debug: Check if vRegClasses and vFlopClasses are present + if ( fVerbose ) + { + if ( p->vRegClasses ) + printf( "Input has vRegClasses with %d entries\n", Vec_IntSize(p->vRegClasses) ); + if ( p->vFlopClasses ) + printf( "Input has vFlopClasses with %d entries\n", Vec_IntSize(p->vFlopClasses) ); + } // consider seq synthesis with multiple clock domains if ( pParsC == NULL && Gia_ManClockDomainNum(p) > 1 ) return Gia_ManSweepWithBoxesAndDomains( p, pParsS, fConst, fEquiv, fVerbose, fVerbEquivs ); diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 02959f7f4..9b593370a 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -44272,7 +44272,25 @@ int Abc_CommandAbc9If( Abc_Frame_t * pAbc, int argc, char ** argv ) goto usage; } } - + + // Auto-detect K from cell library when -j is used + if ( pPars->fEnableCheck07 && pPars->nLutSize == -1 ) + { + If_LibCell_t * pCellLib = (If_LibCell_t *)Abc_FrameReadLibCell(); + if ( pCellLib ) + { + int nMaxInputs = If_LibCellGetMaxInputs( pCellLib ); + if ( nMaxInputs > 0 ) + { + pPars->nLutSize = nMaxInputs; + if ( pPars->fVerbose ) + Abc_Print( 1, "Auto-detected K=%d from cell library (max inputs).\n", nMaxInputs ); + // Disable LUT library since we're using K from cell library + pPars->pLutLib = NULL; + } + } + } + if ( pAbc->pGia == NULL ) { if ( !Abc_FrameReadFlag("silentmode") ) @@ -48454,20 +48472,30 @@ usage: ***********************************************************************/ int Abc_CommandAbc9Trace( Abc_Frame_t * pAbc, int argc, char ** argv ) { + extern void Gia_ManDelayTraceDump( Gia_Man_t * p, char * pFileName ); int c; int fUseLutLib; + int fUseCellLib; int fVerbose; + const char * pFileName = NULL; // set defaults fUseLutLib = 0; + fUseCellLib = 0; fVerbose = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "lvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "F:lcvh" ) ) != EOF ) { switch ( c ) { + case 'F': + pFileName = globalUtilOptarg; + break; case 'l': fUseLutLib ^= 1; break; + case 'c': + fUseCellLib ^= 1; + break; case 'v': fVerbose ^= 1; break; @@ -48479,22 +48507,40 @@ int Abc_CommandAbc9Trace( Abc_Frame_t * pAbc, int argc, char ** argv ) } if ( pAbc->pGia == NULL ) { - Abc_Print( -1, "Abc_CommandAbc9Speedup(): There is no AIG to map.\n" ); + Abc_Print( -1, "Abc_CommandAbc9Trace(): There is no AIG to map.\n" ); return 1; } if ( !Gia_ManHasMapping(pAbc->pGia) ) { - Abc_Print( -1, "Abc_CommandAbc9Speedup(): Mapping of the AIG is not defined.\n" ); + Abc_Print( -1, "Abc_CommandAbc9Trace(): Mapping of the AIG is not defined.\n" ); + return 1; + } + if ( fUseLutLib && fUseCellLib ) + { + Abc_Print( -1, "Abc_CommandAbc9Trace(): Cannot use both LUT library (-l) and cell library (-c) simultaneously.\n" ); return 1; } pAbc->pGia->pLutLib = fUseLutLib ? Abc_FrameReadLibLut() : NULL; - Gia_ManDelayTraceLutPrint( pAbc->pGia, fVerbose ); + pAbc->pGia->pCellLib = fUseCellLib ? Abc_FrameReadLibCell() : NULL; + + if ( pFileName ) + { + // Dump the delay trace to file + Gia_ManDelayTraceDump( pAbc->pGia, (char *)pFileName ); + } + else + { + // Print the delay trace to console + Gia_ManDelayTraceLutPrint( pAbc->pGia, fVerbose ); + } return 0; usage: - Abc_Print( -2, "usage: &trace [-lvh]\n" ); + Abc_Print( -2, "usage: &trace [-F file] [-lcvh]\n" ); Abc_Print( -2, "\t performs delay trace of LUT-mapped network\n" ); - Abc_Print( -2, "\t-l : toggle using unit- or LUT-library-delay model [default = %s]\n", fUseLutLib? "lib": "unit" ); + Abc_Print( -2, "\t-F file : dump the critical path to a file [default = console output]\n" ); + Abc_Print( -2, "\t-l : toggle using LUT-library-delay model [default = %s]\n", fUseLutLib? "yes": "no" ); + Abc_Print( -2, "\t-c : toggle using cell-library-delay model [default = %s]\n", fUseCellLib? "yes": "no" ); Abc_Print( -2, "\t-v : toggle printing optimization summary [default = %s]\n", fVerbose? "yes": "no" ); Abc_Print( -2, "\t-h : print the command usage\n"); return 1; @@ -58778,10 +58824,11 @@ int Abc_CommandAbc9FunTrace( Abc_Frame_t * pAbc, int argc, char ** argv ) extern void Gia_ManMatchCuts( Vec_Mem_t * vTtMem, Gia_Man_t * pGia, int nCutSize, int nCutNum, int fVerbose ); extern Vec_Mem_t * Abc_TruthDecRead( char * pFileName, int nVarNum ); extern void Abc_TtStoreDump( char * pFileName, Vec_Mem_t * vTtMem, int nBytes ); - int c, nVars, nVars2, nCutNum = 8, nCutSize = 0, nNumFuncs = 5, nNumCones = 3, fOutputs = 0, fVerbose = 0; word * pTruth = NULL; + extern Vec_Mem_t * Dau_CollectBoothFunctions( int nLog2Radix ); + int c, nVars, nVars2, nCutNum = 32, nCutSize = 0, nBooth = 0, nNumFuncs = 5, nNumCones = 3, fOutputs = 0, fVerbose = 0; word * pTruth = NULL; char * pStr = NULL, * pFuncFileName = "_npn_member_funcs_.data"; Vec_Mem_t * vTtMem = NULL; Gia_Man_t * pTemp; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "CKNMFovh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "CKBNMFovh" ) ) != EOF ) { switch ( c ) { @@ -58807,6 +58854,24 @@ int Abc_CommandAbc9FunTrace( Abc_Frame_t * pAbc, int argc, char ** argv ) if ( nCutSize < 0 ) goto usage; break; + case 'B': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-B\" should be followed by an integer.\n" ); + goto usage; + } + nBooth = atoi(argv[globalUtilOptind]); + if ( nBooth < 4 || nBooth > 1024 ) { + Abc_Print( -1, "Currently support radix value from 4 to 1024.\n" ); + goto usage; + } + nBooth = Abc_Base2Log(nBooth); + if ( (1 << nBooth) != atoi(argv[globalUtilOptind]) ) { + Abc_Print( -1, "The Booth radix value %s is not a degree of 2.\n", argv[globalUtilOptind] ); + goto usage; + } + globalUtilOptind++; + break; case 'N': if ( globalUtilOptind >= argc ) { @@ -58857,21 +58922,28 @@ int Abc_CommandAbc9FunTrace( Abc_Frame_t * pAbc, int argc, char ** argv ) } if ( argc == globalUtilOptind ) { - abctime clkStart = Abc_Clock(); - int nFileSize = Gia_FileSize( pFuncFileName ); - if ( nFileSize == 0 ) - { - Abc_Print( -1, "Abc_CommandAbc9FunTrace(): Truth table in hex notation (or file name with the functions) should be given on the command line.\n" ); - return 0; + if ( nBooth ) { + vTtMem = Dau_CollectBoothFunctions( nBooth ); + printf( "Generated %d %d-input booth radix-%d encoder functions.\n", 1<<(nBooth-1), nBooth+1, 1<) when precomputed functions are used.\n" ); - return 0; + else { + abctime clkStart = Abc_Clock(); + int nFileSize = Gia_FileSize( pFuncFileName ); + if ( nFileSize == 0 ) + { + Abc_Print( -1, "Abc_CommandAbc9FunTrace(): Truth table in hex notation (or file name with the functions) should be given on the command line.\n" ); + return 0; + } + if ( nCutSize == 0 ) + { + Abc_Print( -1, "Abc_CommandAbc9FunTrace(): The cut size needs to be specified on the command line (-K ) when precomputed functions are used.\n" ); + return 0; + } + vTtMem = Abc_TruthDecRead( pFuncFileName, nCutSize ); + printf( "Finished reading %d %d-input function from file \"%s\". ", nFileSize / 8 / Abc_Truth6WordNum(nCutSize), nCutSize, pFuncFileName ); + Abc_PrintTime( 1, "Time", Abc_Clock() - clkStart ); } - vTtMem = Abc_TruthDecRead( pFuncFileName, nCutSize ); - printf( "Finished reading %d %d-input function from file \"%s\". ", nFileSize / 8 / Abc_Truth6WordNum(nCutSize), nCutSize, pFuncFileName ); - Abc_PrintTime( 1, "Time", Abc_Clock() - clkStart ); Gia_ManMatchCuts( vTtMem, pAbc->pGia, nCutSize, nCutNum, fVerbose ); Vec_MemHashFree( vTtMem ); Vec_MemFree( vTtMem ); @@ -58933,10 +59005,11 @@ int Abc_CommandAbc9FunTrace( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - Abc_Print( -2, "usage: &funtrace [-CKNM num] [-F file] [-ovh] { or }\n" ); + Abc_Print( -2, "usage: &funtrace [-CKBNM num] [-F file] [-ovh] { or }\n" ); Abc_Print( -2, "\t traces the presence of the function in the current AIG\n" ); Abc_Print( -2, "\t-C num : the number of cuts to compute at each node [default = %d]\n", nCutNum ); Abc_Print( -2, "\t-K num : the LUT size to use when is given [default = %d]\n", nCutSize ); + Abc_Print( -2, "\t-B num : the radix of booth partial products to detect [default = %d]\n", nBooth ); Abc_Print( -2, "\t-N num : the number of functions to use when or -F are used [default = %d]\n", nNumFuncs ); Abc_Print( -2, "\t-M num : the number of logic cones to use when is given [default = %d]\n", nNumCones ); Abc_Print( -2, "\t-F file : the file name to store the NPN member functions [default = %s]\n", pFuncFileName ); diff --git a/src/base/wlc/wlcBlast.c b/src/base/wlc/wlcBlast.c index 8950025d5..f028a1324 100644 --- a/src/base/wlc/wlcBlast.c +++ b/src/base/wlc/wlcBlast.c @@ -1857,10 +1857,20 @@ Gia_Man_t * Wlc_NtkBitBlast( Wlc_Ntk_t * p, Wlc_BstPar_t * pParIn ) int Beg = Wlc_ObjRangeBeg(pObj); if ( End >= Beg ) { - assert( nRange == End - Beg + 1 ); - assert( pFanin->Beg <= Beg && End <= pFanin->End ); - for ( k = Beg; k <= End; k++ ) - Vec_IntPush( vRes, pFans0[k - pFanin->Beg] ); + if ( pFanin->End >= pFanin->Beg ) + { + assert( nRange == End - Beg + 1 ); + assert( pFanin->Beg <= Beg && End <= pFanin->End ); + for ( k = Beg; k <= End; k++ ) + Vec_IntPush( vRes, pFans0[k - pFanin->Beg] ); + } + else + { + assert( nRange == End - Beg + 1 ); + assert( pFanin->End <= Beg && End <= pFanin->Beg ); + for ( k = Beg; k <= End; k++ ) + Vec_IntPush( vRes, pFans0[k - pFanin->End] ); + } } else { diff --git a/src/map/if/if.h b/src/map/if/if.h index 0252a467e..3f9ddd101 100644 --- a/src/map/if/if.h +++ b/src/map/if/if.h @@ -641,6 +641,7 @@ extern float If_LibLutSlowestPinDelay( If_LibLut_t * p ); extern If_LibCell_t * If_LibCellRead( char * FileName ); extern If_LibCell_t * If_LibCellDup( If_LibCell_t * p ); extern void If_LibCellFree( If_LibCell_t * pCellLib ); +extern int If_LibCellGetMaxInputs( If_LibCell_t * pCellLib ); extern void If_LibCellPrint( If_LibCell_t * pCellLib ); /*=== ifLibBox.c =============================================================*/ extern If_LibBox_t * If_LibBoxStart(); diff --git a/src/map/if/ifDecJ.c b/src/map/if/ifDecJ.c index 4b33703ff..018ad4969 100644 --- a/src/map/if/ifDecJ.c +++ b/src/map/if/ifDecJ.c @@ -19,6 +19,7 @@ ***********************************************************************/ #include "if.h" +#include "aig/gia/gia.h" ABC_NAMESPACE_IMPL_START @@ -41,6 +42,9 @@ word If_CutPerformDeriveJ( If_Man_t * p, unsigned * pTruth, int nVars, int nLeav void If_PermUnpack( unsigned Value, int Pla2Var[9] ) { } +void Gia_ManDelayTraceDump( Gia_Man_t * p, char * pFileName ) +{ +} //////////////////////////////////////////////////////////////////////// /// END OF FILE /// diff --git a/src/map/if/ifLibLut.c b/src/map/if/ifLibLut.c index 4da141a97..ee819a2a1 100644 --- a/src/map/if/ifLibLut.c +++ b/src/map/if/ifLibLut.c @@ -566,6 +566,28 @@ void If_LibCellFree( If_LibCell_t * pCellLib ) ABC_FREE( pCellLib ); } +/**Function************************************************************* + + Synopsis [Returns the maximum number of inputs in the cell library.] + + Description [Used for auto-detecting K value for &if command.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int If_LibCellGetMaxInputs( If_LibCell_t * pCellLib ) +{ + int i, nMaxInputs = 0; + if ( pCellLib == NULL ) + return 0; + for ( i = 0; i < pCellLib->nCellNum; i++ ) + if ( pCellLib->nCellInputs[i] > nMaxInputs ) + nMaxInputs = pCellLib->nCellInputs[i]; + return nMaxInputs; +} + /**Function************************************************************* Synopsis [Prints the cell library.] diff --git a/src/opt/dau/dauNpn.c b/src/opt/dau/dauNpn.c index 96f81c508..f4a4bb531 100644 --- a/src/opt/dau/dauNpn.c +++ b/src/opt/dau/dauNpn.c @@ -859,6 +859,52 @@ Vec_Mem_t * Dau_CollectNpnFunctions( word * p, int nVars, int fVerbose ) return vTtMem; } +/**Function************************************************************* + + Synopsis [Function enumeration.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Mem_t * Dau_CollectBoothFunctions( int nLog2Radix ) +{ + assert( nLog2Radix >=2 && nLog2Radix <= 10 ); + int nVars = nLog2Radix + 1; + int nWords = Abc_Truth6WordNum( nVars ); + int nFuncs = 1 << (nLog2Radix - 1); + int nMints = 1 << nVars; + Vec_Mem_t * vTtMem = Vec_MemAllocForTTSimple( nVars ); + word * pFuncs = ABC_CALLOC( word, nWords * nFuncs ); + int m, k, i; + for ( m = 0; m < nMints; m++ ) + { + int d = (m & 1); + for ( k = 1; k < nLog2Radix; k++ ) + if ( m & (1 << k) ) + d += 1 << (k-1); + if ( m & (1 << nLog2Radix) ) + d -= 1 << (nLog2Radix-1); + if ( d == 0 ) + continue; + if ( d < 0 ) + d = -d; + assert( d >= 1 && d <= nFuncs ); + Abc_TtSetBit( pFuncs + (d-1)*nWords, m ); + } + for ( i = 0; i < nFuncs; i++ ) { + if ( nVars < 6 ) + pFuncs[i] = Abc_Tt6Stretch( pFuncs[i], nVars ); + Vec_MemHashInsert( vTtMem, pFuncs + i*nWords ); + } + ABC_FREE( pFuncs ); + //Vec_MemDump( stdout, vTtMem ); + return vTtMem; +} + /**Function************************************************************* Synopsis [Function enumeration.] @@ -1065,4 +1111,3 @@ void Dau_CanonicizeArray( Vec_Wrd_t * vFuncs, int nVars, int fVerbose ) //////////////////////////////////////////////////////////////////////// ABC_NAMESPACE_IMPL_END -