From c1ed182d38d2c9dd22f5d531337167ec38c18a15 Mon Sep 17 00:00:00 2001 From: phyzhenli <48823046+phyzhenli@users.noreply.github.com> Date: Tue, 6 Jan 2026 10:34:26 +0800 Subject: [PATCH 01/33] Fix &synch2 crash with creating wrong mapping --- src/aig/gia/giaLf.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/aig/gia/giaLf.c b/src/aig/gia/giaLf.c index 1306600503..3732794ee4 100644 --- a/src/aig/gia/giaLf.c +++ b/src/aig/gia/giaLf.c @@ -1838,6 +1838,12 @@ static inline int Lf_ManDerivePart( Lf_Man_t * p, Gia_Man_t * pNew, Vec_Int_t * } pTruth = Lf_CutTruth( p, pCut ); iLit = Kit_TruthToGia( pNew, (unsigned *)pTruth, Vec_IntSize(vLeaves), vCover, vLeaves, 0 ); + // do not create LUT in the simple case + if ( Abc_Lit2Var(iLit) == 0 ) + return iLit; + Vec_IntForEachEntry( vLeaves, iTemp, k ) + if ( Abc_Lit2Var(iLit) == Abc_Lit2Var(iTemp) ) + return iLit; // create mapping Vec_IntSetEntry( vMapping, Abc_Lit2Var(iLit), Vec_IntSize(vMapping2) ); Vec_IntPush( vMapping2, Vec_IntSize(vLeaves) ); From 62d05a883257005be93cf9a872ac24b10f2e0b88 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Wed, 18 Feb 2026 10:01:16 -0800 Subject: [PATCH 02/33] Enable ccache in Makefile. --- Makefile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Makefile b/Makefile index a9d9b79c51..eeff20d24d 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,13 @@ CXX := g++ AR := ar LD := $(CXX) +# Auto-enable ccache if available +CCACHE := $(shell command -v ccache 2>/dev/null) +ifneq ($(CCACHE),) + CC := $(CCACHE) $(CC) + CXX := $(CCACHE) $(CXX) +endif + MSG_PREFIX ?= ABCSRC ?= . VPATH = $(ABCSRC) @@ -219,6 +226,7 @@ clean: $(VERBOSE)rm -rvf $(OBJ) $(VERBOSE)rm -rvf $(GARBAGE) $(VERBOSE)rm -rvf $(OBJ:.o=.d) + @if [ -n "$(CCACHE)" ]; then echo "$(MSG_PREFIX)ccache available: $(CCACHE)"; fi tags: etags `find . -type f -regex '.*\.\(c\|h\)'` From 3dd086febe43d0d2cd2ab945d7247be54abe991d Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Wed, 18 Feb 2026 10:02:42 -0800 Subject: [PATCH 03/33] New command ÷, etc. --- src/aig/gia/giaDup.c | 120 +++++++++++++++++++++++++++++++++++++ src/base/abc/abcHieGia.c | 4 +- src/base/abci/abc.c | 122 ++++++++++++++++++++++++++++++++++++-- src/base/abci/abcVerify.c | 27 +++++++-- 4 files changed, 262 insertions(+), 11 deletions(-) diff --git a/src/aig/gia/giaDup.c b/src/aig/gia/giaDup.c index 0c0fd3d1e1..ba0b7d78cd 100644 --- a/src/aig/gia/giaDup.c +++ b/src/aig/gia/giaDup.c @@ -23,6 +23,7 @@ #include "misc/vec/vecWec.h" #include "proof/cec/cec.h" #include "misc/util/utilTruth.h" +#include "misc/extra/extra.h" ABC_NAMESPACE_IMPL_START @@ -6844,6 +6845,125 @@ Gia_Man_t * Gia_ManDupExtractMffc( Gia_Man_t * p, Vec_Int_t * vLits, Vec_Int_t * return pNew; } +/**Function************************************************************* + + Synopsis [Divides the AIG into 2 parts at middle level.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Gia_ManDupSplit( Gia_Man_t * p, int nParts, int nCutLevel ) +{ + Gia_Man_t * pPart0, * pPart1; + Gia_Obj_t * pObj; + Vec_Int_t * vCutNodes; + Vec_Ptr_t * vCutNames; + char * pFileName; + int i, Lcut; + assert( nParts == 2 ); + + // Use specified cut level or default to middle + if ( nCutLevel > 0 ) + Lcut = nCutLevel; + else + Lcut = Gia_ManLevelNum(p) / 2; + printf( "Dividing at level %d (total levels = %d). ", Lcut, Gia_ManLevelNum(p) ); + + // mark the nodes pointed to under the cut + Gia_ManForEachAnd( p, pObj, i ) { + if ( Gia_ObjLevel(p, pObj) <= Lcut ) + continue; + if ( Gia_ObjLevel(p, Gia_ObjFanin0(pObj)) <= Lcut ) + Gia_ObjFanin0(pObj)->fMark0 = 1; + if ( Gia_ObjLevel(p, Gia_ObjFanin1(pObj)) <= Lcut ) + Gia_ObjFanin1(pObj)->fMark0 = 1; + } + Gia_ManForEachCo( p, pObj, i ) + if ( Gia_ObjLevel(p, Gia_ObjFanin0(pObj)) < Lcut ) + Gia_ObjFanin0(pObj)->fMark0 = 1; + + // Collect nodes at the cut (nodes at level Lcut that are needed by upper levels) + vCutNodes = Vec_IntAlloc( 100 ); + Gia_ManForEachObj1( p, pObj, i ) { + if ( !pObj->fMark0 ) + continue; + pObj->fMark0 = 0; + Vec_IntPush( vCutNodes, i ); + } + printf( "Found %d nodes at the cut\n", Vec_IntSize(vCutNodes) ); + + // Create names for cut nodes + vCutNames = Vec_PtrAlloc( Vec_IntSize(vCutNodes) ); + for ( i = 0; i < Vec_IntSize(vCutNodes); i++ ) { + char Buffer[100]; sprintf( Buffer, "cut[%d]", i ); + Vec_PtrPush( vCutNames, Abc_UtilStrsav(Buffer) ); + } + + // Create Part 0 (bottom part: levels 0 to Lcut) + pPart0 = Gia_ManStart( Gia_ManObjNum(p) ); + pFileName = Extra_FileNameGenericAppend( p->pSpec ? p->pSpec : "network.aig", "_part0" ); + pPart0->pName = Abc_UtilStrsav( pFileName ); + pPart0->pSpec = Abc_UtilStrsav( pFileName ); + Gia_ManFillValue( p ); + Gia_ManConst0(p)->Value = 0; + Gia_ManForEachCi( p, pObj, i ) + pObj->Value = Gia_ManAppendCi( pPart0 ); + Gia_ManForEachAnd( p, pObj, i ) + if ( Gia_ObjLevel(p, pObj) <= Lcut ) + pObj->Value = Gia_ManAppendAnd( pPart0, Gia_ObjFanin0Copy(pObj), Gia_ObjFanin1Copy(pObj) ); + Gia_ManForEachObjVec( vCutNodes, p, pObj, i ) + Gia_ManAppendCo( pPart0, pObj->Value ); + + // Add names to Part 0 + if ( p->vNamesIn ) { + pPart0->vNamesIn = Vec_PtrDupStr( p->vNamesIn ); + pPart0->vNamesOut = Vec_PtrDupStr( vCutNames ); + } + + // Write Part 0 + pFileName = Extra_FileNameGenericAppend( p->pSpec ? p->pSpec : "network.aig", "_part0.aig" ); + Gia_AigerWrite( pPart0, pFileName, 0, 0, 0 ); + printf( "Part 0: PI = %d, PO = %d, AND = %d, written to %s\n", + Gia_ManCiNum(pPart0), Gia_ManCoNum(pPart0), Gia_ManAndNum(pPart0), pFileName ); + Gia_ManStop( pPart0 ); + + // Create Part 1 (top part: levels > Lcut) + pPart1 = Gia_ManStart( Gia_ManObjNum(p) ); + pFileName = Extra_FileNameGenericAppend( p->pSpec ? p->pSpec : "network.aig", "_part1" ); + pPart1->pName = Abc_UtilStrsav( pFileName ); + pPart1->pSpec = Abc_UtilStrsav( pFileName ); + Gia_ManFillValue( p ); + Gia_ManConst0(p)->Value = 0; + Gia_ManForEachObjVec( vCutNodes, p, pObj, i ) + pObj->Value = Gia_ManAppendCi( pPart1 ); + Gia_ManForEachAnd( p, pObj, i ) + if ( Gia_ObjLevel(p, pObj) > Lcut ) + pObj->Value = Gia_ManAppendAnd( pPart1, Gia_ObjFanin0Copy(pObj), Gia_ObjFanin1Copy(pObj) ); + Gia_ManForEachCo( p, pObj, i ) + Gia_ManAppendCo( pPart1, Gia_ObjFanin0Copy(pObj) ); + + // Add names to Part 1 + if ( p->vNamesOut ) { + pPart1->vNamesIn = Vec_PtrDupStr( vCutNames ); + pPart1->vNamesOut = Vec_PtrDupStr( p->vNamesOut ); + } + + // Write Part 1 + pFileName = Extra_FileNameGenericAppend( p->pSpec ? p->pSpec : "network.aig", "_part1.aig" ); + Gia_AigerWrite( pPart1, pFileName, 0, 0, 0 ); + printf( "Part 1: PI = %d, PO = %d, AND = %d, written to %s\n", + Gia_ManCiNum(pPart1), Gia_ManCoNum(pPart1), Gia_ManAndNum(pPart1), pFileName ); + Gia_ManStop( pPart1 ); + + // Clean up + Vec_IntFree( vCutNodes ); + Vec_PtrFreeFree( vCutNames ); +} + //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// diff --git a/src/base/abc/abcHieGia.c b/src/base/abc/abcHieGia.c index f2f6f8ca60..ea3c2d09a3 100644 --- a/src/base/abc/abcHieGia.c +++ b/src/base/abc/abcHieGia.c @@ -1333,6 +1333,7 @@ static void GiaHie_DumpMappedLuts( Gia_Man_t * p, char * pFileName ) fprintf( pFile, "`timescale 1ns/1ps\n\n" ); // Write LUT module definitions for Yosys compatibility (compact version) + fprintf( pFile, "`ifdef LUTSPECS\n" ); fprintf( pFile, "module LUT2 #( parameter INIT = 04\'h0 ) ( output O, input I0, I1 );\n" ); fprintf( pFile, " assign O = INIT[ {I1, I0} ];\n" ); fprintf( pFile, "endmodule\n" ); @@ -1351,7 +1352,8 @@ static void GiaHie_DumpMappedLuts( Gia_Man_t * p, char * pFileName ) fprintf( pFile, "module LUT6 #( parameter INIT = 64\'h0 ) ( output O, input I0, I1, I2, I3, I4, I5 );\n" ); fprintf( pFile, " assign O = INIT[ {I5, I4, I3, I2, I1, I0} ];\n" ); - fprintf( pFile, "endmodule\n\n" ); + fprintf( pFile, "endmodule\n" ); + fprintf( pFile, "`endif\n\n" ); // Write main module fprintf( pFile, "module " ); diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index dbb5ed99e3..2071b9d57f 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -659,6 +659,7 @@ static int Abc_CommandAbc9MulFind3 ( Abc_Frame_t * pAbc, int argc, cha static int Abc_CommandAbc9BsFind ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9AndCare ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9Cuts ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int Abc_CommandAbc9Divide ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9Test ( Abc_Frame_t * pAbc, int argc, char ** argv ); @@ -1506,8 +1507,9 @@ void Abc_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "ABC9", "&mulfind3", Abc_CommandAbc9MulFind3, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&bsfind", Abc_CommandAbc9BsFind, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&andcare", Abc_CommandAbc9AndCare, 0 ); - Cmd_CommandAdd( pAbc, "ABC9", "&cuts", Abc_CommandAbc9Cuts, 0 ); - + Cmd_CommandAdd( pAbc, "ABC9", "&cuts", Abc_CommandAbc9Cuts, 0 ); + Cmd_CommandAdd( pAbc, "ABC9", "÷", Abc_CommandAbc9Divide, 0 ); + Cmd_CommandAdd( pAbc, "ABC9", "&test", Abc_CommandAbc9Test, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&eslim", Abc_CommandAbc9eSLIM, 0 ); @@ -34455,9 +34457,9 @@ int Abc_CommandAbc9Get( Abc_Frame_t * pAbc, int argc, char ** argv ) Aig_Man_t * pAig; Gia_Man_t * pGia, * pTemp; char * pInits; - int c, fGiaSimple = 0, fMapped = 0, fNames = 0, fVerbose = 0; + int c, fGiaSimple = 0, fMapped = 0, fNames = 0, fReuseNames = 0, fVerbose = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "cmnvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "cmnrvh" ) ) != EOF ) { switch ( c ) { @@ -34470,6 +34472,9 @@ int Abc_CommandAbc9Get( Abc_Frame_t * pAbc, int argc, char ** argv ) case 'n': fNames ^= 1; break; + case 'r': + fReuseNames ^= 1; + break; case 'v': fVerbose ^= 1; break; @@ -34532,17 +34537,38 @@ int Abc_CommandAbc9Get( Abc_Frame_t * pAbc, int argc, char ** argv ) pGia->vOutReqs = Vec_FltAllocArray( Abc_NtkGetCoRequiredFloats(pNtk), Abc_NtkCoNum(pNtk) ); pGia->And2Delay = pNtk->AndGateDelay; } + if ( fReuseNames ) + { + if ( pAbc->pGia == NULL ) + { + Abc_Print( -1, "There is no current AIG to reuse names from.\n" ); + return 1; + } + if ( Gia_ManCiNum(pGia) != Gia_ManCiNum(pAbc->pGia) ) + { + Abc_Print( -1, "The number of CIs differ.\n" ); + return 1; + } + if ( Gia_ManCoNum(pGia) != Gia_ManCoNum(pAbc->pGia) ) + { + Abc_Print( -1, "The number of COs differ.\n" ); + return 1; + } + ABC_SWAP( Vec_Ptr_t *, pGia->vNamesIn, pAbc->pGia->vNamesIn ); + ABC_SWAP( Vec_Ptr_t *, pGia->vNamesOut, pAbc->pGia->vNamesOut ); + } Abc_FrameUpdateGia( pAbc, pGia ); return 0; usage: - Abc_Print( -2, "usage: &get [-cmnvh] \n" ); + Abc_Print( -2, "usage: &get [-cmnrvh] \n" ); Abc_Print( -2, "\t converts the current network into GIA and moves it to the &-space\n" ); Abc_Print( -2, "\t (if the network is a sequential logic network, normalizes the flops\n" ); Abc_Print( -2, "\t to have const-0 initial values, equivalent to \"undc; st; zero\")\n" ); Abc_Print( -2, "\t-c : toggles allowing simple GIA to be imported [default = %s]\n", fGiaSimple? "yes": "no" ); Abc_Print( -2, "\t-m : toggles preserving the current mapping [default = %s]\n", fMapped? "yes": "no" ); Abc_Print( -2, "\t-n : toggles saving CI/CO names of the AIG [default = %s]\n", fNames? "yes": "no" ); + Abc_Print( -2, "\t-r : toggles reusing CI/CO names of the current AIG [default = %s]\n", fReuseNames? "yes": "no" ); Abc_Print( -2, "\t-v : toggles additional verbose output [default = %s]\n", fVerbose? "yes": "no" ); Abc_Print( -2, "\t-h : print the command usage\n"); Abc_Print( -2, "\t : the file name\n"); @@ -42580,6 +42606,7 @@ static Gia_Man_t * Abc_ReadAigerOrVerilogFile( char * pFileName, char * pTopModu FILE * pFile; Gia_Man_t * pGia; char * pTemp; + char * pOrigFileName = NULL; int fVerilog, fSystemVerilog; *pAbc_ReadAigerOrVerilogFileStatus = 0; @@ -42607,6 +42634,8 @@ static Gia_Man_t * Abc_ReadAigerOrVerilogFile( char * pFileName, char * pTopModu { char pCommand[2000]; int RetValue; + // Save the original filename before changing it + pOrigFileName = pFileName; snprintf( pCommand, sizeof(pCommand), "yosys -qp \"read_verilog %s%s; hierarchy %s%s; flatten; proc; opt; async2sync; opt; setundef -undriven -zero; techmap; memory -nomap; memory_map; dffunmap; opt_clean; opt_expr; aigmap; write_aiger -symbols _temp_.aig\"", fSystemVerilog ? "-sv " : "", pFileName, pTopModule ? "-top " : "-auto-top", pTopModule ? pTopModule : "" ); @@ -42625,7 +42654,18 @@ static Gia_Man_t * Abc_ReadAigerOrVerilogFile( char * pFileName, char * pTopModu pGia = Gia_AigerRead( pFileName, 0, 0, 0 ); if ( pGia == NULL ) + { Abc_Print( -1, "Reading AIGER from file \"%s\" has failed.\n", pFileName ); + return NULL; + } + + // If we read from a Verilog file, keep the original filename as the spec + if ( pOrigFileName != NULL ) + { + ABC_FREE( pGia->pSpec ); + pGia->pSpec = Abc_UtilStrsav( pOrigFileName ); + } + return pGia; } @@ -59447,7 +59487,7 @@ int Abc_CommandAbc9Cuts( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - Abc_Print( -2, "usage: cuts [-KC num] [-tdbvh]\n" ); + Abc_Print( -2, "usage: &cuts [-KC num] [-tdbvh]\n" ); Abc_Print( -2, "\t computes K-input cuts for the nodes in the current AIG\n" ); Abc_Print( -2, "\t-K num : max number of leaves (%d <= num <= %d) [default = %d]\n", 2, 14, nCutSize ); Abc_Print( -2, "\t-C num : max number of cuts at a node (%d <= num <= %d) [default = %d]\n", 2, 256, nCutNum ); @@ -59458,6 +59498,76 @@ int Abc_CommandAbc9Cuts( Abc_Frame_t * pAbc, int argc, char ** argv ) return 1; } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_CommandAbc9Divide( Abc_Frame_t * pAbc, int argc, char ** argv ) +{ + extern void Gia_ManDupSplit( Gia_Man_t * p, int nParts, int nCutLevel ); + int nParts = 2; + int nCutLevel = 0; + int c; + Extra_UtilGetoptReset(); + while ( ( c = Extra_UtilGetopt( argc, argv, "PLvh" ) ) != EOF ) + { + switch ( c ) + { + case 'P': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-P\" should be followed by an integer.\n" ); + goto usage; + } + nParts = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nParts < 2 ) + goto usage; + break; + case 'L': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-L\" should be followed by an integer.\n" ); + goto usage; + } + nCutLevel = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nCutLevel < 0 ) + goto usage; + break; + case 'v': + break; + case 'h': + goto usage; + default: + goto usage; + } + } + if ( pAbc->pGia == NULL ) + { + Abc_Print( -1, "Abc_CommandAbc9Divide(): There is no AIG.\n" ); + return 0; + } + Gia_ManDupSplit( pAbc->pGia, nParts, nCutLevel ); + return 0; + +usage: + Abc_Print( -2, "usage: ÷ [-P num] [-L num] [-vh]\n" ); + Abc_Print( -2, "\t divides AIG into N parts at different levels\n" ); + Abc_Print( -2, "\t-P num : number of parts to divide into [default = %d]\n", nParts ); + Abc_Print( -2, "\t-L num : cut level (0 = automatic middle level) [default = %d]\n", nCutLevel ); + Abc_Print( -2, "\t-v : toggle printing verbose information [default = no]\n" ); + Abc_Print( -2, "\t-h : print the command usage\n"); + return 1; +} + /**Function************************************************************* Synopsis [] diff --git a/src/base/abci/abcVerify.c b/src/base/abci/abcVerify.c index c4744ebe05..3ec0e929ac 100644 --- a/src/base/abci/abcVerify.c +++ b/src/base/abci/abcVerify.c @@ -834,32 +834,51 @@ static void Abc_NtkVerifyPrintWords( Vec_Ptr_t * vWords ) } } -void Abc_NtkVerifyPrintCex( const int * pModel, const int * pValues1, const int * pValues2, - const char * const * ppInputNames, int nInputs, const char * const * ppOutputNames, int nOutputs, +void Abc_NtkVerifyPrintCex( const int * pModel, const int * pValues1, const int * pValues2, + const char * const * ppInputNames, int nInputs, const char * const * ppOutputNames, int nOutputs, const char * pNtkName1, const char * pNtkName2 ) { Vec_Ptr_t * vInputs = Vec_PtrAlloc( 0 ); Vec_Ptr_t * vOutputs1 = Vec_PtrAlloc( 0 ); Vec_Ptr_t * vOutputs2 = Vec_PtrAlloc( 0 ); + char * pBaseName1 = NULL; + char * pBaseName2 = NULL; + Abc_NtkVerifyCollectWords( vInputs, ppInputNames, pModel, nInputs ); Abc_NtkVerifyCollectWords( vOutputs1, ppOutputNames, pValues1, nOutputs ); if ( pValues2 ) Abc_NtkVerifyCollectWords( vOutputs2, ppOutputNames, pValues2, nOutputs ); + + // Extract base names for printing + if ( pNtkName1 ) + { + char * pFileNameOnly = Extra_FileNameWithoutPath( (char *)pNtkName1 ); + pBaseName1 = Extra_FileNameGeneric( pFileNameOnly ); + } + if ( pNtkName2 ) + { + char * pFileNameOnly = Extra_FileNameWithoutPath( (char *)pNtkName2 ); + pBaseName2 = Extra_FileNameGeneric( pFileNameOnly ); + } + if ( Vec_PtrSize(vInputs) || Vec_PtrSize(vOutputs1) || Vec_PtrSize(vOutputs2) ) { printf( "INPUT: " ); Abc_NtkVerifyPrintWords( vInputs ); printf( ". OUTPUT: " ); Abc_NtkVerifyPrintWords( vOutputs1 ); - printf( " (%s)", pNtkName1 ? pNtkName1 : "network1" ); + printf( " (%s)", pBaseName1 ? pBaseName1 : (pNtkName1 ? pNtkName1 : "network1") ); if ( pValues2 && Vec_PtrSize(vOutputs2) ) { printf( ", " ); Abc_NtkVerifyPrintWords( vOutputs2 ); - printf( " (%s)", pNtkName2 ? pNtkName2 : "network2" ); + printf( " (%s)", pBaseName2 ? pBaseName2 : (pNtkName2 ? pNtkName2 : "network2") ); } printf( ".\n" ); } + + ABC_FREE( pBaseName1 ); + ABC_FREE( pBaseName2 ); Abc_NtkVerifyFreeWords( vInputs ); Abc_NtkVerifyFreeWords( vOutputs1 ); Abc_NtkVerifyFreeWords( vOutputs2 ); From 6c8b2cfa3b7753d9eba198d3085598aba51b8b16 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Wed, 18 Feb 2026 12:19:04 -0800 Subject: [PATCH 04/33] Compiler problem. --- src/aig/gia/giaDup.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/aig/gia/giaDup.c b/src/aig/gia/giaDup.c index ba0b7d78cd..d1187cb241 100644 --- a/src/aig/gia/giaDup.c +++ b/src/aig/gia/giaDup.c @@ -6905,7 +6905,7 @@ void Gia_ManDupSplit( Gia_Man_t * p, int nParts, int nCutLevel ) // Create Part 0 (bottom part: levels 0 to Lcut) pPart0 = Gia_ManStart( Gia_ManObjNum(p) ); - pFileName = Extra_FileNameGenericAppend( p->pSpec ? p->pSpec : "network.aig", "_part0" ); + pFileName = Extra_FileNameGenericAppend( (char *)(p->pSpec ? p->pSpec : "network.aig"), "_part0" ); pPart0->pName = Abc_UtilStrsav( pFileName ); pPart0->pSpec = Abc_UtilStrsav( pFileName ); Gia_ManFillValue( p ); @@ -6925,7 +6925,7 @@ void Gia_ManDupSplit( Gia_Man_t * p, int nParts, int nCutLevel ) } // Write Part 0 - pFileName = Extra_FileNameGenericAppend( p->pSpec ? p->pSpec : "network.aig", "_part0.aig" ); + pFileName = Extra_FileNameGenericAppend( (char *)(p->pSpec ? p->pSpec : "network.aig"), "_part0.aig" ); Gia_AigerWrite( pPart0, pFileName, 0, 0, 0 ); printf( "Part 0: PI = %d, PO = %d, AND = %d, written to %s\n", Gia_ManCiNum(pPart0), Gia_ManCoNum(pPart0), Gia_ManAndNum(pPart0), pFileName ); @@ -6933,7 +6933,7 @@ void Gia_ManDupSplit( Gia_Man_t * p, int nParts, int nCutLevel ) // Create Part 1 (top part: levels > Lcut) pPart1 = Gia_ManStart( Gia_ManObjNum(p) ); - pFileName = Extra_FileNameGenericAppend( p->pSpec ? p->pSpec : "network.aig", "_part1" ); + pFileName = Extra_FileNameGenericAppend( (char *)(p->pSpec ? p->pSpec : "network.aig"), "_part1" ); pPart1->pName = Abc_UtilStrsav( pFileName ); pPart1->pSpec = Abc_UtilStrsav( pFileName ); Gia_ManFillValue( p ); @@ -6953,7 +6953,7 @@ void Gia_ManDupSplit( Gia_Man_t * p, int nParts, int nCutLevel ) } // Write Part 1 - pFileName = Extra_FileNameGenericAppend( p->pSpec ? p->pSpec : "network.aig", "_part1.aig" ); + pFileName = Extra_FileNameGenericAppend( (char *)(p->pSpec ? p->pSpec : "network.aig"), "_part1.aig" ); Gia_AigerWrite( pPart1, pFileName, 0, 0, 0 ); printf( "Part 1: PI = %d, PO = %d, AND = %d, written to %s\n", Gia_ManCiNum(pPart1), Gia_ManCoNum(pPart1), Gia_ManAndNum(pPart1), pFileName ); From c7ea67b7df375cae5bbee8fefc1031bc9bf97445 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Wed, 18 Feb 2026 12:19:32 -0800 Subject: [PATCH 05/33] Update command "history". --- src/base/cmd/cmd.c | 60 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/src/base/cmd/cmd.c b/src/base/cmd/cmd.c index fff4fa9f6b..0bb4b412b5 100644 --- a/src/base/cmd/cmd.c +++ b/src/base/cmd/cmd.c @@ -441,6 +441,7 @@ int CmdCommandHistory( Abc_Frame_t * pAbc, int argc, char **argv ) char * pName, * pStr = NULL; int i, c; int nPrints = 20; + int nPrinted = 0; Extra_UtilGetoptReset(); while ( ( c = Extra_UtilGetopt( argc, argv, "h" ) ) != EOF ) { @@ -452,29 +453,68 @@ int CmdCommandHistory( Abc_Frame_t * pAbc, int argc, char **argv ) goto usage; } } - if ( argc > globalUtilOptind + 1 ) + if ( argc > globalUtilOptind + 2 ) goto usage; - // get the number from the command line - pStr = argc == globalUtilOptind+1 ? argv[globalUtilOptind] : NULL; - if ( pStr && pStr[0] >= '1' && pStr[0] <= '9' ) - nPrints = atoi(pStr), pStr = NULL; + // parse arguments: can be [substring] [number] in either order + if ( argc == globalUtilOptind + 1 ) + { + // one argument: either number or substring + pStr = argv[globalUtilOptind]; + if ( pStr && pStr[0] >= '1' && pStr[0] <= '9' ) + { + nPrints = atoi(pStr); + pStr = NULL; + } + } + else if ( argc == globalUtilOptind + 2 ) + { + // two arguments: substring and number + char * arg1 = argv[globalUtilOptind]; + char * arg2 = argv[globalUtilOptind + 1]; + + // Try to parse second argument as number + if ( arg2[0] >= '1' && arg2[0] <= '9' ) + { + pStr = arg1; + nPrints = atoi(arg2); + } + // Try to parse first argument as number + else if ( arg1[0] >= '1' && arg1[0] <= '9' ) + { + nPrints = atoi(arg1); + pStr = arg2; + } + else + { + // Neither is a number, error + goto usage; + } + } + // print the commands if ( pStr == NULL ) { + // No search string, show last nPrints entries Vec_PtrForEachEntryStart( char *, pAbc->aHistory, pName, i, Abc_MaxInt(0, Vec_PtrSize(pAbc->aHistory)-nPrints) ) - fprintf( pAbc->Out, "%2d : %s\n", Vec_PtrSize(pAbc->aHistory)-i, pName ); + fprintf( pAbc->Out, "%4d : %s\n", Vec_PtrSize(pAbc->aHistory)-i, pName ); } else { + // Search string provided, show up to nPrints matching entries Vec_PtrForEachEntry( char *, pAbc->aHistory, pName, i ) if ( strstr(pName, pStr) ) - fprintf( pAbc->Out, "%2d : %s\n", Vec_PtrSize(pAbc->aHistory)-i, pName ); + { + fprintf( pAbc->Out, "%4d : %s\n", Vec_PtrSize(pAbc->aHistory)-i, pName ); + if ( ++nPrinted >= nPrints ) + break; + } } return 0; usage: - fprintf( pAbc->Err, "usage: history [-h] \n" ); + fprintf( pAbc->Err, "usage: history [-h] [substring] [num]\n" ); fprintf( pAbc->Err, "\t lists the last commands entered on the command line\n" ); - fprintf( pAbc->Err, "\t-h : print the command usage\n" ); - fprintf( pAbc->Err, "\t : the maximum number of entries to show [default = %d]\n", nPrints ); + fprintf( pAbc->Err, "\t-h : print the command usage\n" ); + fprintf( pAbc->Err, "\tsubstring : search for commands containing this substring\n" ); + fprintf( pAbc->Err, "\tnum : the maximum number of entries to show [default = %d]\n", nPrints ); return ( 1 ); } From 71c24a48124a8244a8bb9afed163f678c6a2e325 Mon Sep 17 00:00:00 2001 From: Jonathan Greene Date: Thu, 19 Feb 2026 13:24:41 -0800 Subject: [PATCH 06/33] Fix backward required-time propagation through boxes --- src/aig/gia/giaSpeedup.c | 26 ++++++++++++++++++++++++++ src/misc/tim/timTime.c | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/aig/gia/giaSpeedup.c b/src/aig/gia/giaSpeedup.c index 0c9d750989..0786bd5599 100644 --- a/src/aig/gia/giaSpeedup.c +++ b/src/aig/gia/giaSpeedup.c @@ -333,6 +333,32 @@ float Gia_ManDelayTraceLut( Gia_Man_t * p ) Gia_ObjSetTimeArrival( p, i, tArrival ); } + // update levels of box output CIs to reflect box structure + // (Gia_ManLevelNum assigns level 0 to all CIs, but box output CIs + // need higher levels so that Gia_ManOrderReverse processes them + // before box input COs during the backward required-time pass) + if ( p->pManTime ) + { + Tim_Man_t * pManTime = (Tim_Man_t *)p->pManTime; + int iBox, nBoxes = Tim_ManBoxNum( pManTime ); + for ( iBox = 0; iBox < nBoxes; iBox++ ) + { + int nIns = Tim_ManBoxInputNum( pManTime, iBox ); + int nOuts = Tim_ManBoxOutputNum( pManTime, iBox ); + int iCoFirst = Tim_ManBoxInputFirst( pManTime, iBox ); + int iCiFirst = Tim_ManBoxOutputFirst( pManTime, iBox ); + int j, maxLevel = 0; + for ( j = 0; j < nIns; j++ ) + { + int coLevel = Gia_ObjLevel( p, Gia_ManCo(p, iCoFirst + j) ); + if ( coLevel > maxLevel ) + maxLevel = coLevel; + } + for ( j = 0; j < nOuts; j++ ) + Gia_ObjSetLevel( p, Gia_ManCi(p, iCiFirst + j), maxLevel + 1 ); + } + } + // get the latest arrival times tArrival = -TIM_ETERNITY; Gia_ManForEachCo( p, pObj, i ) diff --git a/src/misc/tim/timTime.c b/src/misc/tim/timTime.c index c766fb7f13..578eead319 100644 --- a/src/misc/tim/timTime.c +++ b/src/misc/tim/timTime.c @@ -249,7 +249,7 @@ float Tim_ManGetCoRequired( Tim_Man_t * p, int iCo ) Tim_ManBoxForEachOutput( p, pBox, pObj, k ) { pDelays = pTable + 3 + k * pBox->nInputs; - if ( pDelays[k] != -ABC_INFINITY ) + if ( pDelays[i] != -ABC_INFINITY ) DelayBest = Abc_MinFloat( DelayBest, pObj->timeReq - pDelays[i] ); } pObjRes->timeReq = DelayBest; From 771e70381c7ea41c81067f59ce653f8756830af0 Mon Sep 17 00:00:00 2001 From: Jonathan Greene Date: Fri, 20 Feb 2026 11:43:09 -0800 Subject: [PATCH 07/33] Fix two bugs causing problems with &trace and boxes. --- src/aig/gia/giaAiger.c | 15 +++++++++++++++ src/aig/gia/giaSpeedup.c | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/aig/gia/giaAiger.c b/src/aig/gia/giaAiger.c index e9e9e67ca7..39fed2fd47 100644 --- a/src/aig/gia/giaAiger.c +++ b/src/aig/gia/giaAiger.c @@ -677,6 +677,14 @@ Gia_Man_t * Gia_AigerReadFromMemory( char * pContents, int nFileSize, int fGiaSi } pNew->vOutReqs = Vec_FltStart( nOutputs ); memcpy( Vec_FltArray(pNew->vOutReqs), pCur, (size_t)4*nOutputs ); pCur += 4*nOutputs; + // Convert -1.0 back to TIM_ETERNITY for internal use + { + float * pArr = Vec_FltArray(pNew->vOutReqs); + int i; + for ( i = 0; i < nOutputs; i++ ) + if ( pArr[i] < 0 ) + pArr[i] = TIM_ETERNITY; + } if ( fVerbose ) printf( "Finished reading extension \"o\".\n" ); } // read equivalence classes @@ -1562,6 +1570,13 @@ void Gia_AigerWriteS( Gia_Man_t * pInit, char * pFileName, int fWriteSymbols, in { int nPos = Tim_ManPoNum((Tim_Man_t *)p->pManTime); int nFlops = Gia_ManRegNum(p); + // Convert TIM_ETERNITY sentinel to -1.0 per XAIG spec + { + int i; + for ( i = 0; i < nPos + nFlops; i++ ) + if ( pTimes[i] >= TIM_ETERNITY ) + pTimes[i] = -1.0; + } fprintf( pFile, "o" ); Gia_FileWriteBufferSize( pFile, 4*(nPos + nFlops) ); fwrite( pTimes, 1, 4*(nPos + nFlops), pFile ); diff --git a/src/aig/gia/giaSpeedup.c b/src/aig/gia/giaSpeedup.c index 0786bd5599..aa39c9bcd7 100644 --- a/src/aig/gia/giaSpeedup.c +++ b/src/aig/gia/giaSpeedup.c @@ -350,7 +350,7 @@ float Gia_ManDelayTraceLut( Gia_Man_t * p ) int j, maxLevel = 0; for ( j = 0; j < nIns; j++ ) { - int coLevel = Gia_ObjLevel( p, Gia_ManCo(p, iCoFirst + j) ); + int coLevel = Gia_ObjLevel( p, Gia_ObjFanin0(Gia_ManCo(p, iCoFirst + j)) ); if ( coLevel > maxLevel ) maxLevel = coLevel; } From 3b5036a1e1175a05c307b50393c2f1667490fd5a Mon Sep 17 00:00:00 2001 From: Jonathan Greene Date: Sat, 21 Feb 2026 16:54:27 -0800 Subject: [PATCH 08/33] Fix required time handling for unconstrained POs, infinity arithmetic, and absDup cosmetic - Tim_ManInitPoRequiredAll: only overwrite PO required times when ALL are unconstrained; preserve user-specified constraints - Gia_ObjPropagateRequired: propagate infinity unchanged through LUTs - Tim_ManGetCoRequired: guard against infinity minus delay arithmetic - Gia_ManDelayTraceLut: handle infinite required times in slack computation; allow negative slack to report timing violations - Tim_ManCreate: fix required-time loading to address actual POs via Tim_ManForEachPo instead of p->pCos[] (wrong for designs with boxes) - Tim_ManGetArrTimes/Tim_ManGetReqTimes: fix loop-exit detection using boolean flag instead of comparing iterator index against PO/PI count - Gia_ManPrintFlopClasses: use Gia_ManRegBoxNum instead of Gia_ManRegNum Co-Authored-By: Claude Opus 4.6 --- src/aig/gia/giaSpeedup.c | 11 ++++++++--- src/misc/tim/timMan.c | 41 +++++++++++++++++++++++++--------------- src/misc/tim/timTime.c | 7 ++++++- src/proof/abs/absDup.c | 4 ++-- 4 files changed, 42 insertions(+), 21 deletions(-) diff --git a/src/aig/gia/giaSpeedup.c b/src/aig/gia/giaSpeedup.c index aa39c9bcd7..4212c8966e 100644 --- a/src/aig/gia/giaSpeedup.c +++ b/src/aig/gia/giaSpeedup.c @@ -209,6 +209,9 @@ float Gia_ObjPropagateRequired( Gia_Man_t * p, int iObj, int fUseSorting ) float tRequired = 0.0; // Suppress "might be used uninitialized" float * pDelays; assert( Gia_ObjIsLut(p, iObj) ); + // Infinity propagates unchanged + if ( Gia_ObjTimeRequired( p, iObj ) >= TIM_ETERNITY ) + return TIM_ETERNITY; if ( pLutLib == NULL && pCellLib == NULL ) { tRequired = Gia_ObjTimeRequired( p, iObj) - (float)1.0; @@ -407,9 +410,11 @@ float Gia_ManDelayTraceLut( Gia_Man_t * p ) } // set slack for this object - tSlack = Gia_ObjTimeRequired(p, iObj) - Gia_ObjTimeArrival(p, iObj); - assert( tSlack + 0.01 > 0.0 ); - Gia_ObjSetTimeSlack( p, iObj, tSlack < 0.0 ? 0.0 : tSlack ); + if ( Gia_ObjTimeRequired(p, iObj) >= TIM_ETERNITY ) + tSlack = TIM_ETERNITY; + else + tSlack = Gia_ObjTimeRequired(p, iObj) - Gia_ObjTimeArrival(p, iObj); + Gia_ObjSetTimeSlack( p, iObj, tSlack ); } Vec_IntFree( vObjs ); return tArrival; diff --git a/src/misc/tim/timMan.c b/src/misc/tim/timMan.c index 274dc0c0ec..59eac5a0d4 100644 --- a/src/misc/tim/timMan.c +++ b/src/misc/tim/timMan.c @@ -591,19 +591,16 @@ void Tim_ManCreate( Tim_Man_t * p, void * pLib, Vec_Flt_t * vInArrs, Vec_Flt_t * { // Handle special case when timing is only for POs (without boxes/flops) // This happens when old files provide timing for actual design POs only - if ( Vec_FltSize(vOutReqs) < Tim_ManPoNum(p) ) + if ( Vec_FltSize(vOutReqs) <= Tim_ManPoNum(p) ) { - // Special case: timing for actual POs only (less than Tim_ManPoNum when boxes exist) - for ( i = 0; i < Vec_FltSize(vOutReqs); i++ ) - p->pCos[i].timeReq = Vec_FltEntry(vOutReqs, i); - } - else if ( Vec_FltSize(vOutReqs) == Tim_ManPoNum(p) ) - { - // Original case: timing for POs + // Timing for POs (may be partial — omitted entries stay at TIM_ETERNITY) k = 0; Tim_ManForEachPo( p, pObj, i ) + { + if ( k >= Vec_FltSize(vOutReqs) ) + break; pObj->timeReq = Vec_FltEntry(vOutReqs, k++); - assert( k == Tim_ManPoNum(p) ); + } } else { @@ -633,20 +630,27 @@ float * Tim_ManGetArrTimes( Tim_Man_t * p, int nRegs ) float * pTimes; Tim_Obj_t * pObj; int i; + int fFoundTiming = 0; // Check if any PIs have non-zero arrival times Tim_ManForEachPi( p, pObj, i ) if ( pObj->timeArr != 0.0 ) + { + fFoundTiming = 1; break; - if ( i == Tim_ManPiNum(p) && nRegs > 0 ) + } + if ( !fFoundTiming && nRegs > 0 ) { // Check if any flops have non-zero arrival times for ( i = Tim_ManCiNum(p) - nRegs; i < Tim_ManCiNum(p); i++ ) if ( p->pCis[i].timeArr != 0.0 ) + { + fFoundTiming = 1; break; - if ( i == Tim_ManCiNum(p) ) + } + if ( !fFoundTiming ) return NULL; // No timing info at all } - else if ( i == Tim_ManPiNum(p) ) + else if ( !fFoundTiming ) return NULL; // Allocate array for PIs + Flops (compact format, no box outputs) pTimes = ABC_FALLOC( float, Tim_ManPiNum(p) + nRegs ); @@ -663,20 +667,27 @@ float * Tim_ManGetReqTimes( Tim_Man_t * p, int nRegs ) float * pTimes; Tim_Obj_t * pObj; int i, k = 0; + int fFoundConstraint = 0; // Check if any POs have non-infinity required times Tim_ManForEachPo( p, pObj, i ) if ( pObj->timeReq != TIM_ETERNITY ) + { + fFoundConstraint = 1; break; - if ( i == Tim_ManPoNum(p) && nRegs > 0 ) + } + if ( !fFoundConstraint && nRegs > 0 ) { // Check if any flops have non-infinity required times for ( i = Tim_ManCoNum(p) - nRegs; i < Tim_ManCoNum(p); i++ ) if ( p->pCos[i].timeReq != TIM_ETERNITY ) + { + fFoundConstraint = 1; break; - if ( i == Tim_ManCoNum(p) ) + } + if ( !fFoundConstraint ) return NULL; // No timing info at all } - else if ( i == Tim_ManPoNum(p) ) + else if ( !fFoundConstraint ) return NULL; // Allocate array for POs + Flops (compact format, no box inputs) pTimes = ABC_FALLOC( float, Tim_ManPoNum(p) + nRegs ); diff --git a/src/misc/tim/timTime.c b/src/misc/tim/timTime.c index 578eead319..cc0aa5ffd5 100644 --- a/src/misc/tim/timTime.c +++ b/src/misc/tim/timTime.c @@ -98,6 +98,11 @@ void Tim_ManInitPoRequiredAll( Tim_Man_t * p, float Delay ) { Tim_Obj_t * pObj; int i; + // If any PO or flop-input CO is constrained, leave all unchanged + Tim_ManForEachPo( p, pObj, i ) + if ( pObj->timeReq < TIM_ETERNITY ) + return; + // All unconstrained — set to max arrival time Tim_ManForEachPo( p, pObj, i ) Tim_ManSetCoRequired( p, i, Delay ); } @@ -249,7 +254,7 @@ float Tim_ManGetCoRequired( Tim_Man_t * p, int iCo ) Tim_ManBoxForEachOutput( p, pBox, pObj, k ) { pDelays = pTable + 3 + k * pBox->nInputs; - if ( pDelays[i] != -ABC_INFINITY ) + if ( pDelays[i] != -ABC_INFINITY && pObj->timeReq < TIM_ETERNITY ) DelayBest = Abc_MinFloat( DelayBest, pObj->timeReq - pDelays[i] ); } pObjRes->timeReq = DelayBest; diff --git a/src/proof/abs/absDup.c b/src/proof/abs/absDup.c index 942155753a..8bd3b537a0 100644 --- a/src/proof/abs/absDup.c +++ b/src/proof/abs/absDup.c @@ -303,7 +303,7 @@ void Gia_ManPrintFlopClasses( Gia_Man_t * p ) int Counter0, Counter1; if ( p->vFlopClasses == NULL ) return; - if ( Vec_IntSize(p->vFlopClasses) != Gia_ManRegNum(p) ) + if ( Vec_IntSize(p->vFlopClasses) != Gia_ManRegBoxNum(p) ) { printf( "Gia_ManPrintFlopClasses(): The number of flop map entries differs from the number of flops.\n" ); return; @@ -312,7 +312,7 @@ void Gia_ManPrintFlopClasses( Gia_Man_t * p ) Counter1 = Vec_IntCountEntry( p->vFlopClasses, 1 ); printf( "Flop-level abstraction: Excluded FFs = %d Included FFs = %d (%.2f %%) ", Counter0, Counter1, 100.0*Counter1/(Counter0 + Counter1 + 1) ); - if ( Counter0 + Counter1 < Gia_ManRegNum(p) ) + if ( Counter0 + Counter1 < Gia_ManRegBoxNum(p) ) printf( "and there are other FF classes..." ); printf( "\n" ); } From ec8b45add3752be2e870c80983acafb79eddfcbc Mon Sep 17 00:00:00 2001 From: JingrenWang Date: Mon, 23 Feb 2026 15:42:58 +0800 Subject: [PATCH 09/33] Fix(Windows): Update to windows-2025 Signed-off-by: JingrenWang --- .github/workflows/build-windows.yml | 204 ++++++++++++++++++++++++---- 1 file changed, 178 insertions(+), 26 deletions(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index c9f5e2b4fa..6ed4a74b44 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -8,7 +8,7 @@ jobs: build-windows: - runs-on: windows-2019 + runs-on: windows-2025 steps: @@ -17,36 +17,188 @@ jobs: with: submodules: recursive - - name: Prepare MSVC - uses: bus1/cabuild/action/msdevshell@v1 + - name: Setup MSVC + uses: ilammy/msvc-dev-cmd@v1 with: - architecture: x86 + arch: x86 - - name: Upgrade project files to latest Visual Studio, ignoring upgrade errors, and build + - name: Generate solution and project files from dsp + shell: powershell run: | - devenv abcspace.dsw /upgrade - # Fix the upgraded vcxproj files to use C++17 - if (Test-Path abclib.vcxproj) { - $content = Get-Content abclib.vcxproj -Raw - if ($content -match '') { - $content = $content -replace 'Default', 'stdcpp17' - } else { - # Add LanguageStandard if it doesn't exist - $content = $content -replace '()', '$1stdcpp17' + # Parse source files from abclib.dsp + $dspContent = Get-Content "abclib.dsp" -Raw + # Match SOURCE=. followed by path (e.g., SOURCE=.\src\base\abc\abc.c) + # Capture the path without the leading backslash + $sourceFiles = [regex]::Matches($dspContent, 'SOURCE=\.\\([^\r\n]+)') | ForEach-Object { $_.Groups[1].Value } | Sort-Object -Unique + + Write-Host "Found $($sourceFiles.Count) source files" + + # Create the solution file (use tabs for indentation) + $slnContent = "Microsoft Visual Studio Solution File, Format Version 12.00`r`n" + $slnContent += "VisualStudioVersion = 17.0.31903.59`r`n" + $slnContent += "MinimumVisualStudioVersion = 10.0.40219.1`r`n" + $slnContent += 'Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "abclib", "abclib.vcxproj", "{6B6D7E0F-1234-4567-89AB-CDEF01234567}"' + "`r`n" + $slnContent += "EndProject`r`n" + $slnContent += 'Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "abcexe", "abcexe.vcxproj", "{6B6D7E0F-1234-4567-89AB-CDEF01234568}"' + "`r`n" + $slnContent += "`tProjectSection(ProjectDependencies) = postProject`r`n" + $slnContent += "`t`t{6B6D7E0F-1234-4567-89AB-CDEF01234567} = {6B6D7E0F-1234-4567-89AB-CDEF01234567}`r`n" + $slnContent += "`tEndProjectSection`r`n" + $slnContent += "EndProject`r`n" + $slnContent += "Global`r`n" + $slnContent += "`tGlobalSection(SolutionConfigurationPlatforms) = preSolution`r`n" + $slnContent += "`t`tRelease|Win32 = Release|Win32`r`n" + $slnContent += "`tEndGlobalSection`r`n" + $slnContent += "`tGlobalSection(ProjectConfigurationPlatforms) = postSolution`r`n" + $slnContent += "`t`t{6B6D7E0F-1234-4567-89AB-CDEF01234567}.Release|Win32.ActiveCfg = Release|Win32`r`n" + $slnContent += "`t`t{6B6D7E0F-1234-4567-89AB-CDEF01234567}.Release|Win32.Build.0 = Release|Win32`r`n" + $slnContent += "`t`t{6B6D7E0F-1234-4567-89AB-CDEF01234568}.Release|Win32.ActiveCfg = Release|Win32`r`n" + $slnContent += "`t`t{6B6D7E0F-1234-4567-89AB-CDEF01234568}.Release|Win32.Build.0 = Release|Win32`r`n" + $slnContent += "`tEndGlobalSection`r`n" + $slnContent += "EndGlobal`r`n" + Set-Content "abcspace.sln" $slnContent -NoNewline + + # Build source file items for vcxproj + # Separate .c and .cpp files - .c files compile as C, .cpp files compile as C++ + $cCompileItems = "" + $cppCompileItems = "" + $clIncludeItems = "" + foreach ($src in $sourceFiles) { + if ($src -match '\.c$') { + $cCompileItems += " `r`n" + } elseif ($src -match '\.(cpp|cc)$') { + $cppCompileItems += " `r`n" + } elseif ($src -match '\.h$') { + $clIncludeItems += " `r`n" } - Set-Content abclib.vcxproj -NoNewline $content } - if (Test-Path abcexe.vcxproj) { - $content = Get-Content abcexe.vcxproj -Raw - if ($content -match '') { - $content = $content -replace 'Default', 'stdcpp17' - } else { - # Add LanguageStandard if it doesn't exist - $content = $content -replace '()', '$1stdcpp17' - } - Set-Content abcexe.vcxproj -NoNewline $content - } - msbuild abcspace.sln /m /nologo /v:m /p:Configuration=Release /p:UseMultiToolTask=true /p:PlatformToolset=v142 /p:PreprocessorDefinitions="_WINSOCKAPI_" + + # Create abclib.vcxproj (static library) + $libVcxproj = '' + "`r`n" + $libVcxproj += '' + "`r`n" + $libVcxproj += ' ' + "`r`n" + $libVcxproj += ' ' + "`r`n" + $libVcxproj += ' Release' + "`r`n" + $libVcxproj += ' Win32' + "`r`n" + $libVcxproj += ' ' + "`r`n" + $libVcxproj += ' ' + "`r`n" + $libVcxproj += ' ' + "`r`n" + $libVcxproj += ' 17.0' + "`r`n" + $libVcxproj += ' {6B6D7E0F-1234-4567-89AB-CDEF01234567}' + "`r`n" + $libVcxproj += ' Win32Proj' + "`r`n" + $libVcxproj += ' abclib' + "`r`n" + $libVcxproj += ' ' + "`r`n" + $libVcxproj += ' ' + "`r`n" + $libVcxproj += ' ' + "`r`n" + $libVcxproj += ' StaticLibrary' + "`r`n" + $libVcxproj += ' false' + "`r`n" + $libVcxproj += ' v143' + "`r`n" + $libVcxproj += ' true' + "`r`n" + $libVcxproj += ' MultiByte' + "`r`n" + $libVcxproj += ' ' + "`r`n" + $libVcxproj += ' ' + "`r`n" + $libVcxproj += ' ' + "`r`n" + $libVcxproj += ' ' + "`r`n" + $libVcxproj += ' ' + "`r`n" + $libVcxproj += ' ' + "`r`n" + $libVcxproj += ' lib\' + "`r`n" + $libVcxproj += ' ReleaseLib\' + "`r`n" + $libVcxproj += ' ' + "`r`n" + $libVcxproj += ' ' + "`r`n" + $libVcxproj += ' ' + "`r`n" + $libVcxproj += ' Level3' + "`r`n" + $libVcxproj += ' 4146;4334;4996;4703;%(DisableSpecificWarnings)' + "`r`n" + $libVcxproj += ' true' + "`r`n" + $libVcxproj += ' true' + "`r`n" + $libVcxproj += ' true' + "`r`n" + $libVcxproj += ' WIN32;WINDOWS;NDEBUG;_LIB;ABC_DLL=ABC_DLLEXPORT;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ABC_USE_PTHREADS;ABC_USE_CUDD;HAVE_STRUCT_TIMESPEC;_WINSOCKAPI_;%(PreprocessorDefinitions)' + "`r`n" + $libVcxproj += ' true' + "`r`n" + $libVcxproj += ' stdcpp17' + "`r`n" + $libVcxproj += ' src' + "`r`n" + $libVcxproj += ' /Zc:strictStrings- %(AdditionalOptions)' + "`r`n" + $libVcxproj += ' ' + "`r`n" + $libVcxproj += ' ' + "`r`n" + $libVcxproj += ' $(OutDir)abcr.lib' + "`r`n" + $libVcxproj += ' ' + "`r`n" + $libVcxproj += ' ' + "`r`n" + $libVcxproj += ' ' + "`r`n" + $libVcxproj += $cCompileItems + $libVcxproj += $cppCompileItems + $libVcxproj += $clIncludeItems + $libVcxproj += ' ' + "`r`n" + $libVcxproj += ' ' + "`r`n" + $libVcxproj += '' + "`r`n" + Set-Content "abclib.vcxproj" $libVcxproj -NoNewline + + # Create abcexe.vcxproj (executable) + $exeVcxproj = '' + "`r`n" + $exeVcxproj += '' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' Release' + "`r`n" + $exeVcxproj += ' Win32' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' 17.0' + "`r`n" + $exeVcxproj += ' {6B6D7E0F-1234-4567-89AB-CDEF01234568}' + "`r`n" + $exeVcxproj += ' Win32Proj' + "`r`n" + $exeVcxproj += ' abcexe' + "`r`n" + $exeVcxproj += ' abc' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' Application' + "`r`n" + $exeVcxproj += ' false' + "`r`n" + $exeVcxproj += ' v143' + "`r`n" + $exeVcxproj += ' true' + "`r`n" + $exeVcxproj += ' MultiByte' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' _TEST\' + "`r`n" + $exeVcxproj += ' ReleaseExe\' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' Level3' + "`r`n" + $exeVcxproj += ' 4146;4334;4996;4703;%(DisableSpecificWarnings)' + "`r`n" + $exeVcxproj += ' true' + "`r`n" + $exeVcxproj += ' true' + "`r`n" + $exeVcxproj += ' true' + "`r`n" + $exeVcxproj += ' WIN32;WINDOWS;NDEBUG;_CONSOLE;ABC_DLL=ABC_DLLEXPORT;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ABC_USE_PTHREADS;ABC_USE_CUDD;HAVE_STRUCT_TIMESPEC;_WINSOCKAPI_;%(PreprocessorDefinitions)' + "`r`n" + $exeVcxproj += ' true' + "`r`n" + $exeVcxproj += ' stdcpp17' + "`r`n" + $exeVcxproj += ' src' + "`r`n" + $exeVcxproj += ' /Zc:strictStrings- %(AdditionalOptions)' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' Console' + "`r`n" + $exeVcxproj += ' true' + "`r`n" + $exeVcxproj += ' true' + "`r`n" + $exeVcxproj += ' true' + "`r`n" + $exeVcxproj += ' kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;lib\x86\pthreadVC2.lib;%(AdditionalDependencies)' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' {6B6D7E0F-1234-4567-89AB-CDEF01234567}' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += ' ' + "`r`n" + $exeVcxproj += '' + "`r`n" + Set-Content "abcexe.vcxproj" $exeVcxproj -NoNewline + + Write-Host "Project files generated successfully" + + - name: Build + run: | + msbuild abcspace.sln /m /nologo /v:m /p:Configuration=Release /p:Platform=Win32 /p:UseMultiToolTask=true if ($LASTEXITCODE -ne 0) { throw "Build failed with exit code $LASTEXITCODE" } - name: Test Executable From ce559b169e6b0efc61741902e3f9e4f5ef3fff6f Mon Sep 17 00:00:00 2001 From: JingrenWang Date: Tue, 24 Feb 2026 08:37:49 +0800 Subject: [PATCH 10/33] Refactor(Workflow): Windows build refactor Signed-off-by: JingrenWang --- .github/scripts/abcexe.vcxproj | 62 +++++++++ .github/scripts/abclib.vcxproj.template | 52 +++++++ .github/scripts/abcspace.sln | 22 +++ .github/workflows/build-windows.yml | 175 +++--------------------- .gitignore | 4 +- 5 files changed, 155 insertions(+), 160 deletions(-) create mode 100644 .github/scripts/abcexe.vcxproj create mode 100644 .github/scripts/abclib.vcxproj.template create mode 100644 .github/scripts/abcspace.sln diff --git a/.github/scripts/abcexe.vcxproj b/.github/scripts/abcexe.vcxproj new file mode 100644 index 0000000000..817e0809ef --- /dev/null +++ b/.github/scripts/abcexe.vcxproj @@ -0,0 +1,62 @@ + + + + + Release + Win32 + + + + 17.0 + {6B6D7E0F-1234-4567-89AB-CDEF01234568} + Win32Proj + abcexe + abc + + + + Application + false + v143 + true + MultiByte + + + + + + + _TEST\ + ReleaseExe\ + + + + Level3 + 4146;4334;4996;4703;%(DisableSpecificWarnings) + true + true + true + WIN32;WINDOWS;NDEBUG;_CONSOLE;ABC_DLL=ABC_DLLEXPORT;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ABC_USE_PTHREADS;ABC_USE_CUDD;HAVE_STRUCT_TIMESPEC;_WINSOCKAPI_;%(PreprocessorDefinitions) + true + stdcpp17 + src + /Zc:strictStrings- %(AdditionalOptions) + + + Console + true + true + true + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;lib\x86\pthreadVC2.lib;%(AdditionalDependencies) + + + + + + + + {6B6D7E0F-1234-4567-89AB-CDEF01234567} + + + + diff --git a/.github/scripts/abclib.vcxproj.template b/.github/scripts/abclib.vcxproj.template new file mode 100644 index 0000000000..77498528db --- /dev/null +++ b/.github/scripts/abclib.vcxproj.template @@ -0,0 +1,52 @@ + + + + + Release + Win32 + + + + 17.0 + {6B6D7E0F-1234-4567-89AB-CDEF01234567} + Win32Proj + abclib + + + + StaticLibrary + false + v143 + true + MultiByte + + + + + + + lib\ + ReleaseLib\ + + + + Level3 + 4146;4334;4996;4703;%(DisableSpecificWarnings) + true + true + true + WIN32;WINDOWS;NDEBUG;_LIB;ABC_DLL=ABC_DLLEXPORT;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ABC_USE_PTHREADS;ABC_USE_CUDD;HAVE_STRUCT_TIMESPEC;_WINSOCKAPI_;%(PreprocessorDefinitions) + true + stdcpp17 + src + /Zc:strictStrings- %(AdditionalOptions) + + + $(OutDir)abcr.lib + + + +{{SOURCE_FILES}} + + + diff --git a/.github/scripts/abcspace.sln b/.github/scripts/abcspace.sln new file mode 100644 index 0000000000..2c68905790 --- /dev/null +++ b/.github/scripts/abcspace.sln @@ -0,0 +1,22 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "abclib", "abclib.vcxproj", "{6B6D7E0F-1234-4567-89AB-CDEF01234567}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "abcexe", "abcexe.vcxproj", "{6B6D7E0F-1234-4567-89AB-CDEF01234568}" + ProjectSection(ProjectDependencies) = postProject + {6B6D7E0F-1234-4567-89AB-CDEF01234567} = {6B6D7E0F-1234-4567-89AB-CDEF01234567} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6B6D7E0F-1234-4567-89AB-CDEF01234567}.Release|Win32.ActiveCfg = Release|Win32 + {6B6D7E0F-1234-4567-89AB-CDEF01234567}.Release|Win32.Build.0 = Release|Win32 + {6B6D7E0F-1234-4567-89AB-CDEF01234568}.Release|Win32.ActiveCfg = Release|Win32 + {6B6D7E0F-1234-4567-89AB-CDEF01234568}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection +EndGlobal diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 6ed4a74b44..7b6e613041 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -22,179 +22,38 @@ jobs: with: arch: x86 - - name: Generate solution and project files from dsp + - name: Copy project files from scripts + run: | + copy .github\scripts\abcspace.sln . + copy .github\scripts\abcexe.vcxproj . + + - name: Generate abclib.vcxproj from dsp shell: powershell run: | # Parse source files from abclib.dsp $dspContent = Get-Content "abclib.dsp" -Raw - # Match SOURCE=. followed by path (e.g., SOURCE=.\src\base\abc\abc.c) - # Capture the path without the leading backslash $sourceFiles = [regex]::Matches($dspContent, 'SOURCE=\.\\([^\r\n]+)') | ForEach-Object { $_.Groups[1].Value } | Sort-Object -Unique Write-Host "Found $($sourceFiles.Count) source files" - # Create the solution file (use tabs for indentation) - $slnContent = "Microsoft Visual Studio Solution File, Format Version 12.00`r`n" - $slnContent += "VisualStudioVersion = 17.0.31903.59`r`n" - $slnContent += "MinimumVisualStudioVersion = 10.0.40219.1`r`n" - $slnContent += 'Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "abclib", "abclib.vcxproj", "{6B6D7E0F-1234-4567-89AB-CDEF01234567}"' + "`r`n" - $slnContent += "EndProject`r`n" - $slnContent += 'Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "abcexe", "abcexe.vcxproj", "{6B6D7E0F-1234-4567-89AB-CDEF01234568}"' + "`r`n" - $slnContent += "`tProjectSection(ProjectDependencies) = postProject`r`n" - $slnContent += "`t`t{6B6D7E0F-1234-4567-89AB-CDEF01234567} = {6B6D7E0F-1234-4567-89AB-CDEF01234567}`r`n" - $slnContent += "`tEndProjectSection`r`n" - $slnContent += "EndProject`r`n" - $slnContent += "Global`r`n" - $slnContent += "`tGlobalSection(SolutionConfigurationPlatforms) = preSolution`r`n" - $slnContent += "`t`tRelease|Win32 = Release|Win32`r`n" - $slnContent += "`tEndGlobalSection`r`n" - $slnContent += "`tGlobalSection(ProjectConfigurationPlatforms) = postSolution`r`n" - $slnContent += "`t`t{6B6D7E0F-1234-4567-89AB-CDEF01234567}.Release|Win32.ActiveCfg = Release|Win32`r`n" - $slnContent += "`t`t{6B6D7E0F-1234-4567-89AB-CDEF01234567}.Release|Win32.Build.0 = Release|Win32`r`n" - $slnContent += "`t`t{6B6D7E0F-1234-4567-89AB-CDEF01234568}.Release|Win32.ActiveCfg = Release|Win32`r`n" - $slnContent += "`t`t{6B6D7E0F-1234-4567-89AB-CDEF01234568}.Release|Win32.Build.0 = Release|Win32`r`n" - $slnContent += "`tEndGlobalSection`r`n" - $slnContent += "EndGlobal`r`n" - Set-Content "abcspace.sln" $slnContent -NoNewline - - # Build source file items for vcxproj - # Separate .c and .cpp files - .c files compile as C, .cpp files compile as C++ - $cCompileItems = "" - $cppCompileItems = "" - $clIncludeItems = "" + # Build source file items + $sourceItems = "" foreach ($src in $sourceFiles) { if ($src -match '\.c$') { - $cCompileItems += " `r`n" + $sourceItems += " `r`n" } elseif ($src -match '\.(cpp|cc)$') { - $cppCompileItems += " `r`n" + $sourceItems += " `r`n" } elseif ($src -match '\.h$') { - $clIncludeItems += " `r`n" + $sourceItems += " `r`n" } } - # Create abclib.vcxproj (static library) - $libVcxproj = '' + "`r`n" - $libVcxproj += '' + "`r`n" - $libVcxproj += ' ' + "`r`n" - $libVcxproj += ' ' + "`r`n" - $libVcxproj += ' Release' + "`r`n" - $libVcxproj += ' Win32' + "`r`n" - $libVcxproj += ' ' + "`r`n" - $libVcxproj += ' ' + "`r`n" - $libVcxproj += ' ' + "`r`n" - $libVcxproj += ' 17.0' + "`r`n" - $libVcxproj += ' {6B6D7E0F-1234-4567-89AB-CDEF01234567}' + "`r`n" - $libVcxproj += ' Win32Proj' + "`r`n" - $libVcxproj += ' abclib' + "`r`n" - $libVcxproj += ' ' + "`r`n" - $libVcxproj += ' ' + "`r`n" - $libVcxproj += ' ' + "`r`n" - $libVcxproj += ' StaticLibrary' + "`r`n" - $libVcxproj += ' false' + "`r`n" - $libVcxproj += ' v143' + "`r`n" - $libVcxproj += ' true' + "`r`n" - $libVcxproj += ' MultiByte' + "`r`n" - $libVcxproj += ' ' + "`r`n" - $libVcxproj += ' ' + "`r`n" - $libVcxproj += ' ' + "`r`n" - $libVcxproj += ' ' + "`r`n" - $libVcxproj += ' ' + "`r`n" - $libVcxproj += ' ' + "`r`n" - $libVcxproj += ' lib\' + "`r`n" - $libVcxproj += ' ReleaseLib\' + "`r`n" - $libVcxproj += ' ' + "`r`n" - $libVcxproj += ' ' + "`r`n" - $libVcxproj += ' ' + "`r`n" - $libVcxproj += ' Level3' + "`r`n" - $libVcxproj += ' 4146;4334;4996;4703;%(DisableSpecificWarnings)' + "`r`n" - $libVcxproj += ' true' + "`r`n" - $libVcxproj += ' true' + "`r`n" - $libVcxproj += ' true' + "`r`n" - $libVcxproj += ' WIN32;WINDOWS;NDEBUG;_LIB;ABC_DLL=ABC_DLLEXPORT;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ABC_USE_PTHREADS;ABC_USE_CUDD;HAVE_STRUCT_TIMESPEC;_WINSOCKAPI_;%(PreprocessorDefinitions)' + "`r`n" - $libVcxproj += ' true' + "`r`n" - $libVcxproj += ' stdcpp17' + "`r`n" - $libVcxproj += ' src' + "`r`n" - $libVcxproj += ' /Zc:strictStrings- %(AdditionalOptions)' + "`r`n" - $libVcxproj += ' ' + "`r`n" - $libVcxproj += ' ' + "`r`n" - $libVcxproj += ' $(OutDir)abcr.lib' + "`r`n" - $libVcxproj += ' ' + "`r`n" - $libVcxproj += ' ' + "`r`n" - $libVcxproj += ' ' + "`r`n" - $libVcxproj += $cCompileItems - $libVcxproj += $cppCompileItems - $libVcxproj += $clIncludeItems - $libVcxproj += ' ' + "`r`n" - $libVcxproj += ' ' + "`r`n" - $libVcxproj += '' + "`r`n" - Set-Content "abclib.vcxproj" $libVcxproj -NoNewline - - # Create abcexe.vcxproj (executable) - $exeVcxproj = '' + "`r`n" - $exeVcxproj += '' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' Release' + "`r`n" - $exeVcxproj += ' Win32' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' 17.0' + "`r`n" - $exeVcxproj += ' {6B6D7E0F-1234-4567-89AB-CDEF01234568}' + "`r`n" - $exeVcxproj += ' Win32Proj' + "`r`n" - $exeVcxproj += ' abcexe' + "`r`n" - $exeVcxproj += ' abc' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' Application' + "`r`n" - $exeVcxproj += ' false' + "`r`n" - $exeVcxproj += ' v143' + "`r`n" - $exeVcxproj += ' true' + "`r`n" - $exeVcxproj += ' MultiByte' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' _TEST\' + "`r`n" - $exeVcxproj += ' ReleaseExe\' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' Level3' + "`r`n" - $exeVcxproj += ' 4146;4334;4996;4703;%(DisableSpecificWarnings)' + "`r`n" - $exeVcxproj += ' true' + "`r`n" - $exeVcxproj += ' true' + "`r`n" - $exeVcxproj += ' true' + "`r`n" - $exeVcxproj += ' WIN32;WINDOWS;NDEBUG;_CONSOLE;ABC_DLL=ABC_DLLEXPORT;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ABC_USE_PTHREADS;ABC_USE_CUDD;HAVE_STRUCT_TIMESPEC;_WINSOCKAPI_;%(PreprocessorDefinitions)' + "`r`n" - $exeVcxproj += ' true' + "`r`n" - $exeVcxproj += ' stdcpp17' + "`r`n" - $exeVcxproj += ' src' + "`r`n" - $exeVcxproj += ' /Zc:strictStrings- %(AdditionalOptions)' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' Console' + "`r`n" - $exeVcxproj += ' true' + "`r`n" - $exeVcxproj += ' true' + "`r`n" - $exeVcxproj += ' true' + "`r`n" - $exeVcxproj += ' kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;lib\x86\pthreadVC2.lib;%(AdditionalDependencies)' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' {6B6D7E0F-1234-4567-89AB-CDEF01234567}' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += ' ' + "`r`n" - $exeVcxproj += '' + "`r`n" - Set-Content "abcexe.vcxproj" $exeVcxproj -NoNewline + # Read template and replace placeholder + $template = Get-Content ".github\scripts\abclib.vcxproj.template" -Raw + $vcxproj = $template -replace '\{\{SOURCE_FILES\}\}', $sourceItems + Set-Content "abclib.vcxproj" $vcxproj -NoNewline - Write-Host "Project files generated successfully" + Write-Host "abclib.vcxproj generated successfully" - name: Build run: | @@ -216,4 +75,4 @@ jobs: uses: actions/upload-artifact@v4 with: name: package-windows - path: staging/ + path: staging/ \ No newline at end of file diff --git a/.gitignore b/.gitignore index bef9a6aa4b..7236839d31 100644 --- a/.gitignore +++ b/.gitignore @@ -37,7 +37,7 @@ abcext.dsp abcexe.vcproj* abclib.vcproj* -abcspace.sln +/abcspace.sln abcspace.suo *.pyc @@ -62,4 +62,4 @@ tags /cmake /cscope -abc.history +abc.history \ No newline at end of file From ef54c1daea94cac406e3c4bdbbe2ee20c8105c8e Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Tue, 24 Feb 2026 14:59:13 -0800 Subject: [PATCH 11/33] Updating interface of &cec. --- src/base/abci/abc.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 2071b9d57f..f1bef5e235 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -35189,7 +35189,7 @@ int Abc_CommandAbc9WriteVer( Abc_Frame_t * pAbc, int argc, char ** argv ) return 1; } // Check if we should write LUT-based Verilog - if ( fUseLuts || (Gia_ManHasMapping(pAbc->pGia) && !fUseGates) ) + if ( fUseLuts ) { if ( !Gia_ManHasMapping(pAbc->pGia) ) { @@ -35232,7 +35232,6 @@ int Abc_CommandAbc9WriteVer( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_Print( -2, "\t-v : toggle verbose output [default = %s]\n", fVerbose? "yes": "no" ); Abc_Print( -2, "\t-h : print the command usage\n"); Abc_Print( -2, "\t : the file name\n"); - Abc_Print( -2, "\tNote: When AIG is mapped and -l is not specified, LUT-based output is automatically used.\n"); return 1; } @@ -42601,7 +42600,7 @@ int Abc_CommandAbc9EquivFilter( Abc_Frame_t * pAbc, int argc, char ** argv ) SeeAlso [] ***********************************************************************/ -static Gia_Man_t * Abc_ReadAigerOrVerilogFile( char * pFileName, char * pTopModule, int * pAbc_ReadAigerOrVerilogFileStatus ) +static Gia_Man_t * Abc_ReadAigerOrVerilogFile( char * pFileName, char * pTopModule, char * pDefines, int * pAbc_ReadAigerOrVerilogFileStatus ) { FILE * pFile; Gia_Man_t * pGia; @@ -42637,7 +42636,8 @@ static Gia_Man_t * Abc_ReadAigerOrVerilogFile( char * pFileName, char * pTopModu // Save the original filename before changing it pOrigFileName = pFileName; snprintf( pCommand, sizeof(pCommand), - "yosys -qp \"read_verilog %s%s; hierarchy %s%s; flatten; proc; opt; async2sync; opt; setundef -undriven -zero; techmap; memory -nomap; memory_map; dffunmap; opt_clean; opt_expr; aigmap; write_aiger -symbols _temp_.aig\"", + "yosys -qp \"read_verilog %s%s %s%s; hierarchy %s%s; flatten; proc; opt; async2sync; opt; setundef -undriven -zero; techmap; memory -nomap; memory_map; dffunmap; opt_clean; opt_expr; aigmap; write_aiger -symbols _temp_.aig\"", + pDefines ? "-D" : "", pDefines ? pDefines : "", fSystemVerilog ? "-sv " : "", pFileName, pTopModule ? "-top " : "-auto-top", pTopModule ? pTopModule : "" ); #if defined(__wasm) RetValue = 1; @@ -42685,12 +42685,12 @@ int Abc_CommandAbc9Cec( Abc_Frame_t * pAbc, int argc, char ** argv ) extern void Cec_ManPrintCexSummary( Gia_Man_t * p, Abc_Cex_t * pCex, Cec_ParCec_t * pPars ); Cec_ParCec_t ParsCec, * pPars = &ParsCec; Gia_Man_t * pGias[2] = {NULL, NULL}, * pMiter; - char ** pArgvNew, * pTopModule = NULL; + char ** pArgvNew, * pTopModule = NULL, * pDefines = NULL; int c, nArgcNew, fUseSim = 0, fUseNewX = 0, fUseNewY = 0, fMiter = 0, fDualOutput = 0, fDumpMiter = 0, fSavedSpec = 0; int Abc_ReadAigerOrVerilogFileStatus = 0; Cec_ManCecSetDefaultParams( pPars ); Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "CTMnmdbasxytvwh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "CTMDnmdbasxytvwh" ) ) != EOF ) { switch ( c ) { @@ -42725,6 +42725,15 @@ int Abc_CommandAbc9Cec( Abc_Frame_t * pAbc, int argc, char ** argv ) pTopModule = argv[globalUtilOptind]; globalUtilOptind++; break; + case 'D': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-D\" should be followed by defines.\n" ); + goto usage; + } + pDefines = argv[globalUtilOptind]; + globalUtilOptind++; + break; case 'n': pPars->fNaive ^= 1; break; @@ -42846,7 +42855,7 @@ int Abc_CommandAbc9Cec( Abc_Frame_t * pAbc, int argc, char ** argv ) int n; for ( n = 0; n < 2; n++ ) { - pGias[n] = Abc_ReadAigerOrVerilogFile( pFileNames[n], pTopModule, &Abc_ReadAigerOrVerilogFileStatus ); + pGias[n] = Abc_ReadAigerOrVerilogFile( pFileNames[n], pTopModule, pDefines, &Abc_ReadAigerOrVerilogFileStatus ); if ( pGias[n] == NULL ) return Abc_ReadAigerOrVerilogFileStatus; } @@ -42882,7 +42891,7 @@ int Abc_CommandAbc9Cec( Abc_Frame_t * pAbc, int argc, char ** argv ) } FileName = pAbc->pGia->pSpec; } - pGias[1] = Abc_ReadAigerOrVerilogFile( FileName, pTopModule, &Abc_ReadAigerOrVerilogFileStatus ); + pGias[1] = Abc_ReadAigerOrVerilogFile( FileName, pTopModule, pDefines, &Abc_ReadAigerOrVerilogFileStatus ); if ( pGias[1] == NULL ) return Abc_ReadAigerOrVerilogFileStatus; } @@ -42994,11 +43003,12 @@ int Abc_CommandAbc9Cec( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - Abc_Print( -2, "usage: &cec [-CT num] [-M str] [-nmdbasxytvwh]\n" ); + Abc_Print( -2, "usage: &cec [-CT num] [-M str] [-D str] [-nmdbasxytvwh]\n" ); Abc_Print( -2, "\t new combinational equivalence checker\n" ); Abc_Print( -2, "\t-C num : the max number of conflicts at a node [default = %d]\n", pPars->nBTLimit ); Abc_Print( -2, "\t-T num : approximate runtime limit in seconds [default = %d]\n", pPars->TimeLimit ); - Abc_Print( -2, "\t-M str : top module name if Verilog file(s) are used [default = %d]\n", pPars->TimeLimit ); + Abc_Print( -2, "\t-M str : top module name if Verilog file(s) are used [default = \"not used\"]\n" ); + Abc_Print( -2, "\t-D str : defines to be used by Yosys for Verilog files [default = \"not used\"]\n" ); Abc_Print( -2, "\t-n : toggle using naive SAT-based checking [default = %s]\n", pPars->fNaive? "yes":"no"); Abc_Print( -2, "\t-m : toggle miter vs. two circuits [default = %s]\n", fMiter? "miter":"two circuits"); Abc_Print( -2, "\t-d : toggle using dual output miter [default = %s]\n", fDualOutput? "yes":"no"); From d5c1f2cfe12f23778ac8adfd964e00da7e580113 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Wed, 25 Feb 2026 20:00:28 -0800 Subject: [PATCH 12/33] Adding callbacks to "scorr" and "&scorr". --- src/proof/cec/cecCorr.c | 30 ++++++++++++++++++++++++------ src/proof/ssw/sswConstr.c | 8 ++++++++ src/proof/ssw/sswCore.c | 20 +++++++++++++------- src/proof/ssw/sswDyn.c | 2 ++ src/proof/ssw/sswInt.h | 2 +- src/proof/ssw/sswSweep.c | 8 ++++++++ 6 files changed, 56 insertions(+), 14 deletions(-) diff --git a/src/proof/cec/cecCorr.c b/src/proof/cec/cecCorr.c index 8d4c730a18..0496b2e49b 100644 --- a/src/proof/cec/cecCorr.c +++ b/src/proof/cec/cecCorr.c @@ -22,6 +22,13 @@ ABC_NAMESPACE_IMPL_START +static inline int Cec_ParCorShouldStop( Cec_ParCor_t * pPars ) +{ + if ( pPars == NULL || pPars->pFunc == NULL ) + return 0; + return ((int (*)(void *))pPars->pFunc)( pPars->pData ); +} + //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// @@ -808,6 +815,8 @@ void Cec_ManLSCorrespondenceBmc( Gia_Man_t * pAig, Cec_ParCor_t * pPars, int nPr fChanges = 1; for ( i = 0; fChanges && (!pPars->nLimitMax || i < pPars->nLimitMax); i++ ) { + if ( Cec_ParCorShouldStop( pPars ) ) + break; abctime clkBmc = Abc_Clock(); fChanges = 0; pSrm = Gia_ManCorrSpecReduceInit( pAig, pPars->nFrames, nPrefs, !pPars->fLatchCorr, &vOutputs, pPars->fUseRings ); @@ -836,6 +845,8 @@ void Cec_ManLSCorrespondenceBmc( Gia_Man_t * pAig, Cec_ParCor_t * pPars, int nPr Vec_StrFree( vStatus ); Gia_ManStop( pSrm ); Vec_IntFree( vOutputs ); + if ( Cec_ParCorShouldStop( pPars ) ) + break; } Cec_ManSimStop( pSim ); } @@ -975,10 +986,10 @@ int Cec_ManLSCorrespondenceClasses( Gia_Man_t * pAig, Cec_ParCor_t * pPars ) // check the base case if ( fRunBmcFirst && (!pPars->fLatchCorr || pPars->nFrames > 1) ) Cec_ManLSCorrespondenceBmc( pAig, pPars, 0 ); - if ( pPars->pFunc ) + if ( Cec_ParCorShouldStop( pPars ) ) { - ((int (*)(void *))pPars->pFunc)( pPars->pData ); - ((int (*)(void *))pPars->pFunc)( pPars->pData ); + Cec_ManSimStop( pSim ); + return 1; } if ( pPars->nStepsMax == 0 ) { @@ -989,6 +1000,11 @@ int Cec_ManLSCorrespondenceClasses( Gia_Man_t * pAig, Cec_ParCor_t * pPars ) // perform refinement of equivalence classes for ( r = 0; r < nIterMax; r++ ) { + if ( Cec_ParCorShouldStop( pPars ) ) + { + Cec_ManSimStop( pSim ); + return 1; + } if ( pPars->nStepsMax == r ) { Cec_ManSimStop( pSim ); @@ -1036,8 +1052,11 @@ int Cec_ManLSCorrespondenceClasses( Gia_Man_t * pAig, Cec_ParCor_t * pPars ) Vec_StrFree( vStatus ); Vec_IntFree( vOutputs ); //Gia_ManEquivPrintClasses( pAig, 1, 0 ); - if ( pPars->pFunc ) - ((int (*)(void *))pPars->pFunc)( pPars->pData ); + if ( Cec_ParCorShouldStop( pPars ) ) + { + Cec_ManSimStop( pSim ); + return 1; + } // quit if const is no longer there if ( pPars->fStopWhenGone && Gia_ManPoNum(pAig) == 1 && !Gia_ObjIsConst( pAig, Gia_ObjFaninId0p(pAig, Gia_ManPo(pAig, 0)) ) ) { @@ -1448,4 +1467,3 @@ Gia_Man_t * Gia_ManDupStopsTest( Gia_Man_t * p ) ABC_NAMESPACE_IMPL_END - diff --git a/src/proof/ssw/sswConstr.c b/src/proof/ssw/sswConstr.c index a3a7e66f34..d8be282fad 100644 --- a/src/proof/ssw/sswConstr.c +++ b/src/proof/ssw/sswConstr.c @@ -512,6 +512,8 @@ clk = Abc_Clock(); p->fRefined = 0; for ( f = 0; f < p->pPars->nFramesK; f++ ) { + if ( Ssw_ManCallbackStop(p) ) + break; // map constants and PIs Ssw_ObjSetFrame( p, Aig_ManConst1(p->pAig), f, Aig_ManConst1(p->pFrames) ); Saig_ManForEachPi( p->pAig, pObj, i ) @@ -540,10 +542,14 @@ clk = Abc_Clock(); // sweep internal nodes Aig_ManForEachNode( p->pAig, pObj, i ) { + if ( Ssw_ManCallbackStop(p) ) + break; pObjNew = Aig_And( p->pFrames, Ssw_ObjChild0Fra(p, pObj, f), Ssw_ObjChild1Fra(p, pObj, f) ); Ssw_ObjSetFrame( p, pObj, f, pObjNew ); p->fRefined |= Ssw_ManSweepNodeConstr( p, pObj, f, 1 ); } + if ( i < Aig_ManObjNumMax(p->pAig) ) + break; // quit if this is the last timeframe if ( f == p->pPars->nFramesK - 1 ) break; @@ -692,6 +698,8 @@ p->timeReduce += Abc_Clock() - clk; pProgress = Bar_ProgressStart( stdout, Aig_ManObjNumMax(p->pAig) ); Aig_ManForEachObj( p->pAig, pObj, i ) { + if ( Ssw_ManCallbackStop(p) ) + break; if ( p->pPars->fVerbose ) Bar_ProgressUpdate( pProgress, i, NULL ); if ( Saig_ObjIsLo(p->pAig, pObj) ) diff --git a/src/proof/ssw/sswCore.c b/src/proof/ssw/sswCore.c index 1307d67c93..9add71284d 100644 --- a/src/proof/ssw/sswCore.c +++ b/src/proof/ssw/sswCore.c @@ -238,6 +238,7 @@ Aig_Man_t * Ssw_SignalCorrespondenceRefine( Ssw_Man_t * p ) Aig_Man_t * pAigNew; int RetValue, nIter = -1, nPrev[4] = {0}; abctime clk, clkTotal = Abc_Clock(); + abctime nTimeToStop = p->pPars->TimeLimit > 0 ? clkTotal + (abctime)p->pPars->TimeLimit * CLOCKS_PER_SEC : 0; // get the starting stats p->nLitsBeg = Ssw_ClassesLitNum( p->ppClasses ); p->nNodesBeg = Aig_ManNodeNum(p->pAig); @@ -251,6 +252,8 @@ Aig_Man_t * Ssw_SignalCorrespondenceRefine( Ssw_Man_t * p ) if ( !p->pPars->fLatchCorr || p->pPars->nFramesK > 1 ) { p->pMSat = Ssw_SatStart( 0 ); + if ( nTimeToStop ) + sat_solver_set_runtime_limit( p->pMSat->pSat, nTimeToStop ); if ( p->pPars->fConstrs ) Ssw_ManSweepBmcConstr( p ); else @@ -276,11 +279,8 @@ Aig_Man_t * Ssw_SignalCorrespondenceRefine( Ssw_Man_t * p ) Aig_ManStop( pSRed ); } */ - if ( p->pPars->pFunc ) - { - ((int (*)(void *))p->pPars->pFunc)( p->pPars->pData ); - ((int (*)(void *))p->pPars->pFunc)( p->pPars->pData ); - } + if ( Ssw_ManCallbackStop(p) || Ssw_ManCallbackStop(p) ) + goto finalize; if ( p->pPars->nStepsMax == 0 ) { Abc_Print( 1, "Stopped signal correspondence after BMC.\n" ); @@ -290,6 +290,8 @@ Aig_Man_t * Ssw_SignalCorrespondenceRefine( Ssw_Man_t * p ) nSatProof = nSatCallsSat = nRecycles = nSatFailsReal = nUniques = 0; for ( nIter = 0; ; nIter++ ) { + if ( nTimeToStop && Abc_Clock() >= nTimeToStop ) + goto finalize; if ( p->pPars->nStepsMax == nIter ) { Abc_Print( 1, "Stopped signal correspondence after %d refiment iterations.\n", nIter ); @@ -306,9 +308,13 @@ Aig_Man_t * Ssw_SignalCorrespondenceRefine( Ssw_Man_t * p ) Abc_Print( 1, "If the miter is SAT, the reduced result is incorrect.\n" ); break; } + if ( Ssw_ManCallbackStop(p) ) + goto finalize; clk = Abc_Clock(); p->pMSat = Ssw_SatStart( 0 ); + if ( nTimeToStop ) + sat_solver_set_runtime_limit( p->pMSat->pSat, nTimeToStop ); if ( p->pPars->fLatchCorrOpt ) { RetValue = Ssw_ManSweepLatch( p ); @@ -379,8 +385,8 @@ clk = Abc_Clock(); Ssw_ManCleanup( p ); if ( !RetValue ) break; - if ( p->pPars->pFunc ) - ((int (*)(void *))p->pPars->pFunc)( p->pPars->pData ); + if ( Ssw_ManCallbackStop(p) ) + goto finalize; if ( p->pPars->nLimitMax ) { int nCur = Ssw_ClassesCand1Num(p->ppClasses); diff --git a/src/proof/ssw/sswDyn.c b/src/proof/ssw/sswDyn.c index 316b2e4d1c..a2654ca0b6 100644 --- a/src/proof/ssw/sswDyn.c +++ b/src/proof/ssw/sswDyn.c @@ -407,6 +407,8 @@ p->timeReduce += Abc_Clock() - clk; p->iNodeStart = 0; Aig_ManForEachObj( p->pAig, pObj, i ) { + if ( Ssw_ManCallbackStop(p) ) + break; if ( p->iNodeStart == 0 ) p->iNodeStart = i; if ( p->pPars->fVerbose ) diff --git a/src/proof/ssw/sswInt.h b/src/proof/ssw/sswInt.h index 0068192375..11f60fdd9a 100644 --- a/src/proof/ssw/sswInt.h +++ b/src/proof/ssw/sswInt.h @@ -190,6 +190,7 @@ static inline void Ssw_ObjSetFrame_( Ssw_Frm_t * p, Aig_Obj_t * pObj, int static inline Aig_Obj_t * Ssw_ObjChild0Fra_( Ssw_Frm_t * p, Aig_Obj_t * pObj, int i ) { assert( !Aig_IsComplement(pObj) ); return Aig_ObjFanin0(pObj)? Aig_NotCond(Ssw_ObjFrame_(p, Aig_ObjFanin0(pObj), i), Aig_ObjFaninC0(pObj)) : NULL; } static inline Aig_Obj_t * Ssw_ObjChild1Fra_( Ssw_Frm_t * p, Aig_Obj_t * pObj, int i ) { assert( !Aig_IsComplement(pObj) ); return Aig_ObjFanin1(pObj)? Aig_NotCond(Ssw_ObjFrame_(p, Aig_ObjFanin1(pObj), i), Aig_ObjFaninC1(pObj)) : NULL; } +static inline int Ssw_ManCallbackStop( Ssw_Man_t * p ) { return (p && p->pPars && p->pPars->pFunc) ? ((int (*)(void *))p->pPars->pFunc)( p->pPars->pData ) : 0; } //////////////////////////////////////////////////////////////////////// /// FUNCTION DECLARATIONS /// @@ -299,4 +300,3 @@ ABC_NAMESPACE_HEADER_END //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// - diff --git a/src/proof/ssw/sswSweep.c b/src/proof/ssw/sswSweep.c index 2687e9c1c0..ead977af33 100644 --- a/src/proof/ssw/sswSweep.c +++ b/src/proof/ssw/sswSweep.c @@ -288,6 +288,8 @@ clk = Abc_Clock(); pProgress = Bar_ProgressStart( stdout, Aig_ManObjNumMax(p->pAig) * p->pPars->nFramesK ); for ( f = 0; f < p->pPars->nFramesK; f++ ) { + if ( Ssw_ManCallbackStop(p) ) + break; // map constants and PIs Ssw_ObjSetFrame( p, Aig_ManConst1(p->pAig), f, Aig_ManConst1(p->pFrames) ); Saig_ManForEachPi( p->pAig, pObj, i ) @@ -298,12 +300,16 @@ clk = Abc_Clock(); // sweep internal nodes Aig_ManForEachNode( p->pAig, pObj, i ) { + if ( Ssw_ManCallbackStop(p) ) + break; if ( p->pPars->fVerbose ) Bar_ProgressUpdate( pProgress, Aig_ManObjNumMax(p->pAig) * f + i, NULL ); pObjNew = Aig_And( p->pFrames, Ssw_ObjChild0Fra(p, pObj, f), Ssw_ObjChild1Fra(p, pObj, f) ); Ssw_ObjSetFrame( p, pObj, f, pObjNew ); p->fRefined |= Ssw_ManSweepNode( p, pObj, f, 1, NULL ); } + if ( i < Aig_ManObjNumMax(p->pAig) ) + break; // quit if this is the last timeframe if ( f == p->pPars->nFramesK - 1 ) break; @@ -415,6 +421,8 @@ p->timeReduce += Abc_Clock() - clk; vObjPairs = (p->pPars->fEquivDump || p->pPars->fEquivDump2)? Vec_IntAlloc(1000) : NULL; Aig_ManForEachObj( p->pAig, pObj, i ) { + if ( Ssw_ManCallbackStop(p) ) + break; if ( p->pPars->fVerbose ) Bar_ProgressUpdate( pProgress, i, NULL ); if ( Saig_ObjIsLo(p->pAig, pObj) ) From c1937d12ac9fddb26e59bae6fc38b7a7c14959ee Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Wed, 25 Feb 2026 20:00:57 -0800 Subject: [PATCH 13/33] Improvements to &sprove. --- src/proof/cec/cecProve.c | 65 ++++++++++++++++++++++++++++++++-------- 1 file changed, 52 insertions(+), 13 deletions(-) diff --git a/src/proof/cec/cecProve.c b/src/proof/cec/cecProve.c index 273791fe46..2de1b68b65 100644 --- a/src/proof/cec/cecProve.c +++ b/src/proof/cec/cecProve.c @@ -64,6 +64,8 @@ int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, in #define PAR_THR_MAX 8 #define PAR_ENGINE_UFAR 6 +#define PAR_ENGINE_SCORR1 7 +#define PAR_ENGINE_SCORR2 8 struct Par_Share_t_ { volatile int fSolved; @@ -82,7 +84,25 @@ typedef struct Par_ThData_t_ Wlc_Ntk_t * pWlc; Par_Share_t * pShare; } Par_ThData_t; +typedef struct Cec_ScorrStop_t_ +{ + Par_Share_t * pShare; + abctime TimeToStop; +} Cec_ScorrStop_t; static volatile Par_Share_t * g_pUfarShare = NULL; +static inline const char * Cec_SolveEngineName( int iEngine ) +{ + if ( iEngine == 0 ) return "rar"; + if ( iEngine == 1 ) return "bmc"; + if ( iEngine == 2 ) return "pdr"; + if ( iEngine == 3 ) return "bmc-glucose"; + if ( iEngine == 4 ) return "pdr-abs"; + if ( iEngine == 5 ) return "bmcg"; + if ( iEngine == PAR_ENGINE_UFAR ) return "ufar"; + if ( iEngine == PAR_ENGINE_SCORR1 ) return "scorr-new"; + if ( iEngine == PAR_ENGINE_SCORR2 ) return "scorr-old"; + return "unknown"; +} static inline void Cec_CopyGiaName( Gia_Man_t * pSrc, Gia_Man_t * pDst ) { char * pName = pSrc->pName ? pSrc->pName : pSrc->pSpec; @@ -108,6 +128,17 @@ static int Cec_SProveStopUfar( int RunId ) (void)RunId; return g_pUfarShare && g_pUfarShare->fSolved != 0; } +static int Cec_ScorrStop( void * pUser ) +{ + Cec_ScorrStop_t * p = (Cec_ScorrStop_t *)pUser; + if ( p == NULL ) + return 0; + if ( p->pShare && p->pShare->fSolved ) + return 1; + if ( p->TimeToStop && Abc_Clock() >= p->TimeToStop ) + return 1; + return 0; +} static int Cec_SProveCallback( void * pUser, int fSolved, unsigned Result ) { Par_ThData_t * pThData = (Par_ThData_t *)pUser; @@ -273,12 +304,15 @@ int Cec_GiaProveOne( Gia_Man_t * p, int iEngine, int nTimeOut, int fVerbose, Par } return RetValue; } -Gia_Man_t * Cec_GiaScorrOld( Gia_Man_t * p ) +Gia_Man_t * Cec_GiaScorrOld( Gia_Man_t * p, int nTimeOut, Par_Share_t * pShare ) { + Cec_ScorrStop_t Stop = { pShare, nTimeOut > 0 ? Abc_Clock() + (abctime)nTimeOut * CLOCKS_PER_SEC : 0 }; if ( Gia_ManRegNum(p) == 0 ) return Gia_ManDup( p ); Ssw_Pars_t Pars, * pPars = &Pars; Ssw_ManSetDefaultParams( pPars ); + pPars->pFunc = (void *)Cec_ScorrStop; + pPars->pData = (void *)&Stop; Aig_Man_t * pAig = Gia_ManToAigSimple( p ); Aig_Man_t * pAig2 = Ssw_SignalCorrespondence( pAig, pPars ); Gia_Man_t * pGia2 = Gia_ManFromAigSimple( pAig2 ); @@ -286,8 +320,9 @@ Gia_Man_t * Cec_GiaScorrOld( Gia_Man_t * p ) Aig_ManStop( pAig ); return pGia2; } -Gia_Man_t * Cec_GiaScorrNew( Gia_Man_t * p ) +Gia_Man_t * Cec_GiaScorrNew( Gia_Man_t * p, int nTimeOut, Par_Share_t * pShare ) { + Cec_ScorrStop_t Stop = { pShare, nTimeOut > 0 ? Abc_Clock() + (abctime)nTimeOut * CLOCKS_PER_SEC : 0 }; if ( Gia_ManRegNum(p) == 0 ) return Gia_ManDup( p ); Cec_ParCor_t Pars, * pPars = &Pars; @@ -296,6 +331,8 @@ Gia_Man_t * Cec_GiaScorrNew( Gia_Man_t * p ) pPars->nLevelMax = 100; pPars->fVerbose = 0; pPars->fUseCSat = 1; + pPars->pFunc = (void *)Cec_ScorrStop; + pPars->pData = (void *)&Stop; return Cec_ManLSCorrespondence( p, pPars ); } @@ -376,7 +413,7 @@ int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, in Par_ThData_t ThData[PAR_THR_MAX]; pthread_t WorkerThread[PAR_THR_MAX]; Par_Share_t Share; - int i, nWorkers = nProcs + (fUseUif ? 1 : 0), RetValue = -1, RetEngine = -2; + int i, nWorkers = nProcs + (fUseUif ? 1 : 0), RetValue = -1, RetEngine = -1; memset( &Share, 0, sizeof(Par_Share_t) ); Abc_CexFreeP( &p->pCexComb ); Abc_CexFreeP( &p->pCexSeq ); @@ -391,10 +428,10 @@ int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, in Cec_GiaInitThreads( ThData, nWorkers, p, nTimeOut, nTimeOut3, pWlc, fUseUif, fVerbose, WorkerThread, &Share ); // meanwhile, perform scorr - Gia_Man_t * pScorr = Cec_GiaScorrNew( p ); + Gia_Man_t * pScorr = Cec_GiaScorrNew( p, nTimeOut, &Share ); clkScorr = Abc_Clock() - clkTotal; if ( Gia_ManAndNum(pScorr) == 0 ) - RetValue = 1, RetEngine = -1; + RetValue = 1, RetEngine = PAR_ENGINE_SCORR1; RetValue = Cec_GiaWaitThreads( ThData, nWorkers, p, RetValue, &RetEngine ); if ( RetValue == -1 ) @@ -406,15 +443,15 @@ int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, in } Cec_GiaInitThreads( ThData, nWorkers, pScorr, nTimeOut2, nTimeOut3, pWlc, fUseUif, fVerbose, NULL, &Share ); - // meanwhile, perform scorr - if ( Gia_ManAndNum(pScorr) < 100000 ) + RetValue = Cec_GiaWaitThreads( ThData, nWorkers, p, RetValue, &RetEngine ); + if ( RetValue == -1 && Gia_ManAndNum(pScorr) < 100000 ) { - Gia_Man_t * pScorr2 = Cec_GiaScorrOld( pScorr ); + // Run this reduction only when round-2 did not decide the problem. + Gia_Man_t * pScorr2 = Cec_GiaScorrOld( pScorr, nTimeOut3, &Share ); clkScorr2 = Abc_Clock() - clkStart; if ( Gia_ManAndNum(pScorr2) == 0 ) - RetValue = 1; - - RetValue = Cec_GiaWaitThreads( ThData, nWorkers, p, RetValue, &RetEngine ); + RetValue = 1, RetEngine = PAR_ENGINE_SCORR2; + if ( RetValue == -1 ) { if ( !fSilent && fVerbose ) { @@ -440,11 +477,13 @@ int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, in if ( !fSilent ) { char * pProbName = p->pSpec ? p->pSpec : Gia_ManName(p); + if ( RetValue != -1 && RetEngine < 0 ) + RetEngine = PAR_ENGINE_SCORR1; printf( "Problem \"%s\" is ", pProbName ? pProbName : "(none)" ); if ( RetValue == 0 ) - printf( "SATISFIABLE (solved by %d).", RetEngine ); + printf( "SATISFIABLE (solved by %s).", Cec_SolveEngineName(RetEngine) ); else if ( RetValue == 1 ) - printf( "UNSATISFIABLE (solved by %d).", RetEngine ); + printf( "UNSATISFIABLE (solved by %s).", Cec_SolveEngineName(RetEngine) ); else if ( RetValue == -1 ) printf( "UNDECIDED." ); else assert( 0 ); From 4e5c5e62af3c5beda477578e55656c2c721ac5f9 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Wed, 25 Feb 2026 20:18:28 -0800 Subject: [PATCH 14/33] Compiler problem. --- src/proof/cec/cecProve.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/proof/cec/cecProve.c b/src/proof/cec/cecProve.c index 2de1b68b65..017296540f 100644 --- a/src/proof/cec/cecProve.c +++ b/src/proof/cec/cecProve.c @@ -306,7 +306,9 @@ int Cec_GiaProveOne( Gia_Man_t * p, int iEngine, int nTimeOut, int fVerbose, Par } Gia_Man_t * Cec_GiaScorrOld( Gia_Man_t * p, int nTimeOut, Par_Share_t * pShare ) { - Cec_ScorrStop_t Stop = { pShare, nTimeOut > 0 ? Abc_Clock() + (abctime)nTimeOut * CLOCKS_PER_SEC : 0 }; + Cec_ScorrStop_t Stop; + Stop.pShare = pShare; + Stop.TimeToStop = nTimeOut > 0 ? (abctime)(Abc_Clock() + (abctime)nTimeOut * CLOCKS_PER_SEC) : 0; if ( Gia_ManRegNum(p) == 0 ) return Gia_ManDup( p ); Ssw_Pars_t Pars, * pPars = &Pars; @@ -322,7 +324,9 @@ Gia_Man_t * Cec_GiaScorrOld( Gia_Man_t * p, int nTimeOut, Par_Share_t * pShare ) } Gia_Man_t * Cec_GiaScorrNew( Gia_Man_t * p, int nTimeOut, Par_Share_t * pShare ) { - Cec_ScorrStop_t Stop = { pShare, nTimeOut > 0 ? Abc_Clock() + (abctime)nTimeOut * CLOCKS_PER_SEC : 0 }; + Cec_ScorrStop_t Stop; + Stop.pShare = pShare; + Stop.TimeToStop = nTimeOut > 0 ? (abctime)(Abc_Clock() + (abctime)nTimeOut * CLOCKS_PER_SEC) : 0; if ( Gia_ManRegNum(p) == 0 ) return Gia_ManDup( p ); Cec_ParCor_t Pars, * pPars = &Pars; From f3a17d343a03a84e440acfc7336254f798e26ed2 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Thu, 26 Feb 2026 20:08:03 -0800 Subject: [PATCH 15/33] Fixing assertion failure introduced by a recent PR. --- src/misc/tim/timTime.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/misc/tim/timTime.c b/src/misc/tim/timTime.c index cc0aa5ffd5..8626cf6bb5 100644 --- a/src/misc/tim/timTime.c +++ b/src/misc/tim/timTime.c @@ -99,9 +99,10 @@ void Tim_ManInitPoRequiredAll( Tim_Man_t * p, float Delay ) Tim_Obj_t * pObj; int i; // If any PO or flop-input CO is constrained, leave all unchanged - Tim_ManForEachPo( p, pObj, i ) - if ( pObj->timeReq < TIM_ETERNITY ) - return; + // This led to an assertion failure in &if, so it is commented out below + //Tim_ManForEachPo( p, pObj, i ) + // if ( pObj->timeReq < TIM_ETERNITY ) + // return; // All unconstrained — set to max arrival time Tim_ManForEachPo( p, pObj, i ) Tim_ManSetCoRequired( p, i, Delay ); @@ -269,4 +270,3 @@ float Tim_ManGetCoRequired( Tim_Man_t * p, int iCo ) ABC_NAMESPACE_IMPL_END - From ee40e40d09685734f15466410c44bb1e1b0a812e Mon Sep 17 00:00:00 2001 From: Drew Lewis Date: Mon, 2 Mar 2026 22:22:27 +0000 Subject: [PATCH 16/33] Have the buffer grow with a 2x factor to avoid O(n^2) work when reading big files. Signed-off-by: Drew Lewis --- src/map/scl/sclLiberty.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/map/scl/sclLiberty.c b/src/map/scl/sclLiberty.c index 2064fde69d..06d40c84bf 100644 --- a/src/map/scl/sclLiberty.c +++ b/src/map/scl/sclLiberty.c @@ -559,14 +559,17 @@ static char * Io_LibLoadFileGz( char * pFileName, long * pnFileSize ) const int READ_BLOCK_SIZE = 100000; gzFile pFile; char * pContents; - long amtRead, readBlock, nFileSize = READ_BLOCK_SIZE; + long amtRead, readBlock, nFileSize = READ_BLOCK_SIZE, nCapacity = READ_BLOCK_SIZE; pFile = gzopen( pFileName, "rb" ); // if pFileName doesn't end in ".gz" then this acts as a passthrough to fopen - pContents = ABC_ALLOC( char, nFileSize ); + pContents = ABC_ALLOC( char, nCapacity ); readBlock = 0; while ((amtRead = gzread(pFile, pContents + readBlock * READ_BLOCK_SIZE, READ_BLOCK_SIZE)) == READ_BLOCK_SIZE) { //Abc_Print( 1,"%d: read %d bytes\n", readBlock, amtRead); nFileSize += READ_BLOCK_SIZE; - pContents = ABC_REALLOC(char, pContents, nFileSize); + if ( nFileSize > nCapacity ) { + nCapacity *= 2; + pContents = ABC_REALLOC(char, pContents, nCapacity); + } ++readBlock; } //Abc_Print( 1,"%d: read %d bytes\n", readBlock, amtRead); From c92cfab80bf75372f7597f0e4554d111ba735cbd Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sun, 8 Mar 2026 10:25:15 -0700 Subject: [PATCH 17/33] Adding new line at the end of AIGER files. --- src/aig/gia/giaAiger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aig/gia/giaAiger.c b/src/aig/gia/giaAiger.c index 39fed2fd47..c37c3ea9e4 100644 --- a/src/aig/gia/giaAiger.c +++ b/src/aig/gia/giaAiger.c @@ -1297,7 +1297,7 @@ Vec_Str_t * Gia_AigerWriteIntoMemoryStr( Gia_Man_t * p ) Gia_AigerWriteUnsigned( vBuffer, uLit - uLit1 ); Gia_AigerWriteUnsigned( vBuffer, uLit1 - uLit0 ); } - Vec_StrPrintStr( vBuffer, "c" ); + Vec_StrPrintStr( vBuffer, "c\n" ); return vBuffer; } From ba69519d736763531d141859caffcca887b664f7 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sun, 8 Mar 2026 10:26:27 -0700 Subject: [PATCH 18/33] Adding command for calling external solvers. --- src/base/cmd/cmd.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/src/base/cmd/cmd.c b/src/base/cmd/cmd.c index 0bb4b412b5..bbe3b7d8e8 100644 --- a/src/base/cmd/cmd.c +++ b/src/base/cmd/cmd.c @@ -67,6 +67,7 @@ static int CmdCommandCapo ( Abc_Frame_t * pAbc, int argc, char ** argv static int CmdCommandStarter ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int CmdCommandAutoTuner ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int CmdCommandSolver ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int CmdCommandSolver2 ( Abc_Frame_t * pAbc, int argc, char ** argv ); extern int Cmd_CommandAbcLoadPlugIn( Abc_Frame_t * pAbc, int argc, char ** argv ); @@ -123,6 +124,7 @@ void Cmd_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "Various", "starter", CmdCommandStarter, 0 ); Cmd_CommandAdd( pAbc, "Various", "autotuner", CmdCommandAutoTuner, 0 ); Cmd_CommandAdd( pAbc, "Various", "&solver", CmdCommandSolver, 0 ); + Cmd_CommandAdd( pAbc, "Various", "&solver2", CmdCommandSolver2, 0 ); Cmd_CommandAdd( pAbc, "Various", "load_plugin", Cmd_CommandAbcLoadPlugIn, 0 ); } @@ -2971,6 +2973,79 @@ int CmdCommandSolver( Abc_Frame_t * pAbc, int argc, char **argv ) return 1; } + +/**Function******************************************************************** + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int CmdCommandSolver2( Abc_Frame_t * pAbc, int argc, char **argv ) +{ + FILE * pFile; + char Command[2000]; + int i; + + if ( argc > 1 ) + { + if ( strcmp( argv[1], "-h" ) == 0 ) + goto usage; + if ( strcmp( argv[1], "-?" ) == 0 ) + goto usage; + } + +#if defined(__wasm) + fprintf( pAbc->Err, "Unsupported command.\n" ); + return 1; +#else + // Check if solver binary exists in current directory or PATH + if ( (pFile = fopen( "./solver", "r" )) != NULL ) + { + sprintf( Command, "%s", "./solver" ); + fclose( pFile ); + } + else + { + char CheckCommand[100]; + sprintf( CheckCommand, "which solver > /dev/null 2>&1" ); + if ( system( CheckCommand ) != 0 ) + { + fprintf( pAbc->Err, "Cannot find \"solver\" binary in the current directory or in PATH.\n" ); + goto usage; + } + sprintf( Command, "%s", "solver" ); + } + + // Append user-provided arguments as-is: solver + for ( i = 1; i < argc; i++ ) + { + strcat( Command, " " ); + strcat( Command, argv[i] ); + } + + fprintf( pAbc->Out, "Executing command: %s\n", Command ); + if ( system( Command ) == -1 ) + { + fprintf( pAbc->Err, "The following command has failed:\n" ); + fprintf( pAbc->Err, "\"%s\"\n", Command ); + return 1; + } +#endif + return 0; + +usage: + fprintf( pAbc->Err, "\tusage: &solver2 \n"); + fprintf( pAbc->Err, "\t run the external solver as \"solver \"\n" ); + fprintf( pAbc->Err, "\t-h : print the command usage\n" ); + fprintf( pAbc->Err, "\t : all arguments passed directly to solver\n" ); + return 1; +} + /**Function******************************************************************** Synopsis [Print the version string.] From a745d5ec817bf1fce32d205a0bb586e10a052516 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sun, 8 Mar 2026 10:27:12 -0700 Subject: [PATCH 19/33] Adding profiling to %ufar. --- src/opt/ufar/UfarCmd.cpp | 144 ++++++++++++++++- src/opt/ufar/UfarMgr.cpp | 329 ++++++++++++++++++++++++++++++++++++++- src/opt/ufar/UfarMgr.h | 31 +++- src/opt/untk/NtkNtk.cpp | 99 +++++++++++- src/opt/untk/NtkNtk.h | 4 +- src/opt/util/util.cpp | 27 +++- 6 files changed, 619 insertions(+), 15 deletions(-) diff --git a/src/opt/ufar/UfarCmd.cpp b/src/opt/ufar/UfarCmd.cpp index 37728b04d9..6ac2320ff4 100755 --- a/src/opt/ufar/UfarCmd.cpp +++ b/src/opt/ufar/UfarCmd.cpp @@ -15,8 +15,11 @@ #include #include #include +#include +#include #include "base/wlc/wlc.h" +#include "aig/gia/giaAig.h" #include "opt/ufar/UfarCmd.h" #include "opt/ufar/UfarMgr.h" #include "opt/untk/NtkNtk.h" @@ -120,6 +123,8 @@ static int Abc_CommandProveUsingUif( Abc_Frame_t * pAbc, int argc, char ** argv cout << "There is no current design.\n"; return 0; } + // Make each %ufar invocation stateless: always start from factory defaults. + ufar_manager.params = UFAR::UfarManager::Params(); OptMgr opt_mgr(argv[0]); opt_mgr.AddOpt("--norm", ufar_manager.params.fNorm ? "yes" : "no", "", "toggle using data type normalization"); @@ -137,9 +142,14 @@ static int Abc_CommandProveUsingUif( Abc_Frame_t * pAbc, int argc, char ** argv opt_mgr.AddOpt("--cbawb", ufar_manager.params.fCbaWb ? "yes" : "no", "", "toggle using cex-based refinement for white boxing"); opt_mgr.AddOpt("--grey", ufar_manager.params.fGrey ? "yes" : "no", "", "toggle using grey-box constraints"); opt_mgr.AddOpt("--grey2", to_string(ufar_manager.params.nGrey), "float", "specify the greyness threshold"); + opt_mgr.AddOpt("--allwb", ufar_manager.params.fAllWb ? "yes" : "no", "", "start with all operators white-boxed (no initial abstraction)"); + opt_mgr.AddOpt("--crossonly", ufar_manager.params.fCrossOnly ? "yes" : "no", "", "allow UIF pairs only across LHS/RHS cones of the miter"); + opt_mgr.AddOpt("--crossstats", "no", "", "print multiplier counts in LHS/RHS/shared cones and exit"); opt_mgr.AddOpt("--dump", "none", "str", "specify file name"); + opt_mgr.AddOpt("--dump-first-aig", "none", "str", "dump first internal bit-blasted AIG and exit"); opt_mgr.AddOpt("--dump-abs", "none", "str", "specify file name"); opt_mgr.AddOpt("--par", "none", "str", "use parallel solvers"); + opt_mgr.AddOpt("--solver", "none", "str", "external solver command line"); opt_mgr.AddOpt("--dump_states", "none", "str", "specify the name for the states file"); opt_mgr.AddOpt("--read_states", "none", "str", "specify the name for the states file"); opt_mgr.AddOpt("--sp", ufar_manager.params.fSuper_prove ? "yes" : "no", "", "toggle using super_prove"); @@ -147,6 +157,8 @@ static int Abc_CommandProveUsingUif( Abc_Frame_t * pAbc, int argc, char ** argv opt_mgr.AddOpt("--syn", ufar_manager.params.fSyn ? "yes" : "no", "", "toggle using simple synthesis"); opt_mgr.AddOpt("--pth", ufar_manager.params.fPthread ? "yes" : "no", "", "toggle using pthreads"); opt_mgr.AddOpt("--onewb", to_string(ufar_manager.params.iOneWb), "int", "specify the mode for one-white-boxing"); + opt_mgr.AddOpt("--initallpairs", to_string(ufar_manager.params.nInitAllPairsLimit), "num", "pre-seed all compatible UIF pairs when #ops <= this limit (0=off)"); + opt_mgr.AddOpt("--initnear", to_string(ufar_manager.params.nInitNearMults), "num", "pre-seed UIF pairs among up to this many multipliers closest to output"); opt_mgr.AddOpt("--timeout", to_string(ufar_manager.params.nTimeout), "num", "specify the timeout (sec)"); opt_mgr.AddOpt("--exp", to_string(ufar_manager.params.iExp), "int", "specify the exp mode"); opt_mgr.AddOpt("--miter", "yes", "", "toggle mitering the problem"); @@ -174,6 +186,10 @@ static int Abc_CommandProveUsingUif( Abc_Frame_t * pAbc, int argc, char ** argv ufar_manager.params.fCbaWb ^= 1; if(opt_mgr["--grey"]) ufar_manager.params.fGrey ^= 1; + if(opt_mgr["--allwb"]) + ufar_manager.params.fAllWb ^= 1; + if(opt_mgr["--crossonly"]) + ufar_manager.params.fCrossOnly ^= 1; if(opt_mgr["--grey2"]) ufar_manager.params.nGrey = stof(opt_mgr.GetOptVal("--grey2")); if(opt_mgr["--sp"]) @@ -186,10 +202,16 @@ static int Abc_CommandProveUsingUif( Abc_Frame_t * pAbc, int argc, char ** argv ufar_manager.params.fPthread ^= 1; if(opt_mgr["--onewb"]) ufar_manager.params.iOneWb = stoi(opt_mgr.GetOptVal("--onewb")); + if(opt_mgr["--initallpairs"]) + ufar_manager.params.nInitAllPairsLimit = stoi(opt_mgr.GetOptVal("--initallpairs")); + if(opt_mgr["--initnear"]) + ufar_manager.params.nInitNearMults = stoi(opt_mgr.GetOptVal("--initnear")); if(opt_mgr["--exp"]) ufar_manager.params.iExp = stoi(opt_mgr.GetOptVal("--exp")); if(opt_mgr["--par"]) ufar_manager.params.parSetting = opt_mgr.GetOptVal("--par"); + if(opt_mgr["--solver"]) + ufar_manager.params.solverSetting = opt_mgr.GetOptVal("--solver"); if(opt_mgr["--sim"]) ufar_manager.params.simSetting = opt_mgr.GetOptVal("--sim"); if(opt_mgr["--dump_states"]) { @@ -216,7 +238,7 @@ static int Abc_CommandProveUsingUif( Abc_Frame_t * pAbc, int argc, char ** argv if(regex_search(option, sub_match, regex(R"(/?(\w+)\.v$)"))) ufar_manager.params.fileAbs = sub_match[1].str(); else - ufar_manager.params.fileAbs = opt_mgr.GetOptVal("--dump"); + ufar_manager.params.fileAbs = opt_mgr.GetOptVal("--dump-abs"); } if(opt_mgr["--dump"]) { smatch sub_match; @@ -226,6 +248,9 @@ static int Abc_CommandProveUsingUif( Abc_Frame_t * pAbc, int argc, char ** argv else ufar_manager.params.fileName = opt_mgr.GetOptVal("--dump"); } + string firstAigDumpFile = ""; + if ( opt_mgr["--dump-first-aig"] ) + firstAigDumpFile = opt_mgr.GetOptVal("--dump-first-aig"); // ufar_manager.DumpParams(); LogT::prefix = "UIF_PROVE"; @@ -257,6 +282,68 @@ static int Abc_CommandProveUsingUif( Abc_Frame_t * pAbc, int argc, char ** argv Wlc_AbcUpdateNtk(pAbc, pNew); } + if ( opt_mgr["--crossstats"] ) + { + Wlc_Ntk_t * pCur = Wlc_AbcGetNtk(pAbc); + if ( Wlc_NtkPoNum(pCur) != 2 ) + { + cout << "CrossStats requires dual outputs before mitering.\n"; + return 0; + } + int nObjs = Wlc_NtkObjNumMax(pCur); + vector vConeL(nObjs, 0), vConeR(nObjs, 0); + auto mark_cone = [&]( int iStart, vector& vMark ) + { + if ( iStart < 0 || iStart >= nObjs ) + return; + vector stack(1, iStart); + while ( !stack.empty() ) + { + int iObj = stack.back(); + stack.pop_back(); + if ( iObj < 0 || iObj >= nObjs || vMark[iObj] ) + continue; + vMark[iObj] = 1; + Wlc_Obj_t * pObjT = Wlc_NtkObj(pCur, iObj); + // Sequential traversal: from flop output (FO) continue to corresponding flop input (FI). + if ( pObjT->Type == WLC_OBJ_FO ) + { + Wlc_Obj_t * pFi = Wlc_ObjFo2Fi(pCur, pObjT); + stack.push_back( Wlc_ObjId(pCur, pFi) ); + } + int iFanin, k; + Wlc_ObjForEachFanin( pObjT, iFanin, k ) + stack.push_back(iFanin); + } + }; + int iRootL = Wlc_ObjFaninId0( Wlc_NtkPo(pCur, 0) ); + int iRootR = Wlc_ObjFaninId0( Wlc_NtkPo(pCur, 1) ); + mark_cone(iRootL, vConeL); + mark_cone(iRootR, vConeR); + + int nL = 0, nR = 0, nB = 0, nN = 0; + Wlc_Obj_t * pObjT; int iObj; + Wlc_NtkForEachObj( pCur, pObjT, iObj ) + { + if ( pObjT->Type != WLC_OBJ_ARI_MULTI ) + continue; + bool fL = vConeL[iObj] != 0; + bool fR = vConeR[iObj] != 0; + if ( fL && fR ) nB++; + else if ( fL ) nL++; + else if ( fR ) nR++; + else nN++; + } + cout << "UIF_PROVE : CrossStats: L=" << nL + << " R=" << nR + << " BOTH=" << nB + << " NONE=" << nN + << " TOTAL=" << (nL + nR + nB + nN) << endl; + //fflush(stdout); + //exit(1); + return 0; + } + if (opt_mgr["--under"]) { pNew = UFAR::MakeUnderApprox(Wlc_AbcGetNtk(pAbc), stoi(opt_mgr.GetOptVal("--under"))); Wlc_AbcUpdateNtk(pAbc, pNew); @@ -267,6 +354,12 @@ static int Abc_CommandProveUsingUif( Abc_Frame_t * pAbc, int argc, char ** argv Gia_Man_t * pGia = UFAR::BitBlast(Wlc_AbcGetNtk(pAbc)); Gia_ManPrintStats( pGia, NULL ); + if ( !firstAigDumpFile.empty() && firstAigDumpFile != "none" ) + { + Gia_AigerWriteSimple( pGia, (char *)firstAigDumpFile.c_str() ); + Gia_ManStop( pGia ); + return 0; + } Gia_ManStop( pGia ); ufar_manager.Initialize(Wlc_AbcGetNtk(pAbc), set_op_types); @@ -283,14 +376,61 @@ static int Abc_CommandProveUsingUif( Abc_Frame_t * pAbc, int argc, char ** argv gettimeofday(&t2, NULL); unsigned tTotal = elapsed_time_usec(t1, t2); if(opt_mgr["--profile"]) { + unsigned nCexChecks = 0, nBitBlasts = 0; + unsigned long long tBitBlastUsec = 0, tCexCheckUsec = 0; + UFAR::Ufar_GetOrigCexStats(&nCexChecks, &nBitBlasts, &tBitBlastUsec, &tCexCheckUsec); + LOG(0) << "OrigCexStats: checks = " << nCexChecks + << ", bitblasts = " << nBitBlasts + << ", blast_time = " << fixed << setprecision(4) << ((double)tBitBlastUsec / 1000000.0) + << " sec [" << (tTotal ? (100.0 * (double)tBitBlastUsec / (double)tTotal) : 0.0) << "%]" + << ", cex_check_time = " << ((double)tCexCheckUsec / 1000000.0) + << " sec [" << (tTotal ? (100.0 * (double)tCexCheckUsec / (double)tTotal) : 0.0) << "%]"; auto log_profile = [&](const string& str, abctime t) { - LOG(1) << str << " time = " << fixed << setprecision(4) << setw(8) << (double)t/1000000 << " sec [" << setw(7) << (double)t/tTotal*100 << "%]"; + LOG(0) << str << " time = " << fixed << setprecision(4) << setw(8) << (double)t/1000000 << " sec [" << setw(7) << (double)t/tTotal*100 << "%]"; + }; + auto pct = [&](unsigned n, unsigned d) { + return d ? 100.0 * (double)n / (double)d : 0.0; }; log_profile("BLSolver ", ufar_manager.profile.tBLSolver); log_profile("UifRefine ", ufar_manager.profile.tUifRefine); log_profile("WbRefine ", ufar_manager.profile.tWbRefine); log_profile("UifSim ", ufar_manager.profile.tUifSim); log_profile("GbRefine ", ufar_manager.profile.tGbRefine); + log_profile("CexCheck ", ufar_manager.profile.tCexCheckOrig); + { + unsigned long long tKnown = (unsigned long long)ufar_manager.profile.tBLSolver + + (unsigned long long)ufar_manager.profile.tUifRefine + + (unsigned long long)ufar_manager.profile.tWbRefine + + (unsigned long long)ufar_manager.profile.tUifSim + + (unsigned long long)ufar_manager.profile.tGbRefine + + (unsigned long long)ufar_manager.profile.tCexCheckOrig; + unsigned long long tUnaccounted = (tTotal > tKnown) ? (tTotal - tKnown) : 0; + LOG(0) << "Unaccounted time = " << fixed << setprecision(4) << setw(8) + << ((double)tUnaccounted / 1000000.0) << " sec [" << setw(7) + << (tTotal ? (double)tUnaccounted * 100.0 / (double)tTotal : 0.0) << "%]"; + } + LOG(0) << "UFAR calls: verify = " << ufar_manager.profile.nVerifyCalls + << " (sat = " << ufar_manager.profile.nSatCalls + << ", unsat = " << ufar_manager.profile.nUnsatCalls + << ", undec = " << ufar_manager.profile.nUnknownCalls << ")"; + LOG(0) << "UFAR cex : real = " << ufar_manager.profile.nRealCex + << ", spurious = " << ufar_manager.profile.nSpuriousCex + << " [" << fixed << setprecision(1) + << pct(ufar_manager.profile.nSpuriousCex, ufar_manager.profile.nSatCalls) + << "% spurious among SAT-abstraction]"; + LOG(0) << "UFAR ref : iters_uif = " << ufar_manager.profile.nIterUif + << ", iters_wb = " << ufar_manager.profile.nIterWb + << ", pairs_added = " << ufar_manager.profile.nUifPairsAdded + << ", mul_mul_pairs_added = " << ufar_manager.profile.nUifMulMulPairsAdded + << ", wb_added = " << ufar_manager.profile.nWbAdded; + LOG(0) << "UFAR size : max_pairs = " << ufar_manager.profile.nMaxUifPairs + << ", max_white_boxes = " << ufar_manager.profile.nMaxWhiteBoxes; + if ( ufar_manager.profile.nVerifyCalls ) { + LOG(0) << "UFAR avg : blsolve_call = " + << fixed << setprecision(4) + << (double)ufar_manager.profile.tBLSolver / 1000000.0 / (double)ufar_manager.profile.nVerifyCalls + << " sec/call"; + } } LOG(0) << "Time = " << setprecision(5) << ((double) (tTotal) / 1000000) << " sec"; diff --git a/src/opt/ufar/UfarMgr.cpp b/src/opt/ufar/UfarMgr.cpp index 45487af771..b2177c275f 100755 --- a/src/opt/ufar/UfarMgr.cpp +++ b/src/opt/ufar/UfarMgr.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #ifdef _WIN32 #include @@ -35,6 +36,27 @@ static inline unsigned log_level() { return LogT::loglevel; } +static unsigned s_nOrigCexChecks = 0; +static unsigned s_nOrigBitBlasts = 0; +static unsigned long long s_tOrigBitBlastUsec = 0; +static unsigned long long s_tOrigCexCheckUsec = 0; + +void Ufar_ResetOrigCexStats() +{ + s_nOrigCexChecks = 0; + s_nOrigBitBlasts = 0; + s_tOrigBitBlastUsec = 0; + s_tOrigCexCheckUsec = 0; +} + +void Ufar_GetOrigCexStats( unsigned * pChecks, unsigned * pBitBlasts, unsigned long long * pBitBlastUsec, unsigned long long * pCexCheckUsec ) +{ + if ( pChecks ) *pChecks = s_nOrigCexChecks; + if ( pBitBlasts ) *pBitBlasts = s_nOrigBitBlasts; + if ( pBitBlastUsec ) *pBitBlastUsec = s_tOrigBitBlastUsec; + if ( pCexCheckUsec ) *pCexCheckUsec = s_tOrigCexCheckUsec; +} + static void split(const string &s, char delim, vector& elems) { stringstream ss(s); string item; @@ -132,7 +154,14 @@ static bool verify_cex_direct(Wlc_Ntk_t * pNtk, Abc_Cex_t * pCex) { } static bool verify_cex_on_original(Wlc_Ntk_t * pOrig, Abc_Cex_t * pCex) { + timeval t1, t2, tCheck1, tCheck2; + gettimeofday(&tCheck1, NULL); + gettimeofday(&t1, NULL); Gia_Man_t * pGiaOrig = BitBlast(pOrig); + gettimeofday(&t2, NULL); + s_nOrigCexChecks++; + s_nOrigBitBlasts++; + s_tOrigBitBlastUsec += elapsed_time_usec(t1, t2); unsigned nbits_orig_pis = compute_bit_level_pi_num(pOrig); int nbits_ppis = pCex->nPis - Gia_ManPiNum(pGiaOrig); @@ -161,6 +190,9 @@ static bool verify_cex_on_original(Wlc_Ntk_t * pOrig, Abc_Cex_t * pCex) { Gia_ManForEachPo( pGiaOrig, pObj, i ) { if (pObj->Value==1) { LOG(3) << "CEX is real."; + Gia_ManStop(pGiaOrig); + gettimeofday(&tCheck2, NULL); + s_tOrigCexCheckUsec += elapsed_time_usec(tCheck1, tCheck2); return true; } } @@ -168,6 +200,8 @@ static bool verify_cex_on_original(Wlc_Ntk_t * pOrig, Abc_Cex_t * pCex) { Gia_ManStop(pGiaOrig); LOG(3) << "CEX is spurious."; + gettimeofday(&tCheck2, NULL); + s_tOrigCexCheckUsec += elapsed_time_usec(tCheck1, tCheck2); return false; } @@ -949,6 +983,8 @@ UfarManager::Params::Params() : fGrey(false), nGrey(0), fNorm(true), + fAllWb(false), + fCrossOnly(false), fSuper_prove(false), fSimple(false), fSyn(false), @@ -956,21 +992,26 @@ UfarManager::Params::Params() : iOneWb(-1), iExp(-1), nConstraintLimit(65536), + nInitAllPairsLimit(0), + nInitNearMults(0), iVerbosity(0), nSeqLookBack(0), nTimeout(65536) {} -UfarManager::UfarManager() : _pOrigNtk(NULL), _pAbsWithAuxPos(NULL) {} +UfarManager::UfarManager() : _pOrigNtk(NULL), _pAbsWithAuxPos(NULL), _fCrossReady(false) {} UfarManager::~UfarManager() { if (_pOrigNtk) Wlc_NtkFree(_pOrigNtk); } void UfarManager::Initialize(Wlc_Ntk_t * pNtk, const set& types) { + Ufar_ResetOrigCexStats(); + LogT::loglevel = params.iVerbosity; if (_pOrigNtk) Wlc_NtkFree(_pOrigNtk); _vec_orig_names.clear(); _vec_op_ids.clear(); _vec_op_blackbox_marks.clear(); + _vec_op_side.clear(); _vec_op_greyness.clear(); _set_uif_pairs.clear(); _set_uif_sim_pairs.clear(); @@ -1001,12 +1042,211 @@ void UfarManager::Initialize(Wlc_Ntk_t * pNtk, const set& types) { } _vec_op_blackbox_marks.resize(_vec_op_ids.size(), true); + _vec_op_side.resize(_vec_op_ids.size(), 0); + _fCrossReady = false; + if ( params.fAllWb ) + std::fill( _vec_op_blackbox_marks.begin(), _vec_op_blackbox_marks.end(), false ); + + if ( params.fCrossOnly ) + { + int nObjs = Wlc_NtkObjNumMax(_pOrigNtk); + vector vConeL(nObjs, 0), vConeR(nObjs, 0); + auto mark_cone = [&]( int iStart, vector& vMark ) + { + if ( iStart < 0 || iStart >= nObjs ) + return; + vector stack(1, iStart); + while ( !stack.empty() ) + { + int iObj = stack.back(); + stack.pop_back(); + if ( iObj < 0 || iObj >= nObjs || vMark[iObj] ) + continue; + vMark[iObj] = 1; + Wlc_Obj_t * pObjT = Wlc_NtkObj(_pOrigNtk, iObj); + // Sequential traversal: from flop output (FO) continue to corresponding flop input (FI). + if ( pObjT->Type == WLC_OBJ_FO ) + { + Wlc_Obj_t * pFi = Wlc_ObjFo2Fi(_pOrigNtk, pObjT); + stack.push_back( Wlc_ObjId(_pOrigNtk, pFi) ); + } + int iFanin, k; + Wlc_ObjForEachFanin( pObjT, iFanin, k ) + stack.push_back(iFanin); + } + }; + + if ( Wlc_NtkPoNum(_pOrigNtk) == 1 ) + { + Wlc_Obj_t * pPo = Wlc_NtkPo(_pOrigNtk, 0); + int iMiter = Wlc_ObjFaninId0(pPo); + if ( iMiter >= 0 && iMiter < nObjs ) + { + Wlc_Obj_t * pMit = Wlc_NtkObj(_pOrigNtk, iMiter); + if ( Wlc_ObjFaninNum(pMit) >= 2 ) + { + int iL = Wlc_ObjFaninId0(pMit); + int iR = Wlc_ObjFaninId1(pMit); + mark_cone(iL, vConeL); + mark_cone(iR, vConeR); + _fCrossReady = true; + } + } + } + if ( _fCrossReady ) + { + int nL = 0, nR = 0, nB = 0, nN = 0; + for ( size_t iOp = 0; iOp < _vec_op_ids.size(); ++iOp ) + { + int iObj = _vec_op_ids[iOp]; + bool fL = vConeL[iObj] != 0; + bool fR = vConeR[iObj] != 0; + char Side = fL ? (fR ? 3 : 1) : (fR ? 2 : 0); + _vec_op_side[iOp] = Side; + if ( Side == 1 ) nL++; + else if ( Side == 2 ) nR++; + else if ( Side == 3 ) nB++; + else nN++; + } + LOG(1) << "CrossOnly: classified operators L=" << nL << " R=" << nR << " BOTH=" << nB << " NONE=" << nN; + } + else + LOG(1) << "CrossOnly: unable to derive LHS/RHS cones from miter; disabling cross filter."; + } + + auto seed_pairs_for_indices = [&]( const vector& vOpIdxs ) + { + auto sig = [&]( int iObj, int iFanin ) + { + int iFin = (iFanin == 0) ? Wlc_ObjFaninId0(Wlc_NtkObj(_pOrigNtk, iObj)) : Wlc_ObjFaninId1(Wlc_NtkObj(_pOrigNtk, iObj)); + Wlc_Obj_t * pFin = Wlc_NtkObj(_pOrigNtk, iFin); + return std::make_pair( Wlc_ObjRange(pFin), Wlc_ObjIsSigned(pFin) ); + }; + auto sigOut = [&]( int iObj ) + { + Wlc_Obj_t * pObj = Wlc_NtkObj(_pOrigNtk, iObj); + return std::make_pair( Wlc_ObjRange(pObj), Wlc_ObjIsSigned(pObj) ); + }; + for ( size_t i = 0; i < vOpIdxs.size(); ++i ) + for ( size_t j = i + 1; j < vOpIdxs.size(); ++j ) + { + int idx1 = vOpIdxs[i]; + int idx2 = vOpIdxs[j]; + int iObj1 = _vec_op_ids[idx1]; + int iObj2 = _vec_op_ids[idx2]; + Wlc_Obj_t * pObj1 = Wlc_NtkObj(_pOrigNtk, iObj1); + Wlc_Obj_t * pObj2 = Wlc_NtkObj(_pOrigNtk, iObj2); + if ( pObj1->Type != pObj2->Type ) + continue; + if ( sigOut(iObj1) != sigOut(iObj2) ) + continue; + + bool fDirect = (sig(iObj1, 0) == sig(iObj2, 0)) && (sig(iObj1, 1) == sig(iObj2, 1)); + bool fSwap = (sig(iObj1, 0) == sig(iObj2, 1)) && (sig(iObj1, 1) == sig(iObj2, 0)); + if ( fDirect ) { + UIF_PAIR Pair(OperatorID(idx1), OperatorID(idx2), 0); + if ( _allow_uif_pair(Pair) ) + _set_uif_pairs.insert( Pair ); + } + if ( fSwap ) { + UIF_PAIR Pair(OperatorID(idx1), OperatorID(idx2), 1); + if ( _allow_uif_pair(Pair) ) + _set_uif_pairs.insert( Pair ); + } + } + }; + + if ( params.nInitNearMults > 0 ) + { + vector > vScoreIdx; // (seq distance from outputs, op-index in _vec_op_ids) + int nObjs = Wlc_NtkObjNumMax(_pOrigNtk); + vector vDist(nObjs, -1); + queue q; + Wlc_Obj_t * pPoT; int iPo; + Wlc_NtkForEachPo( _pOrigNtk, pPoT, iPo ) + { + int iRoot = Wlc_ObjFaninId0(pPoT); + if ( iRoot > 0 && iRoot < nObjs && vDist[iRoot] == -1 ) + { + vDist[iRoot] = 0; + q.push(iRoot); + } + } + while ( !q.empty() ) + { + int iObj = q.front(); + q.pop(); + Wlc_Obj_t * pObjT = Wlc_NtkObj(_pOrigNtk, iObj); + int dNext = vDist[iObj] + 1; + if ( pObjT->Type == WLC_OBJ_FO ) + { + Wlc_Obj_t * pFi = Wlc_ObjFo2Fi(_pOrigNtk, pObjT); + int iFi = Wlc_ObjId(_pOrigNtk, pFi); + if ( iFi > 0 && iFi < nObjs && (vDist[iFi] == -1 || dNext < vDist[iFi]) ) + { + vDist[iFi] = dNext; + q.push(iFi); + } + } + int iFanin, k; + Wlc_ObjForEachFanin( pObjT, iFanin, k ) + { + if ( iFanin <= 0 || iFanin >= nObjs ) + continue; + if ( vDist[iFanin] == -1 || dNext < vDist[iFanin] ) + { + vDist[iFanin] = dNext; + q.push(iFanin); + } + } + } + + for ( size_t i = 0; i < _vec_op_ids.size(); ++i ) + { + int iObj = _vec_op_ids[i]; + if ( Wlc_NtkObj(_pOrigNtk, iObj)->Type != WLC_OBJ_ARI_MULTI ) + continue; + if ( iObj <= 0 || iObj >= nObjs ) + continue; + if ( vDist[iObj] < 0 ) + continue; + vScoreIdx.push_back( { vDist[iObj], (int)i } ); + } + sort( vScoreIdx.begin(), vScoreIdx.end(), + []( const pair& a, const pair& b ) + { return a.first != b.first ? a.first < b.first : a.second < b.second; } ); + vector vSeedOps; + size_t nTake = Abc_MinInt( (int)vScoreIdx.size(), (int)params.nInitNearMults ); + vSeedOps.reserve( nTake ); + for ( size_t i = 0; i < nTake; ++i ) + vSeedOps.push_back( vScoreIdx[i].second ); + sort( vSeedOps.begin(), vSeedOps.end() ); + + size_t nBefore = _set_uif_pairs.size(); + seed_pairs_for_indices( vSeedOps ); + if ( _set_uif_pairs.size() > nBefore ) { + LOG(1) << "InitNear: pre-seeded " << (_set_uif_pairs.size() - nBefore) + << " UIF pairs among " << vSeedOps.size() << " closest multipliers (limit = " << params.nInitNearMults << ")"; + } + } + + if ( params.nInitAllPairsLimit > 0 && _vec_op_ids.size() <= params.nInitAllPairsLimit ) + { + vector vAllOps; + vAllOps.reserve( _vec_op_ids.size() ); + for ( size_t i = 0; i < _vec_op_ids.size(); ++i ) + vAllOps.push_back( (int)i ); + size_t nBefore = _set_uif_pairs.size(); + seed_pairs_for_indices( vAllOps ); + if ( _set_uif_pairs.size() > nBefore ) { + LOG(1) << "InitAllPairs: pre-seeded " << (_set_uif_pairs.size() - nBefore) + << " UIF pairs (ops = " << _vec_op_ids.size() << ", limit = " << params.nInitAllPairsLimit << ")"; + } + } _p_sim_mgr.reset(new SimUifPairFinder(_pOrigNtk, &_vec_op_ids)); _p_cex_mgr.reset(new CexUifPairFinder(_pOrigNtk, &_vec_op_ids)); - LogT::loglevel = params.iVerbosity; - struct timeval now; gettimeofday(&now, NULL); _timeout.tv_sec = now.tv_sec + params.nTimeout; @@ -1122,6 +1362,8 @@ void UfarManager::FindUifPairsUsingSim() { set set_new_pairs; for(auto& x:_set_uif_sim_pairs) { + if ( !_allow_uif_pair(x) ) + continue; auto res = _set_uif_pairs.insert(x); if(res.second) set_new_pairs.insert(x); @@ -1149,6 +1391,14 @@ void UfarManager::FindUifPairsUsingCex(Abc_Cex_t * pCex, Abc_Cex_t ** ppCex) { } else { _p_cex_mgr->FindUifPairsBasic(cex_po_values, params.nSeqLookBack, set_found_pairs); } + if ( params.fCrossOnly && _fCrossReady ) + { + for ( auto it = set_found_pairs.begin(); it != set_found_pairs.end(); ) + if ( !_allow_uif_pair(*it) ) + it = set_found_pairs.erase(it); + else + ++it; + } if(log_level() >= 3) print_pairs(set_found_pairs); if(params.fPbaUif && !set_found_pairs.empty()) { @@ -1171,6 +1421,14 @@ void UfarManager::FindUifPairsUsingCex(Abc_Cex_t * pCex, Abc_Cex_t ** ppCex) { } } + if ( params.fCrossOnly && _fCrossReady ) + { + for ( auto it = set_found_pairs.begin(); it != set_found_pairs.end(); ) + if ( !_allow_uif_pair(*it) ) + it = set_found_pairs.erase(it); + else + ++it; + } for(auto& x : set_found_pairs) _set_uif_pairs.insert(x); gettimeofday(&t2, NULL); @@ -1403,7 +1661,7 @@ int UfarManager::VerifyCurrentAbstraction(Abc_Cex_t ** ppCex) { } } */ - ret = verify_model(pCurrent, ppCex, ¶ms.fileName, ¶ms.parSetting, params.fSyn, &_timeout, params.pFuncStop, params.RunId); + ret = verify_model(pCurrent, ppCex, ¶ms.fileName, ¶ms.parSetting, params.fSyn, &_timeout, params.pFuncStop, params.RunId, ¶ms.solverSetting, (int)params.nTimeout); Wlc_NtkFree(pCurrent); gettimeofday(&t2, NULL); @@ -1447,9 +1705,14 @@ int UfarManager::PerformUIFProve(const timeval& timer) { LOG(1) << "Grey: [Total] = " << setprecision(4) << stat << " (" << _vec_op_greyness.size() << ")"; }; auto print_stat = [&]() { + unsigned nWhiteBoxes = count(_vec_op_blackbox_marks.begin(), _vec_op_blackbox_marks.end(), false); + if (profile.nMaxUifPairs < _set_uif_pairs.size()) + profile.nMaxUifPairs = _set_uif_pairs.size(); + if (profile.nMaxWhiteBoxes < nWhiteBoxes) + profile.nMaxWhiteBoxes = nWhiteBoxes; gettimeofday(&curTime, NULL); elapsedTime = elapsed_time_usec(timer, curTime)/1000000.0; - snprintf(buffer, sizeof(buffer), "Iteration[%2u][%3u]: %4lu White boxes\t%4lu UIF constraints (time = %.4f)", n_iter_wb, n_iter_uif, count(_vec_op_blackbox_marks.begin(), _vec_op_blackbox_marks.end(), false), _set_uif_pairs.size(), elapsedTime); + snprintf(buffer, sizeof(buffer), "Iteration[%2u][%3u]: %4u White boxes\t%4lu UIF constraints (time = %.4f)", n_iter_wb, n_iter_uif, nWhiteBoxes, _set_uif_pairs.size(), elapsedTime); LOG(1) << buffer << _get_profile_uf_wb(); dump_grey_stat(); if(!params.fileStatesOut.empty()) _dump_states(params.fileStatesOut); @@ -1491,18 +1754,28 @@ int UfarManager::PerformUIFProve(const timeval& timer) { Wlc_NtkFree(pCurrent); ret = 0; } else { + profile.nVerifyCalls++; ret = VerifyCurrentAbstraction(&mem.pCex); } if (ret == 0) { // SAT + profile.nSatCalls++; if ( Ufar_ShouldStop(params) ) return -1; // GetOperatorsInCex(mem.pCex); - if (verify_cex_on_original(_pOrigNtk, mem.pCex)) { + timeval tCheck1, tCheck2; + gettimeofday(&tCheck1, NULL); + bool fRealCex = verify_cex_on_original(_pOrigNtk, mem.pCex); + gettimeofday(&tCheck2, NULL); + profile.tCexCheckOrig += elapsed_time_usec(tCheck1, tCheck2); + if (fRealCex) { + profile.nRealCex++; PrintWordCEX(_pOrigNtk, mem.pCex, &_vec_orig_names); return 0; } + profile.nSpuriousCex++; unsigned n_before = _set_uif_pairs.size(); + set set_before = _set_uif_pairs; FindUifPairsUsingCex(mem.pCex, &mem.pCex2); if ( Ufar_ShouldStop(params) ) @@ -1534,17 +1807,28 @@ int UfarManager::PerformUIFProve(const timeval& timer) { } } + if (_set_uif_pairs.size() > n_before) + profile.nUifPairsAdded += (_set_uif_pairs.size() - n_before); + if (_set_uif_pairs.size() > n_before) { + for (const auto& x : _set_uif_pairs) { + if (set_before.find(x) == set_before.end() && _is_mul_mul_pair(x)) + profile.nUifMulMulPairsAdded++; + } + } ++n_iter_uif; + profile.nIterUif++; print_stat(); if(_set_uif_pairs.size() > params.nConstraintLimit) return -1; } else if (ret == 1) { // UNSAT + profile.nUnsatCalls++; //_shrink_final_abstraction(); //print_stat(); return 1; } else { + profile.nUnknownCalls++; return -1; } @@ -1552,9 +1836,14 @@ int UfarManager::PerformUIFProve(const timeval& timer) { if ( Ufar_ShouldStop(params) ) return -1; + unsigned nWhiteBoxesBefore = count(_vec_op_blackbox_marks.begin(), _vec_op_blackbox_marks.end(), false); DetermineWhiteBoxes(mem.pCex); + unsigned nWhiteBoxesAfter = count(_vec_op_blackbox_marks.begin(), _vec_op_blackbox_marks.end(), false); + if (nWhiteBoxesAfter > nWhiteBoxesBefore) + profile.nWbAdded += (nWhiteBoxesAfter - nWhiteBoxesBefore); ++n_iter_wb; + profile.nIterWb++; print_stat(); } return -1; @@ -1573,6 +1862,31 @@ void UfarManager::_massage_state_b() { } +bool UfarManager::_is_mul_mul_pair(const UIF_PAIR& x) const { + if (!_pOrigNtk) + return false; + if (x.first.idx >= _vec_op_ids.size() || x.second.idx >= _vec_op_ids.size()) + return false; + int obj1 = _vec_op_ids[x.first.idx]; + int obj2 = _vec_op_ids[x.second.idx]; + Wlc_Obj_t * pObj1 = Wlc_NtkObj(_pOrigNtk, obj1); + Wlc_Obj_t * pObj2 = Wlc_NtkObj(_pOrigNtk, obj2); + return pObj1 && pObj2 && pObj1->Type == WLC_OBJ_ARI_MULTI && pObj2->Type == WLC_OBJ_ARI_MULTI; +} + +bool UfarManager::_allow_uif_pair(const UIF_PAIR& x) const { + if ( !params.fCrossOnly || !_fCrossReady ) + return true; + if ( x.first.idx < 0 || x.second.idx < 0 ) + return false; + if ( x.first.idx >= (int)_vec_op_side.size() || x.second.idx >= (int)_vec_op_side.size() ) + return false; + char s1 = _vec_op_side[x.first.idx]; + char s2 = _vec_op_side[x.second.idx]; + return (s1 == 1 && s2 == 2) || (s1 == 2 && s2 == 1); +} + + string UfarManager::_get_profile_uf_wb() { if (log_level() <= 4) return ""; unsigned num_full_white = 0; @@ -1625,6 +1939,9 @@ void UfarManager::DumpParams() const { unsigned n_setw = 15; cout << "Parameters : " << endl; cout << " " << setw(n_setw) << left << "cexmin" << " : " << (params.fCexMin ? "yes" : "no") << endl; + cout << " " << setw(n_setw) << left << "allwb" << " : " << (params.fAllWb ? "yes" : "no") << endl; + cout << " " << setw(n_setw) << left << "crossonly" << " : " << (params.fCrossOnly ? "yes" : "no") << endl; + cout << " " << setw(n_setw) << left << "initnear" << " : " << params.nInitNearMults << endl; cout << " " << setw(n_setw) << left << "iLogLevel" << " : " << params.iVerbosity << endl; } diff --git a/src/opt/ufar/UfarMgr.h b/src/opt/ufar/UfarMgr.h index 31b91ef401..ad17d84748 100755 --- a/src/opt/ufar/UfarMgr.h +++ b/src/opt/ufar/UfarMgr.h @@ -42,6 +42,9 @@ typedef struct Gia_Man_t_ Gia_Man_t; namespace UFAR { +void Ufar_ResetOrigCexStats(); +void Ufar_GetOrigCexStats(unsigned * pChecks, unsigned * pBitBlasts, unsigned long long * pBitBlastUsec, unsigned long long * pCexCheckUsec); + using VecVecInt = std::vector >; using VecVecStr = std::vector >; using VecChar = std::vector; @@ -72,6 +75,8 @@ class UfarManager { bool fGrey; float nGrey; bool fNorm; + bool fAllWb; + bool fCrossOnly; bool fSuper_prove; bool fSimple; bool fSyn; @@ -79,23 +84,43 @@ class UfarManager { int iOneWb; int iExp; unsigned nConstraintLimit; + unsigned nInitAllPairsLimit; + unsigned nInitNearMults; unsigned iVerbosity; unsigned nSeqLookBack; unsigned nTimeout; std::string simSetting; std::string parSetting; + std::string solverSetting; std::string fileName; std::string fileAbs; std::string fileStatesOut; std::string fileStatesIn; }; struct Profile { - Profile() : tBLSolver(0), tUifRefine(0), tWbRefine(0), tUifSim(0), tGbRefine(0) {} + Profile() : tBLSolver(0), tUifRefine(0), tWbRefine(0), tUifSim(0), tGbRefine(0), tCexCheckOrig(0), + nVerifyCalls(0), nSatCalls(0), nUnsatCalls(0), nUnknownCalls(0), + nRealCex(0), nSpuriousCex(0), nIterUif(0), nIterWb(0), + nUifPairsAdded(0), nUifMulMulPairsAdded(0), nWbAdded(0), nMaxUifPairs(0), nMaxWhiteBoxes(0) {} unsigned tBLSolver; unsigned tUifRefine; unsigned tWbRefine; unsigned tUifSim; unsigned tGbRefine; + unsigned tCexCheckOrig; + unsigned nVerifyCalls; + unsigned nSatCalls; + unsigned nUnsatCalls; + unsigned nUnknownCalls; + unsigned nRealCex; + unsigned nSpuriousCex; + unsigned nIterUif; + unsigned nIterWb; + unsigned nUifPairsAdded; + unsigned nUifMulMulPairsAdded; + unsigned nWbAdded; + unsigned nMaxUifPairs; + unsigned nMaxWhiteBoxes; }; UfarManager(); @@ -132,6 +157,8 @@ class UfarManager { void _perform_proof_based_grey_boxing(Abc_Cex_t * pCex); void _perform_cex_based_white_boxing(); std::string _get_profile_uf_wb(); + bool _is_mul_mul_pair(const UIF_PAIR& x) const; + bool _allow_uif_pair(const UIF_PAIR& x) const; void _massage_state_b(); void _dump_states(const std::string& file); void _read_states(const std::string& file); @@ -143,6 +170,7 @@ class UfarManager { std::vector _vec_op_ids; std::vector _vec_op_blackbox_marks; + std::vector _vec_op_side; // 0=unknown, 1=L-only, 2=R-only, 3=both std::vector > _vec_vec_op_ffs; std::vector _vec_op_greyness; @@ -156,6 +184,7 @@ class UfarManager { std::unique_ptr _p_cex_mgr; std::ostringstream _oss; + bool _fCrossReady; struct timespec _timeout; }; diff --git a/src/opt/untk/NtkNtk.cpp b/src/opt/untk/NtkNtk.cpp index 9c2a1da857..b0cb5bd15d 100755 --- a/src/opt/untk/NtkNtk.cpp +++ b/src/opt/untk/NtkNtk.cpp @@ -11,12 +11,18 @@ #include #endif #include +#include +#include +#include +#include +#include #include #include #include #include #include +#include #include "opt/util/util.h" #include "opt/ufar/UfarPth.h" @@ -1250,11 +1256,77 @@ static void readCexFromFile(int& ret, FILE * file, Abc_Cex_t ** ppCex, int nOrig } } -int verify_model(Wlc_Ntk_t * pNtk, Abc_Cex_t ** ppCex, const string* pFileName, const string* pParSetting, bool fSyn, struct timespec * timeout, int (*pFuncStop)(int), int RunId) { +static inline bool is_solver_cmd_defined(const string* pSolverSetting) { + return pSolverSetting && !pSolverSetting->empty() && *pSolverSetting != "none"; +} + +static inline int run_external_solver_on_aig( Abc_Ntk_t * pAbcNtk, const string& solverCmd, int nRuntimeLimitSec ) +{ + const char * pAigFile = "file.aig"; + Io_Write( pAbcNtk, (char *)pAigFile, IO_FILE_AIGER ); + std::remove( "status.txt" ); + std::remove( "log.txt" ); + string command = solverCmd; + if ( command.find(pAigFile) == string::npos ) + command += string(" ") + pAigFile; + if ( nRuntimeLimitSec > 0 ) + command += " " + to_string(nRuntimeLimitSec); + command += " > log.txt 2>&1"; + LOG(1) << "UFAR external solver: launching command instead of PDR: " << command; + int res = system( command.c_str() ); + std::remove( pAigFile ); + return res; +} + +static inline int read_external_status_unsat_first_line() +{ + ifstream ifs("status.txt", std::ifstream::in); + if ( !ifs ) + return -1; + int firstLine = -1; + ifs >> firstLine; + if ( ifs && firstLine == 0 ) + return 1; + return -1; +} + +static inline int read_external_result_from_log_last_line() +{ + ifstream ifs("log.txt", std::ifstream::in); + if ( !ifs ) + return -1; + string line, last; + auto trim = []( string & s ) + { + while ( !s.empty() && isspace((unsigned char)s.front()) ) + s.erase( s.begin() ); + while ( !s.empty() && isspace((unsigned char)s.back()) ) + s.pop_back(); + }; + while ( getline(ifs, line) ) + { + trim(line); + if ( !line.empty() ) + last = line; + } + if ( last.empty() ) + return -1; + transform( last.begin(), last.end(), last.begin(), + []( unsigned char c ){ return (char)toupper(c); } ); + if ( last.find("UNSAT") != string::npos ) + return 1; + if ( last.find("SAT") != string::npos ) + return 0; + if ( last.find("UNKNOWN") != string::npos || last.find("UNDECIDED") != string::npos ) + return -1; + return -1; +} + +int verify_model(Wlc_Ntk_t * pNtk, Abc_Cex_t ** ppCex, const string* pFileName, const string* pParSetting, bool fSyn, struct timespec * timeout, int (*pFuncStop)(int), int RunId, const string* pSolverSetting, int nUfarTimeoutSec) { if ( pFuncStop && pFuncStop(RunId) ) return -1; if ( !pParSetting || pParSetting->empty() || Wlc_NtkFfNum(pNtk) == 0 ) - return bit_level_solve( pNtk, ppCex, pFileName, pParSetting, fSyn, pFuncStop, RunId ); + return bit_level_solve( pNtk, ppCex, pFileName, pParSetting, fSyn, pFuncStop, RunId, pSolverSetting, nUfarTimeoutSec ); if(*ppCex) { Abc_CexFree(*ppCex); @@ -1275,7 +1347,7 @@ int verify_model(Wlc_Ntk_t * pNtk, Abc_Cex_t ** ppCex, const string* pFileName, } -int bit_level_solve(Wlc_Ntk_t * pNtk, Abc_Cex_t ** ppCex, const string* pFileName, const string* pParSetting, bool fSyn, int (*pFuncStop)(int), int RunId) { +int bit_level_solve(Wlc_Ntk_t * pNtk, Abc_Cex_t ** ppCex, const string* pFileName, const string* pParSetting, bool fSyn, int (*pFuncStop)(int), int RunId, const string* pSolverSetting, int nRuntimeLimitSec) { if ( pFuncStop && pFuncStop(RunId) ) return -1; if(*ppCex) { @@ -1319,6 +1391,27 @@ int bit_level_solve(Wlc_Ntk_t * pNtk, Abc_Cex_t ** ppCex, const string* pFileNam } } else { auto runPDR = [&](FILE * file){ + if ( is_solver_cmd_defined(pSolverSetting) ) + { + run_external_solver_on_aig( pAbcNtk, *pSolverSetting, nRuntimeLimitSec ); + int extStatus = read_external_result_from_log_last_line(); + if ( extStatus == -1 ) + extStatus = read_external_status_unsat_first_line(); + if ( extStatus == 1 ) + LOG(1) << "UFAR external solver result (UNSAT) available. Skipping PDR."; + else + LOG(1) << "UFAR external solver result not usable (log/status not UNSAT). Calling PDR."; + if ( extStatus == 1 ) + { + writeCexToFile(1, file, NULL); + return 1; + } + if ( pFuncStop && pFuncStop(RunId) ) + { + writeCexToFile(-1, file, NULL); + return -1; + } + } Pdr_Par_t PdrPars, *pPdrPars = &PdrPars; Pdr_ManSetDefaultParams(pPdrPars); pPdrPars->nConfLimit = 0; diff --git a/src/opt/untk/NtkNtk.h b/src/opt/untk/NtkNtk.h index 85d9ac9355..07b1c12f05 100755 --- a/src/opt/untk/NtkNtk.h +++ b/src/opt/untk/NtkNtk.h @@ -136,8 +136,8 @@ void PrintWordCEX(Wlc_Ntk_t * pNtk, Abc_Cex_t * pCex, const std::vector= 2 && val.back() == q; + if ( fClosed ) + val = val.substr(1, val.size() - 2); + else + { + val.erase(0, 1); + while ( i + 1 < argc ) + { + string next = argv[++i]; + if ( !next.empty() && next.back() == q ) + { + val += " " + next.substr(0, next.size() - 1); + fClosed = true; + break; + } + val += " " + next; + } + if ( !fClosed ) + return false; + } + } + opt._val = val; } } From 7ae0f4966a68ba3190b03a16810ae3daf23d14c0 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sun, 8 Mar 2026 12:04:25 -0700 Subject: [PATCH 20/33] Adding gla to sprove. --- src/base/abci/abc.c | 2 +- src/proof/abs/abs.h | 3 ++- src/proof/abs/absGla.c | 10 +++++++++- src/proof/abs/absUtil.c | 3 ++- src/proof/cec/cecProve.c | 36 +++++++++++++++++++++++++++++++++--- 5 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index f1bef5e235..63847c88ba 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -51398,7 +51398,7 @@ int Abc_CommandAbc9SProve( Abc_Frame_t * pAbc, int argc, char ** argv ) { Gia_Man_t * pGiaUse = pAbc->pGia, * pGiaTemp = NULL; Wlc_Ntk_t * pWlc = (Wlc_Ntk_t *)pAbc->pAbcWlc; - int c, nProcs = 5, nTimeOut = 3, nTimeOut2 = 10, nTimeOut3 = 100, fUseUif = 0, fVerbose = 0, fVeryVerbose = 0, fSilent = 0; + int c, nProcs = 6, nTimeOut = 3, nTimeOut2 = 10, nTimeOut3 = 100, fUseUif = 0, fVerbose = 0, fVeryVerbose = 0, fSilent = 0; Extra_UtilGetoptReset(); while ( ( c = Extra_UtilGetopt( argc, argv, "PTUWusvwh" ) ) != EOF ) { diff --git a/src/proof/abs/abs.h b/src/proof/abs/abs.h index 1c31e7cc63..782afebdfc 100644 --- a/src/proof/abs/abs.h +++ b/src/proof/abs/abs.h @@ -74,6 +74,8 @@ struct Abs_Par_t_ char * pFileVabs; // dumps the abstracted model into this file int fVerbose; // verbose flag int fVeryVerbose; // print additional information + int RunId; // id in this run + int (*pFuncStop)(int); // callback to terminate int iFrame; // the number of frames covered int iFrameProved; // the number of frames proved int nFramesNoChange; // the number of last frames without changes @@ -174,4 +176,3 @@ ABC_NAMESPACE_HEADER_END //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// - diff --git a/src/proof/abs/absGla.c b/src/proof/abs/absGla.c index 75f991d3be..9f1a8a31e9 100644 --- a/src/proof/abs/absGla.c +++ b/src/proof/abs/absGla.c @@ -1576,6 +1576,8 @@ int Gia_ManPerformGla( Gia_Man_t * pAig, Abs_Par_t * pPars ) for ( i = f = 0; !pPars->nFramesMax || f < pPars->nFramesMax; i++ ) { int nAbsOld; + if ( pPars->pFuncStop && pPars->pFuncStop(pPars->RunId) ) + goto finish; // remember the timeframe p->pPars->iFrame = -1; // create new SAT solver @@ -1585,6 +1587,8 @@ int Gia_ManPerformGla( Gia_Man_t * pAig, Abs_Par_t * pPars ) // unroll the circuit for ( f = 0; !pPars->nFramesMax || f < pPars->nFramesMax; f++ ) { + if ( pPars->pFuncStop && pPars->pFuncStop(pPars->RunId) ) + goto finish; // remember current limits int nConflsBeg = sat_solver2_nconflicts(p->pSat); int nAbs = Vec_IntSize(p->vAbs); @@ -1618,6 +1622,11 @@ int Gia_ManPerformGla( Gia_Man_t * pAig, Abs_Par_t * pPars ) nVarsOld = p->nSatVars; for ( c = 0; ; c++ ) { + if ( pPars->pFuncStop && pPars->pFuncStop(pPars->RunId) ) + { + Status = l_Undef; + goto finish; + } // consider the special case when the target literal is implied false // by implications which happened as a result of previous refinements // note that incremental UNSAT core cannot be computed because there is no learned clauses @@ -1898,4 +1907,3 @@ int Gia_ManPerformGla( Gia_Man_t * pAig, Abs_Par_t * pPars ) ABC_NAMESPACE_IMPL_END - diff --git a/src/proof/abs/absUtil.c b/src/proof/abs/absUtil.c index 286d1091ba..d0d85ae41a 100644 --- a/src/proof/abs/absUtil.c +++ b/src/proof/abs/absUtil.c @@ -59,6 +59,8 @@ void Abs_ParSetDefaults( Abs_Par_t * p ) p->fUseRollback = 0; // use rollback to the starting number of frames p->fPropFanout = 1; // propagate fanouts during refinement p->fVerbose = 0; // verbose flag + p->RunId = -1; // id in this run + p->pFuncStop = NULL; // callback to terminate p->iFrame = -1; // the number of frames covered p->iFrameProved = -1; // the number of frames proved p->nFramesNoChangeLim = 2; // the number of frames without change to dump abstraction @@ -254,4 +256,3 @@ int Gia_GlaCountNodes( Gia_Man_t * p, Vec_Int_t * vGla ) ABC_NAMESPACE_IMPL_END - diff --git a/src/proof/cec/cecProve.c b/src/proof/cec/cecProve.c index 017296540f..c3ed1fad71 100644 --- a/src/proof/cec/cecProve.c +++ b/src/proof/cec/cecProve.c @@ -26,6 +26,7 @@ #include "proof/pdr/pdr.h" #include "proof/cec/cec.h" #include "proof/ssw/ssw.h" +#include "proof/abs/abs.h" #ifdef ABC_USE_PTHREADS @@ -66,6 +67,7 @@ int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, in #define PAR_ENGINE_UFAR 6 #define PAR_ENGINE_SCORR1 7 #define PAR_ENGINE_SCORR2 8 +#define PAR_ENGINE_GLA 9 struct Par_Share_t_ { volatile int fSolved; @@ -90,6 +92,7 @@ typedef struct Cec_ScorrStop_t_ abctime TimeToStop; } Cec_ScorrStop_t; static volatile Par_Share_t * g_pUfarShare = NULL; +static volatile Par_Share_t * g_pGlaShare = NULL; static inline const char * Cec_SolveEngineName( int iEngine ) { if ( iEngine == 0 ) return "rar"; @@ -101,6 +104,7 @@ static inline const char * Cec_SolveEngineName( int iEngine ) if ( iEngine == PAR_ENGINE_UFAR ) return "ufar"; if ( iEngine == PAR_ENGINE_SCORR1 ) return "scorr-new"; if ( iEngine == PAR_ENGINE_SCORR2 ) return "scorr-old"; + if ( iEngine == PAR_ENGINE_GLA ) return "gla-q"; return "unknown"; } static inline void Cec_CopyGiaName( Gia_Man_t * pSrc, Gia_Man_t * pDst ) @@ -128,6 +132,11 @@ static int Cec_SProveStopUfar( int RunId ) (void)RunId; return g_pUfarShare && g_pUfarShare->fSolved != 0; } +static int Cec_SProveStopGla( int RunId ) +{ + (void)RunId; + return g_pGlaShare && g_pGlaShare->fSolved != 0; +} static int Cec_ScorrStop( void * pUser ) { Cec_ScorrStop_t * p = (Cec_ScorrStop_t *)pUser; @@ -177,7 +186,7 @@ int Cec_GiaProveOne( Gia_Man_t * p, int iEngine, int nTimeOut, int fVerbose, Par { abctime clk = Abc_Clock(); int RetValue = -1; - if ( iEngine != PAR_ENGINE_UFAR && Gia_ManRegNum(p) == 0 ) + if ( iEngine != PAR_ENGINE_UFAR && iEngine != PAR_ENGINE_GLA && Gia_ManRegNum(p) == 0 ) { if ( fVerbose ) printf( "Engine %d skipped because the current miter is combinational.\n", iEngine ); @@ -294,6 +303,22 @@ int Cec_GiaProveOne( Gia_Man_t * p, int iEngine, int nTimeOut, int fVerbose, Par g_pUfarShare = NULL; } } + else if ( iEngine == PAR_ENGINE_GLA ) + { + if ( Gia_ManPoNum(p) != 1 ) + return -1; + Abs_Par_t Pars, * pPars = &Pars; + Abs_ParSetDefaults( pPars ); + pPars->nTimeOut = nTimeOut; + pPars->fCallProver = 1; // emulate "&gla -q" + pPars->fVerbose = 0; + pPars->fVeryVerbose = 0; + pPars->RunId = 0; + pPars->pFuncStop = Cec_SProveStopGla; + g_pGlaShare = pThData ? pThData->pShare : NULL; + RetValue = Gia_ManPerformGla( p, pPars ); + g_pGlaShare = NULL; + } else assert( 0 ); //while ( Abc_Clock() < clkStop ); if ( pThData && pThData->pShare && RetValue != -1 ) @@ -379,7 +404,12 @@ void Cec_GiaInitThreads( Par_ThData_t * ThData, int nWorkers, Gia_Man_t * p, int { ThData[i].p = Gia_ManDup(p); Cec_CopyGiaName( p, ThData[i].p ); - ThData[i].iEngine = (fUseUif && i == nWorkers - 1) ? PAR_ENGINE_UFAR : i; + if ( fUseUif && i == nWorkers - 1 ) + ThData[i].iEngine = PAR_ENGINE_UFAR; + else if ( !fUseUif && nWorkers == 6 && i == 5 ) + ThData[i].iEngine = PAR_ENGINE_GLA; + else + ThData[i].iEngine = i; ThData[i].nTimeOut = nTimeOut; ThData[i].fWorking = 0; ThData[i].Result = -1; @@ -427,7 +457,7 @@ int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, in printf( "Processes = %d TimeOut = %d sec Verbose = %d.\n", nProcs, nTimeOut, fVerbose ); fflush( stdout ); - assert( nProcs == 3 || nProcs == 5 ); + assert( nProcs == 3 || nProcs == 5 || nProcs == 6 ); assert( nWorkers <= PAR_THR_MAX ); Cec_GiaInitThreads( ThData, nWorkers, p, nTimeOut, nTimeOut3, pWlc, fUseUif, fVerbose, WorkerThread, &Share ); From fa5029da953d8ce313aa41eee9475fb5c44a6c8d Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Tue, 10 Mar 2026 22:19:37 -0700 Subject: [PATCH 21/33] Updates to &if mapper. --- src/aig/gia/giaIf.c | 25 +++++++--- src/aig/gia/giaSpeedup.c | 99 ++++++++++++++++++++++++++++++++++------ src/base/abci/abc.c | 53 +++++++++++++-------- src/map/if/if.h | 14 +++++- src/map/if/ifCore.c | 1 - src/map/if/ifDecJ.c | 6 ++- src/map/if/ifMan.c | 1 + src/map/if/ifMap.c | 71 +++++++++++++++++++++++++++- src/map/if/ifTime.c | 26 ++++++++++- 9 files changed, 249 insertions(+), 47 deletions(-) diff --git a/src/aig/gia/giaIf.c b/src/aig/gia/giaIf.c index e733bccad7..682d7b1714 100644 --- a/src/aig/gia/giaIf.c +++ b/src/aig/gia/giaIf.c @@ -1190,7 +1190,7 @@ int Gia_ManFromIfLogicCreateLutSpecialJ( Gia_Man_t * pNew, word * pRes, Vec_Int_ { word Truth; int i, iObjLit1, iObjLit2, iObjLit3; - word z = If_CutPerformDeriveJ( NULL, (unsigned *)pRes, Vec_IntSize(vLeaves), Vec_IntSize(vLeaves), NULL, 1 ); + word z = If_CutPerformDeriveJ( NULL, (unsigned *)pRes, Vec_IntSize(vLeaves), Vec_IntSize(vLeaves), NULL, 1, 0 ); assert( z != 0 ); if ( ((z >> 63) & 1) == 0 ) { @@ -2135,7 +2135,7 @@ void Gia_ManConfigPrint2( unsigned char * pConfigData, int nLeaves ) SeeAlso [] ***********************************************************************/ -void Gia_ManFromIfGetConfig2( Vec_Str_t * vConfigs2, If_Man_t * pIfMan, word * pTruth, int nLeaves ) +void Gia_ManFromIfGetConfig2( Vec_Str_t * vConfigs2, If_Man_t * pIfMan, word * pTruth, int nLeaves, int fDelay ) { int i, CellId; int startPos = Vec_StrSize(vConfigs2); @@ -2143,13 +2143,18 @@ void Gia_ManFromIfGetConfig2( Vec_Str_t * vConfigs2, If_Man_t * pIfMan, word * p // Determine cell type based on the number of leaves and configuration if ( nLeaves <= 4 ) // 7 bytes = 1 byte CellId + 4 bytes mapping + 2 bytes truth table { + word z = If_CutPerformDeriveJ( pIfMan, (unsigned *)pTruth, nLeaves, nLeaves, NULL, 1, fDelay ); + int fHavePerm = (z != 0) && ((z & ABC_CONST(0x4000000000000000)) != 0); // Cell type 0: Simple LUT4 CellId = 0; // Write CellId Vec_StrPush( vConfigs2, (char)CellId ); // Write mapping for ( i = 0; i < nLeaves; i++ ) - Vec_StrPush( vConfigs2, 2+i ); + { + int v = fHavePerm ? (int)((z >> (2 * i)) & 3) : i; + Vec_StrPush( vConfigs2, 2 + v ); + } for ( ; i < 4; i++ ) Vec_StrPush( vConfigs2, 0 ); // Write truth table (16 bits for LUT4) @@ -2161,7 +2166,7 @@ void Gia_ManFromIfGetConfig2( Vec_Str_t * vConfigs2, If_Man_t * pIfMan, word * p } else // 12 bytes = 1 byte CellId + 7 bytes mapping + 4 bytes truth tables { - word z = If_CutPerformDeriveJ( pIfMan, (unsigned *)pTruth, nLeaves, nLeaves, NULL, 1 ); + word z = If_CutPerformDeriveJ( pIfMan, (unsigned *)pTruth, nLeaves, nLeaves, NULL, 1, fDelay ); //Gia_ManConfigPrint( 0, z, nLeaves ); if ( ((z >> 63) & 1) == 0 ) { @@ -2551,7 +2556,16 @@ Gia_Man_t * Gia_ManFromIfLogic( If_Man_t * pIfMan ) Abc_TtFlip( pTruth, Abc_TtWordNum(pCutBest->nLeaves), k ); if ( Abc_LitIsCompl(pIfObj->iCopy) ^ pCutBest->fCompl ) Abc_TtNot( pTruth, Abc_TtWordNum(pCutBest->nLeaves) ); - Gia_ManFromIfGetConfig2( vConfigs2, pIfMan, pTruth, pCutBest->nLeaves ); + if ( pIfMan->pPars->fDelayOptCell ) + { + pIfMan->nCutLeavesCur = pCutBest->nLeaves; + If_CutForEachLeaf( pIfMan, pCutBest, pIfLeaf, k ) + { + pIfMan->pCutLeavesCur[k] = pIfLeaf->Id; + pIfMan->pCutLeafArrCur[k] = If_ObjCutBest(pIfLeaf)->Delay; + } + } + Gia_ManFromIfGetConfig2( vConfigs2, pIfMan, pTruth, pCutBest->nLeaves, pIfMan->pPars->fDelayOptCell ); } } else @@ -3337,4 +3351,3 @@ Gia_Man_t * Gia_ManDupUnhashMapping( Gia_Man_t * p ) ABC_NAMESPACE_IMPL_END - diff --git a/src/aig/gia/giaSpeedup.c b/src/aig/gia/giaSpeedup.c index 4212c8966e..e5caba8fcc 100644 --- a/src/aig/gia/giaSpeedup.c +++ b/src/aig/gia/giaSpeedup.c @@ -33,6 +33,54 @@ ABC_NAMESPACE_IMPL_START /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// +static int Gia_ManConfig2GetBytePos( Gia_Man_t * p, int iObj ) +{ + int iLut, bytePos = 0; + if ( p == NULL || p->vConfigs2 == NULL ) + return -1; + Gia_ManForEachLut( p, iLut ) + { + unsigned char CellId; + if ( bytePos >= Vec_StrSize(p->vConfigs2) ) + return -1; + if ( iLut == iObj ) + return bytePos; + CellId = (unsigned char)Vec_StrEntry( p->vConfigs2, bytePos ); + if ( CellId == 0 ) + bytePos += 7; + else if ( CellId == 1 ) + bytePos += 12; + else if ( CellId == 2 ) + bytePos += 14; + else + return -1; + } + return -1; +} +static int Gia_ManConfig2DerivePinDelays( Gia_Man_t * p, int iObj, If_LibCell_t * pCellLib, int * pPinDelay, int nLutSize ) +{ + int bytePos, i, nPins; + unsigned char CellId; + if ( pCellLib == NULL || pPinDelay == NULL || nLutSize < 1 || nLutSize > 32 ) + return 0; + for ( i = 0; i < nLutSize; i++ ) + pPinDelay[i] = 1; + bytePos = Gia_ManConfig2GetBytePos( p, iObj ); + if ( bytePos < 0 || bytePos >= Vec_StrSize(p->vConfigs2) ) + return 0; + CellId = (unsigned char)Vec_StrEntry( p->vConfigs2, bytePos ); + if ( CellId >= pCellLib->nCellNum ) + return 0; + nPins = Abc_MinInt( pCellLib->nCellInputs[CellId], 9 ); + for ( i = 0; i < nPins; i++ ) + { + int v = (unsigned char)Vec_StrEntry( p->vConfigs2, bytePos + 1 + i ); + if ( v >= 2 && v < 2 + nLutSize ) + pPinDelay[v - 2] = pCellLib->pCellPinDelays[CellId][i]; + } + return 1; +} + /**Function************************************************************* Synopsis [Sorts the pins in the decreasing order of delays.] @@ -113,7 +161,7 @@ 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]; + int k, iFanin, pPinPerm[32], pPinDelay[32]; float pPinDelays[32]; float tArrival, * pDelays; if ( Gia_ObjIsCi(pObj) ) @@ -132,15 +180,17 @@ float Gia_ObjComputeArrival( Gia_Man_t * p, int iObj, int fUseSorting ) { // Handle cell library delays (use integer delays directly) int nLutSize = Gia_ObjLutSize(p, iObj); + int fHaveCfg2 = Gia_ManConfig2DerivePinDelays( p, iObj, pCellLib, pPinDelay, nLutSize ); // 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 ( !fHaveCfg2 ) + 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 @@ -151,6 +201,15 @@ float Gia_ObjComputeArrival( Gia_Man_t * p, int iObj, int fUseSorting ) tArrival = Gia_ObjTimeArrival(p, iFanin) + delay; } } + else if ( fHaveCfg2 ) + { + Gia_LutForEachFanin( p, iObj, iFanin, k ) + { + float delay = (float)pPinDelay[k]; + if ( tArrival < Gia_ObjTimeArrival(p, iFanin) + delay ) + tArrival = Gia_ObjTimeArrival(p, iFanin) + delay; + } + } else { // Fall back to default delay if no matching cell @@ -204,7 +263,7 @@ 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]; + int k, iFanin, pPinPerm[32], pPinDelay[32]; float pPinDelays[32]; float tRequired = 0.0; // Suppress "might be used uninitialized" float * pDelays; @@ -223,15 +282,17 @@ float Gia_ObjPropagateRequired( Gia_Man_t * p, int iObj, int fUseSorting ) { // Handle cell library delays (use integer delays directly) int nLutSize = Gia_ObjLutSize(p, iObj); + int fHaveCfg2 = Gia_ManConfig2DerivePinDelays( p, iObj, pCellLib, pPinDelay, nLutSize ); // 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 ( !fHaveCfg2 ) + 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 @@ -243,6 +304,15 @@ float Gia_ObjPropagateRequired( Gia_Man_t * p, int iObj, int fUseSorting ) Gia_ObjSetTimeRequired( p, iFanin, tRequired ); } } + else if ( fHaveCfg2 ) + { + Gia_LutForEachFanin( p, iObj, iFanin, k ) + { + tRequired = Gia_ObjTimeRequired( p, iObj ) - (float)pPinDelay[k]; + if ( Gia_ObjTimeRequired(p, iFanin) > tRequired ) + Gia_ObjSetTimeRequired( p, iFanin, tRequired ); + } + } else { // Fall back to default delay if no matching cell @@ -977,4 +1047,3 @@ Gia_Man_t * Gia_ManSpeedup( Gia_Man_t * p, int Percentage, int Degree, int fVerb ABC_NAMESPACE_IMPL_END - diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 63847c88ba..e42dfb8a4d 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -22285,7 +22285,7 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) If_ManSetDefaultPars( pPars ); pPars->pLutLib = (If_LibLut_t *)Abc_FrameReadLibLut(); Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "KCFAGRNTXYUZDEWSJqalepmrsdbgxyzuojiktncfvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "KCFAGRNTXYZUDEWSJqalepmrsdbgxyzuoiktncfvh" ) ) != EOF ) { switch ( c ) { @@ -22535,9 +22535,9 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) case 'o': pPars->fUseBuffs ^= 1; break; - case 'j': - pPars->fEnableCheck07 ^= 1; - break; + //case 'j': + // pPars->fEnableCheck07 ^= 1; + // break; case 'i': pPars->fUseCofVars ^= 1; break; @@ -22867,7 +22867,7 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) sprintf(LutSize, "library" ); else sprintf(LutSize, "%d", pPars->nLutSize ); - Abc_Print( -2, "usage: if [-KCFAGRNTXYUZ num] [-DEW float] [-SJ str] [-qarlepmsdbgxyuojiktnczfvh]\n" ); + Abc_Print( -2, "usage: if [-KCFAGRNTXYZMU num] [-DEW float] [-SJ str] [-qarlepmsdbgxyuoiktnczfvh]\n" ); Abc_Print( -2, "\t performs FPGA technology mapping of the network\n" ); Abc_Print( -2, "\t-K num : the number of LUT inputs (2 < num < %d) [default = %s]\n", IF_MAX_LUTSIZE+1, LutSize ); Abc_Print( -2, "\t-C num : the max number of priority cuts (0 < num < 2^12) [default = %d]\n", pPars->nCutsMax ); @@ -22901,7 +22901,7 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_Print( -2, "\t-y : toggles delay optimization with recorded library [default = %s]\n", pPars->fUserRecLib? "yes": "no" ); Abc_Print( -2, "\t-u : toggles delay optimization with SAT-based library [default = %s]\n", pPars->fUserSesLib? "yes": "no" ); Abc_Print( -2, "\t-o : toggles using buffers to decouple combinational outputs [default = %s]\n", pPars->fUseBuffs? "yes": "no" ); - Abc_Print( -2, "\t-j : toggles enabling additional check [default = %s]\n", pPars->fEnableCheck07? "yes": "no" ); + //Abc_Print( -2, "\t-j : toggles enabling additional check [default = %s]\n", pPars->fEnableCheck07? "yes": "no" ); Abc_Print( -2, "\t-i : toggles using cofactoring variables [default = %s]\n", pPars->fUseCofVars? "yes": "no" ); Abc_Print( -2, "\t-k : toggles matching based on precomputed DSD manager [default = %s]\n", pPars->fUseDsdTune? "yes": "no" ); Abc_Print( -2, "\t-t : toggles optimizing average rather than maximum level [default = %s]\n", pPars->fDoAverage? "yes": "no" ); @@ -44067,8 +44067,9 @@ int Abc_CommandAbc9If( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_FrameSetLibLut( If_LibLutSetSimple( 6 ) ); } pPars->pLutLib = (If_LibLut_t *)Abc_FrameReadLibLut(); + pPars->pCellLib = (If_LibCell_t *)Abc_FrameReadLibCell(); Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "KCFAGRDEWSJTXYZqalepmrsdbgxyofuijkztncvwh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "KCFAGRDEWSJTXYZMqalepmrsdbgxyofuijkztncvwh" ) ) != EOF ) { switch ( c ) { @@ -44084,6 +44085,7 @@ int Abc_CommandAbc9If( Abc_Frame_t * pAbc, int argc, char ** argv ) goto usage; // if the LUT size is specified, disable library pPars->pLutLib = NULL; + pPars->pCellLib = NULL; break; case 'C': if ( globalUtilOptind >= argc ) @@ -44173,6 +44175,21 @@ int Abc_CommandAbc9If( Abc_Frame_t * pAbc, int argc, char ** argv ) if ( pPars->nAndDelay < 0 ) goto usage; break; + case 'M': + { + int Value; + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-M\" should be followed by 0 or 1.\n" ); + goto usage; + } + Value = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( Value < 0 || Value > 1 ) + goto usage; + pPars->fDelayOptCell = Value; + break; + } case 'D': if ( globalUtilOptind >= argc ) { @@ -44349,6 +44366,7 @@ int Abc_CommandAbc9If( Abc_Frame_t * pAbc, int argc, char ** argv ) 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; + pPars->pCellLib = pCellLib; } } } @@ -44537,6 +44555,11 @@ int Abc_CommandAbc9If( Abc_Frame_t * pAbc, int argc, char ** argv ) pPars->nLutSize = 4; } + if ( pPars->fEnableCheck07 ) + pPars->nCutsMax = Abc_MaxInt( pPars->nCutsMax, 16 ); + else + pPars->pCellLib = NULL; + // enable truth table computation if cut minimization is selected if ( pPars->fCutMin || pPars->fDeriveLuts ) { @@ -44672,7 +44695,7 @@ int Abc_CommandAbc9If( Abc_Frame_t * pAbc, int argc, char ** argv ) sprintf(LutSize, "library" ); else sprintf(LutSize, "%d", pPars->nLutSize ); - Abc_Print( -2, "usage: &if [-KCFAGRTXY num] [-DEW float] [-SJ str] [-qarlepmsdbgxyofuijkztnchvw]\n" ); + Abc_Print( -2, "usage: &if [-KCFAGRTXYZM num] [-DEW float] [-SJ str] [-qarlepmsdbgxyofuijkztnchvw]\n" ); Abc_Print( -2, "\t performs FPGA technology mapping of the network\n" ); Abc_Print( -2, "\t-K num : the number of LUT inputs (2 < num < %d) [default = %s]\n", IF_MAX_LUTSIZE+1, LutSize ); Abc_Print( -2, "\t-C num : the max number of priority cuts (0 < num < 2^12) [default = %d]\n", pPars->nCutsMax ); @@ -44683,6 +44706,7 @@ int Abc_CommandAbc9If( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_Print( -2, "\t-T num : the type of LUT structures [default = any]\n", pPars->nStructType ); Abc_Print( -2, "\t-X num : delay of AND-gate in LUT library units [default = %d]\n", pPars->nAndDelay ); Abc_Print( -2, "\t-Y num : area of AND-gate in LUT library units [default = %d]\n", pPars->nAndArea ); + Abc_Print( -2, "\t-M num : enables delay-driven decomposition [default = %d]\n", pPars->fDelayOptCell ); Abc_Print( -2, "\t-D float : sets the delay constraint for the mapping [default = %s]\n", Buffer ); Abc_Print( -2, "\t-E float : sets epsilon used for tie-breaking [default = %f]\n", pPars->Epsilon ); Abc_Print( -2, "\t-W float : sets wire delay between adjects LUTs [default = %f]\n", pPars->WireDelay ); @@ -48585,22 +48609,13 @@ int Abc_CommandAbc9Trace( Abc_Frame_t * pAbc, int argc, char ** argv ) pAbc->pGia->pLutLib = fUseLutLib ? Abc_FrameReadLibLut() : NULL; 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 ); - } + Gia_ManDelayTraceDump( pAbc->pGia, (char *)pFileName ); return 0; usage: 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-F file : dump the critical path to a file [default = console output]\n" ); + Abc_Print( -2, "\t-F file : dump the critical path to a file [default = stdout]\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" ); diff --git a/src/map/if/if.h b/src/map/if/if.h index 3f9ddd101b..bfc451c6c1 100644 --- a/src/map/if/if.h +++ b/src/map/if/if.h @@ -126,6 +126,7 @@ struct If_Par_t_ int fCutMin; // performs cut minimization by removing functionally reducdant variables int fDelayOpt; // special delay optimization int fDelayOptLut; // delay optimization for LUTs + int fDelayOptCell; // delay optimization for cells int fDsdBalance; // special delay optimization int fUserRecLib; // use recorded library int fUserSesLib; // use SAT-based synthesis @@ -175,6 +176,7 @@ struct If_Par_t_ float FinalDelay; // final delay after mapping float FinalArea; // final area after mapping If_LibLut_t * pLutLib; // the LUT library + If_LibCell_t * pCellLib; // the cell library float * pTimesArr; // arrival times float * pTimesReq; // required times int (* pFuncCost) (If_Man_t *, If_Cut_t *); // procedure to compute the user's cost of a cut @@ -299,6 +301,14 @@ struct If_Man_t_ Vec_Int_t * vVisited2; Vec_Int_t * vCuts; Vec_Int_t * vCutCosts; + // current cut context for user callbacks + If_Obj_t * pCutObjCur; // current object whose cut is being checked + If_Cut_t * pCutCur; // current cut being checked + int nCutLeavesCur; // number of leaves in current cut + int pCutLeavesCur[IF_MAX_LUTSIZE]; // current cut leaves (IDs) + float pCutLeafArrCur[IF_MAX_LUTSIZE]; // current cut leaf arrivals + float CutDelayCur; // current cut delay returned by user callback + int fCutDelayCurValid; // indicates CutDelayCur is valid // timing manager Tim_Man_t * pManTim; @@ -319,6 +329,7 @@ struct If_Cut_t_ float Edge; // the edge flow float Power; // the power flow float Delay; // delay of the cut + word Config; // configuration string int iCutFunc; // TT ID of the cut int uMaskFunc; // polarity bitmask unsigned uSign; // cut signature @@ -564,7 +575,8 @@ extern float If_CutPowerDerefed( If_Man_t * p, If_Cut_t * pCut, If_Obj extern float If_CutPowerRefed( If_Man_t * p, If_Cut_t * pCut, If_Obj_t * pRoot ); /*=== ifDec.c =============================================================*/ extern word If_CutPerformDerive07( If_Man_t * p, unsigned * pTruth, int nVars, int nLeaves, char * pStr ); -extern word If_CutPerformDeriveJ( If_Man_t * p, unsigned * pTruth, int nVars, int nLeaves, char * pStr, int fDerive ); +extern word If_CutPerformDeriveJ( If_Man_t * p, unsigned * pTruth, int nVars, int nLeaves, char * pStr, int fDerive, int fDelay ); +extern void If_CutComputeIntrinsicJ( If_Man_t * p, word Config, int nLeaves, int * pIntrinsicDelays ); extern int If_CutPerformCheck07( If_Man_t * p, unsigned * pTruth, int nVars, int nLeaves, char * pStr ); extern int If_CutPerformCheck08( If_Man_t * p, unsigned * pTruth, int nVars, int nLeaves, char * pStr ); extern int If_CutPerformCheck10( If_Man_t * p, unsigned * pTruth, int nVars, int nLeaves, char * pStr ); diff --git a/src/map/if/ifCore.c b/src/map/if/ifCore.c index 58649b7204..975a573068 100644 --- a/src/map/if/ifCore.c +++ b/src/map/if/ifCore.c @@ -207,4 +207,3 @@ int If_ManPerformMappingComb( If_Man_t * p ) ABC_NAMESPACE_IMPL_END - diff --git a/src/map/if/ifDecJ.c b/src/map/if/ifDecJ.c index 018ad49691..d9676727b8 100644 --- a/src/map/if/ifDecJ.c +++ b/src/map/if/ifDecJ.c @@ -35,10 +35,13 @@ int If_CutPerformCheckJ( If_Man_t * p, unsigned * pTruth, int nVars, int nLeaves { return 1; } -word If_CutPerformDeriveJ( If_Man_t * p, unsigned * pTruth, int nVars, int nLeaves, char * pStr, int fDerive ) +word If_CutPerformDeriveJ( If_Man_t * p, unsigned * pTruth, int nVars, int nLeaves, char * pStr, int fDerive, int fDelay ) { return 0; } +void If_CutComputeIntrinsicJ( If_Man_t * p, word Config, int nLeaves, int * pIntrinsicDelays ) +{ +} void If_PermUnpack( unsigned Value, int Pla2Var[9] ) { } @@ -52,4 +55,3 @@ void Gia_ManDelayTraceDump( Gia_Man_t * p, char * pFileName ) ABC_NAMESPACE_IMPL_END - diff --git a/src/map/if/ifMan.c b/src/map/if/ifMan.c index 1a79014da4..ebf650db48 100644 --- a/src/map/if/ifMan.c +++ b/src/map/if/ifMan.c @@ -719,6 +719,7 @@ void If_ManSetupCutTriv( If_Man_t * p, If_Cut_t * pCut, int ObjId ) pCut->uSign = If_ObjCutSign( pCut->pLeaves[0] ); pCut->iCutFunc = p->pPars->fUseTtPerm ? 3 : (p->pPars->fTruth ? 2: -1); pCut->uMaskFunc = 0; + pCut->Config = 0; assert( pCut->pLeaves[0] < p->vObjs->nSize ); } diff --git a/src/map/if/ifMap.c b/src/map/if/ifMap.c index ac62e26e43..b03201a6b2 100644 --- a/src/map/if/ifMap.c +++ b/src/map/if/ifMap.c @@ -162,6 +162,7 @@ int * If_CutArrTimeProfile( If_Man_t * p, If_Cut_t * pCut ) void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPreprocess, int fFirst ) { If_Set_t * pCutSet; + If_Obj_t * pLeaf; If_Cut_t * pCut0, * pCut1, * pCut; If_Cut_t * pCut0R, * pCut1R; int fFunc0R, fFunc1R; @@ -193,6 +194,31 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep pCut->Delay = If_CutSopBalanceEval( p, pCut, NULL ); else if ( p->pPars->fDsdBalance ) pCut->Delay = If_CutDsdBalanceEval( p, pCut, NULL ); + else if ( p->pPars->fEnableCheck07 && p->pPars->fDelayOptCell ) + { + int iLeaf, Intrinsic[IF_MAX_LUTSIZE]; + float Delay = -IF_FLOAT_LARGE; + if ( pCut->nLeaves == 0 ) + { + pCut->fUseless = 0; + pCut->Delay = 0.0; + goto IfMapBestCutDone; + } + assert( pCut->nLeaves == 1 || pCut->Config ); + If_CutComputeIntrinsicJ( p, pCut->Config, pCut->nLeaves, Intrinsic ); + If_CutForEachLeaf( p, pCut, pLeaf, iLeaf ) + { + If_Cut_t * pBestCut = If_ObjCutBest( pLeaf ); + assert( pBestCut != NULL ); + assert( pBestCut->fUseless == 0 ); + Delay = IF_MAX( Delay, If_ObjArrTime(pLeaf) + (float)Intrinsic[iLeaf] ); + } + pCut->fUseless = (Delay > IF_FLOAT_LARGE/2); + pCut->Delay = Delay; +IfMapBestCutDone: +// if ( pCut->nLeaves == 9 && !pCut->fUseless ) +// Abc_Print( 1, "Delay-debug(Map9-best): obj=%d delay=%.2f\n", pObj->Id, pCut->Delay ); + } else if ( p->pPars->fUserRecLib ) pCut->Delay = If_CutDelayRecCost3( p, pCut, pObj ); else if ( p->pPars->fUserSesLib ) @@ -324,12 +350,32 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep { assert( p->pPars->fUseTtPerm == 0 ); assert( pCut->nLimit >= 4 && pCut->nLimit <= 16 ); + pCut->Config = 0; if ( p->pPars->fUseDsd ) pCut->fUseless = If_DsdManCheckDec( p->pIfDsdMan, If_CutDsdLit(p, pCut) ); else if ( p->pPars->pFuncCell2 ) pCut->fUseless = !p->pPars->pFuncCell2( p, (word *)If_CutTruthW(p, pCut), pCut->nLeaves, NULL, NULL ); else + { + int iLeaf; + // Expose current cut context for user callbacks. + p->pCutObjCur = pObj; + p->pCutCur = pCut; + p->nCutLeavesCur = pCut->nLeaves; + for ( iLeaf = 0; iLeaf < p->nCutLeavesCur; iLeaf++ ) + { + If_Obj_t * pLeaf = If_CutLeaf( p, pCut, iLeaf ); + if ( p->pPars->fEnableCheck07 && p->pPars->fDelayOptCell && pCut->nLeaves > 1 ) + { + If_Cut_t * pBestCut = If_ObjCutBest( pLeaf ); + assert( pBestCut != NULL ); + assert( pBestCut->fUseless == 0 ); + } + p->pCutLeavesCur[iLeaf] = pLeaf->Id; + p->pCutLeafArrCur[iLeaf] = If_ObjArrTime( pLeaf ); + } pCut->fUseless = !p->pPars->pFuncCell( p, If_CutTruth(p, pCut), Abc_MaxInt(6, pCut->nLeaves), pCut->nLeaves, p->pPars->pLutStruct ); + } p->nCutsUselessAll += pCut->fUseless; p->nCutsUseless[pCut->nLeaves] += pCut->fUseless; p->nCutsCountAll++; @@ -427,6 +473,28 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep pCut->Delay = If_CutSopBalanceEval( p, pCut, NULL ); else if ( p->pPars->fDsdBalance ) pCut->Delay = If_CutDsdBalanceEval( p, pCut, NULL ); + else if ( p->pPars->fEnableCheck07 && p->pPars->fDelayOptCell ) + { + if ( pCut->nLeaves == 0 ) + { + pCut->Delay = 0.0; + pCut->fUseless = 0; + goto IfMapCutEvalDone; + } + if ( pCut->nLeaves == 1 ) + { + pLeaf = If_ManObj( p, pCut->pLeaves[0] ); + pCut->Delay = If_ObjArrTime( pLeaf ); + pCut->fUseless = 0; + goto IfMapCutEvalDone; + } + assert( pCut->fUseless || p->fCutDelayCurValid ); + assert( pCut->fUseless || pCut->Config != 0 ); + pCut->Delay = pCut->fUseless ? IF_FLOAT_LARGE : p->CutDelayCur; +IfMapCutEvalDone: +// if ( pCut->nLeaves == 9 && !pCut->fUseless ) +// Abc_Print( 1, "Delay-debug(Map9): obj=%d delay=%.2f\n", pObj->Id, pCut->Delay ); + } else if ( p->pPars->fUserRecLib ) pCut->Delay = If_CutDelayRecCost3( p, pCut, pObj ); else if ( p->pPars->fUserLutDec ) @@ -502,7 +570,7 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep if ( Mode && pObj->nRefs > 0 ) If_CutAreaRef( p, If_ObjCutBest(pObj) ); if ( If_ObjCutBest(pObj)->fUseless ) - Abc_Print( 1, "The best cut is useless.\n" ); + Abc_Print( 1, "The best cut is useless. Please increase the number of cuts used by the mapper, for example: \"&if -C 32\"\n" ); // call the user specified function for each cut if ( p->pPars->pFuncUser ) If_ObjForEachCut( pObj, pCut, i ) @@ -702,4 +770,3 @@ int If_ManPerformMappingRound( If_Man_t * p, int nCutsUsed, int Mode, int fPrepr ABC_NAMESPACE_IMPL_END - diff --git a/src/map/if/ifTime.c b/src/map/if/ifTime.c index 216e4ce5ce..2b3e21a5ad 100644 --- a/src/map/if/ifTime.c +++ b/src/map/if/ifTime.c @@ -131,6 +131,20 @@ float If_CutDelay( If_Man_t * p, If_Obj_t * pObj, If_Cut_t * pCut ) } else { + if ( p->pPars->fEnableCheck07 && p->pPars->fDelayOptCell && p->pPars->pCellLib ) + { + int Intrinsic[IF_MAX_LUTSIZE]; + if ( pCut->nLeaves == 0 ) + return 0.0; + assert( pCut->nLeaves == 1 || pCut->Config != 0 ); + If_CutComputeIntrinsicJ( p, pCut->Config, pCut->nLeaves, Intrinsic ); + If_CutForEachLeaf( p, pCut, pLeaf, i ) + { + DelayCur = If_ObjCutBest(pLeaf)->Delay + (float)Intrinsic[i]; + Delay = IF_MAX( Delay, DelayCur ); + } + return Delay; + } if ( pCut->fUser ) { assert( !p->pPars->fLiftLeaves ); @@ -219,6 +233,17 @@ void If_CutPropagateRequired( If_Man_t * p, If_Obj_t * pObj, If_Cut_t * pCut, fl } else { + if ( p->pPars->fEnableCheck07 && p->pPars->fDelayOptCell && p->pPars->pCellLib ) + { + int Intrinsic[IF_MAX_LUTSIZE]; + if ( pCut->nLeaves == 0 ) + return; + assert( (pObj && pObj->Id == 0) || pCut->nLeaves == 1 || pCut->Config != 0 ); + If_CutComputeIntrinsicJ( p, pCut->Config, pCut->nLeaves, Intrinsic ); + If_CutForEachLeaf( p, pCut, pLeaf, i ) + pLeaf->Required = IF_MIN( pLeaf->Required, ObjRequired - (float)Intrinsic[i] ); + return; + } if ( pCut->fUser ) { char Perm[IF_MAX_FUNC_LUTSIZE], * pPerm = Perm; @@ -528,4 +553,3 @@ void If_ManComputeRequired( If_Man_t * p ) ABC_NAMESPACE_IMPL_END - From cf5aef38890e8b8b2cdbbf35192dddc27ba265d0 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Tue, 10 Mar 2026 22:26:43 -0700 Subject: [PATCH 22/33] Fix compiler problems. --- src/map/if/ifMan.c | 2 +- src/map/if/ifMap.c | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/map/if/ifMan.c b/src/map/if/ifMan.c index ebf650db48..ba5601fe85 100644 --- a/src/map/if/ifMan.c +++ b/src/map/if/ifMan.c @@ -226,7 +226,7 @@ void If_ManSimpleSort( int * pArray, int nSize ) void If_ManDumpCut( If_Cut_t * pCut, int nLutSize, Vec_Int_t * vCuts ) { int i; - for ( i = 0; i < pCut->nLeaves; i++ ) + for ( i = 0; i < (int)pCut->nLeaves; i++ ) Vec_IntPush( vCuts, pCut->pLeaves[i] ); for ( ; i < nLutSize; i++ ) Vec_IntPush( vCuts, -1 ); diff --git a/src/map/if/ifMap.c b/src/map/if/ifMap.c index b03201a6b2..6b710d6e09 100644 --- a/src/map/if/ifMap.c +++ b/src/map/if/ifMap.c @@ -216,8 +216,7 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep pCut->fUseless = (Delay > IF_FLOAT_LARGE/2); pCut->Delay = Delay; IfMapBestCutDone: -// if ( pCut->nLeaves == 9 && !pCut->fUseless ) -// Abc_Print( 1, "Delay-debug(Map9-best): obj=%d delay=%.2f\n", pObj->Id, pCut->Delay ); + ; } else if ( p->pPars->fUserRecLib ) pCut->Delay = If_CutDelayRecCost3( p, pCut, pObj ); @@ -294,7 +293,7 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep if ( !If_CutMergeOrdered( p, pCut0, pCut1, pCut ) ) continue; } - if ( p->pPars->fUserLutDec && !fFirst && pCut->nLeaves > p->pPars->nLutDecSize ) + if ( p->pPars->fUserLutDec && !fFirst && (int)pCut->nLeaves > p->pPars->nLutDecSize ) continue; if ( pObj->fSpec && pCut->nLeaves == (unsigned)p->pPars->nLutSize ) continue; @@ -492,8 +491,7 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep assert( pCut->fUseless || pCut->Config != 0 ); pCut->Delay = pCut->fUseless ? IF_FLOAT_LARGE : p->CutDelayCur; IfMapCutEvalDone: -// if ( pCut->nLeaves == 9 && !pCut->fUseless ) -// Abc_Print( 1, "Delay-debug(Map9): obj=%d delay=%.2f\n", pObj->Id, pCut->Delay ); + ; } else if ( p->pPars->fUserRecLib ) pCut->Delay = If_CutDelayRecCost3( p, pCut, pObj ); From ca0fc3ed2931ec853592a2001bcbfe5dfff1590b Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Thu, 19 Mar 2026 18:37:32 -0700 Subject: [PATCH 23/33] Adding support for Verilog dumping in "lutexact'. --- src/sat/bmc/bmcMaj.c | 162 ++++++++++++++++++++++++++++++++++++++++- src/sat/bmc/bmcMaj2.c | 163 +++++++++++++++++++++++++++++++++++++++++- src/sat/bmc/bmcMaj7.c | 161 +++++++++++++++++++++++++++++++++++++++++ src/sat/bmc/bmcMaj8.c | 161 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 644 insertions(+), 3 deletions(-) diff --git a/src/sat/bmc/bmcMaj.c b/src/sat/bmc/bmcMaj.c index 1b05c76050..e342ff350a 100644 --- a/src/sat/bmc/bmcMaj.c +++ b/src/sat/bmc/bmcMaj.c @@ -1363,6 +1363,161 @@ static void Exa3_ManPrintPerm( Exa3_Man_t * p ) } } } +static void Exa3_ManDumpVerilogName( Exa3_Man_t * p, char * pBase ) +{ + char Flags[32]; + int n = 0; + if ( p->pPars->pSymStr ) + snprintf( pBase, 128, "Y%.*s", 15, p->pPars->pSymStr ); + else + snprintf( pBase, 128, "%.*s", 16, p->pPars->pTtStr ); + if ( p->pPars->fUseIncr ) Flags[n++] = 'i'; + if ( p->pPars->fOnlyAnd ) Flags[n++] = 'a'; + if ( p->pPars->fFewerVars ) Flags[n++] = 'o'; + if ( p->pPars->fLutCascade ) Flags[n++] = 'r'; + if ( p->pPars->fLutInFixed ) Flags[n++] = 'f'; + if ( p->pPars->fGlucose ) Flags[n++] = 'g'; + if ( p->pPars->fCadical ) Flags[n++] = 'c'; + if ( p->pPars->fKissat ) Flags[n++] = 'k'; + if ( p->pPars->fDumpBlif ) Flags[n++] = 'd'; + if ( p->pPars->fMinNodes ) Flags[n++] = 'm'; + if ( p->pPars->fUsePerm ) Flags[n++] = 'p'; + Flags[n] = '\0'; + snprintf( pBase + strlen(pBase), 128 - strlen(pBase), "_K%d_M%d_%s", p->nLutSize, p->nNodes, Flags ); +} +static int Exa3_ManDumpCascadeVerilog( Exa3_Man_t * p, int fCompl ) +{ + static const char * pBels[8] = { "A6LUT", "B6LUT", "C6LUT", "D6LUT", "E6LUT", "F6LUT", "G6LUT", "H6LUT" }; + int i, k, iVar; + char pBase[128], pFileName[132], pModuleName[160]; + FILE * pFile; + if ( p->nLutSize > 6 ) + { + if ( !p->pPars->fSilent ) + printf( "Vivado LUT cascade dumping supports only LUTs with up to 6 inputs. Falling back to BLIF dumping.\n" ); + return 0; + } + Exa3_ManDumpVerilogName( p, pBase ); + snprintf( pFileName, sizeof(pFileName), "%s.v", pBase ); + snprintf( pModuleName, sizeof(pModuleName), "lut_cascade_%s", pBase ); + pFile = fopen( pFileName, "wb" ); + if ( pFile == NULL ) + return 0; + fprintf( pFile, "// Vivado LUT cascade for the %d-input function %s synthesized by ABC on %s\n", p->nVars, pBase, Extra_TimeStamp() ); + fprintf( pFile, "module %s (\n", pModuleName ); + fprintf( pFile, " input wire [%d:0] x,\n", p->nVars - 1 ); + fprintf( pFile, " output wire y\n" ); + fprintf( pFile, ");\n" ); + for ( i = 0; i < p->nNodes - 1; i++ ) + fprintf( pFile, " (* KEEP = \"yes\", DONT_TOUCH = \"yes\" *) wire n%d;\n", i ); + if ( p->nNodes > 1 ) + fprintf( pFile, "\n" ); + for ( i = p->nVars; i < p->nObjs; i++ ) + { + int iNode = i - p->nVars; + int iSlice = iNode / 8; + int iVarStart = 1 + p->LutMask * iNode; + word Truth = 0; + word Mask = p->nLutSize == 6 ? ~(word)0 : ((((word)1) << (1 << p->nLutSize)) - 1); + for ( k = 0; k < p->LutMask; k++ ) + if ( bmcg_sat_solver_read_cex_varvalue(p->pSat, iVarStart + k) ) + Truth |= ((word)1) << (k + 1); + if ( i == p->nObjs - 1 && fCompl ) + Truth = (~Truth) & Mask; + if ( p->nLutSize < 6 ) + Truth = Abc_Tt6Stretch( Truth, p->nLutSize ); + fprintf( pFile, " (* HU_SET = \"hu_lut_cascade_%d\", RLOC = \"X0Y%d\", BEL = \"%s\", DONT_TOUCH = \"yes\", KEEP = \"yes\", IS_BEL_FIXED = \"yes\" *)\n", + iSlice, iSlice, pBels[iNode % 8] ); + fprintf( pFile, " LUT6 #(.INIT(64'h%016llX)) u_lut%d (\n", (unsigned long long)Truth, iNode ); + for ( k = 0; k < 6; k++ ) + { + fprintf( pFile, " .I%d(", k ); + if ( k < p->nLutSize ) + { + iVar = Exa3_ManFindFanin( p, i, k ); + if ( iVar < p->nVars ) + fprintf( pFile, "x[%d]", iVar ); + else + fprintf( pFile, "n%d", iVar - p->nVars ); + } + else + fprintf( pFile, "1'b0" ); + fprintf( pFile, "),\n" ); + } + if ( i == p->nObjs - 1 ) + fprintf( pFile, " .O(y)\n" ); + else + fprintf( pFile, " .O(n%d)\n", iNode ); + fprintf( pFile, " );\n\n" ); + } + fprintf( pFile, "endmodule\n\n" ); + fclose( pFile ); + if ( !p->pPars->fSilent ) + printf( "Finished dumping the resulting LUT cascade into file \"%s\".\n", pFileName ); + return 1; +} +static int Exa3_ManDumpVerilog( Exa3_Man_t * p, int fCompl ) +{ + int i, k, iVar; + int nBits = 1 << p->nLutSize; + int nDigits = (nBits + 3) >> 2; + char pBase[128], pFileName[132], pModuleName[160]; + FILE * pFile; + if ( p->nLutSize > 6 ) + { + if ( !p->pPars->fSilent ) + printf( "Vivado LUT dumping supports only LUTs with up to 6 inputs. Skipping Verilog dump.\n" ); + return 0; + } + Exa3_ManDumpVerilogName( p, pBase ); + snprintf( pFileName, sizeof(pFileName), "%s.v", pBase ); + snprintf( pModuleName, sizeof(pModuleName), "lut_net_%s", pBase ); + pFile = fopen( pFileName, "wb" ); + if ( pFile == NULL ) + return 0; + fprintf( pFile, "// Vivado LUT net for the %d-input function %s synthesized by ABC on %s\n", p->nVars, pBase, Extra_TimeStamp() ); + fprintf( pFile, "module %s (\n", pModuleName ); + fprintf( pFile, " input wire [%d:0] x,\n", p->nVars - 1 ); + fprintf( pFile, " output wire y\n" ); + fprintf( pFile, ");\n" ); + for ( i = 0; i < p->nNodes - 1; i++ ) + fprintf( pFile, " wire n%d;\n", i ); + if ( p->nNodes > 1 ) + fprintf( pFile, "\n" ); + for ( i = p->nVars; i < p->nObjs; i++ ) + { + int iNode = i - p->nVars; + int iVarStart = 1 + p->LutMask * iNode; + word Truth = 0; + word Mask = p->nLutSize == 6 ? ~(word)0 : ((((word)1) << nBits) - 1); + for ( k = 0; k < p->LutMask; k++ ) + if ( bmcg_sat_solver_read_cex_varvalue(p->pSat, iVarStart + k) ) + Truth |= ((word)1) << (k + 1); + if ( i == p->nObjs - 1 && fCompl ) + Truth = (~Truth) & Mask; + fprintf( pFile, " LUT%d #(.INIT(%d'h%0*llX)) u_lut%d (\n", p->nLutSize, nBits, nDigits, (unsigned long long)Truth, iNode ); + for ( k = 0; k < p->nLutSize; k++ ) + { + fprintf( pFile, " .I%d(", k ); + iVar = Exa3_ManFindFanin( p, i, k ); + if ( iVar < p->nVars ) + fprintf( pFile, "x[%d]", iVar ); + else + fprintf( pFile, "n%d", iVar - p->nVars ); + fprintf( pFile, "),\n" ); + } + if ( i == p->nObjs - 1 ) + fprintf( pFile, " .O(y)\n" ); + else + fprintf( pFile, " .O(n%d)\n", iNode ); + fprintf( pFile, " );\n\n" ); + } + fprintf( pFile, "endmodule\n\n" ); + fclose( pFile ); + if ( !p->pPars->fSilent ) + printf( "Finished dumping the resulting LUT network into file \"%s\".\n", pFileName ); + return 1; +} /**Function************************************************************* Synopsis [] @@ -1713,7 +1868,13 @@ int Exa3_ManExactSynthesis( Bmc_EsPar_t * pPars ) if ( !pPars->fSilent && (p->nUsed[0] || p->nUsed[1]) ) printf( "Added = %d. Tried = %d. ", p->nUsed[1], p->nUsed[0] ); if ( !pPars->fSilent ) Abc_PrintTime( 1, "Total runtime", Abc_Clock() - clkTotal ); if ( iMint == -1 && pPars->fDumpBlif ) + { Exa3_ManDumpBlif( p, fCompl ); + if ( pPars->fLutCascade ) + Exa3_ManDumpCascadeVerilog( p, fCompl ); + else + Exa3_ManDumpVerilog( p, fCompl ); + } if ( pPars->pSymStr ) ABC_FREE( pPars->pTtStr ); Exa3_ManFree( p ); @@ -4344,4 +4505,3 @@ void Exa_NpnCascadeTest6() //////////////////////////////////////////////////////////////////////// ABC_NAMESPACE_IMPL_END - diff --git a/src/sat/bmc/bmcMaj2.c b/src/sat/bmc/bmcMaj2.c index ffc6946ae5..761795d967 100644 --- a/src/sat/bmc/bmcMaj2.c +++ b/src/sat/bmc/bmcMaj2.c @@ -1236,6 +1236,157 @@ static void Exa3_ManDumpBlif( Exa3_Man_t * p, int fCompl ) printf( "Finished dumping the resulting LUT network into file \"%s\".\n", pFileName ); ABC_FREE( pStr ); } +static void Exa3_ManDumpVerilogName( Exa3_Man_t * p, char * pBase ) +{ + char Flags[32]; + int n = 0; + if ( p->pPars->pSymStr ) + snprintf( pBase, 128, "Y%.*s", 15, p->pPars->pSymStr ); + else + snprintf( pBase, 128, "%.*s", 16, p->pPars->pTtStr ); + if ( p->pPars->fUseIncr ) Flags[n++] = 'i'; + if ( p->pPars->fOnlyAnd ) Flags[n++] = 'a'; + if ( p->pPars->fFewerVars ) Flags[n++] = 'o'; + if ( p->pPars->fLutCascade ) Flags[n++] = 'r'; + if ( p->pPars->fLutInFixed ) Flags[n++] = 'f'; + if ( p->pPars->fGlucose ) Flags[n++] = 'g'; + if ( p->pPars->fCadical ) Flags[n++] = 'c'; + if ( p->pPars->fKissat ) Flags[n++] = 'k'; + if ( p->pPars->fDumpBlif ) Flags[n++] = 'd'; + if ( p->pPars->fMinNodes ) Flags[n++] = 'm'; + if ( p->pPars->fUsePerm ) Flags[n++] = 'p'; + Flags[n] = '\0'; + snprintf( pBase + strlen(pBase), 128 - strlen(pBase), "_K%d_M%d_%s", p->nLutSize, p->nNodes, Flags ); +} +static int Exa3_ManDumpCascadeVerilog( Exa3_Man_t * p, int fCompl ) +{ + static const char * pBels[8] = { "A6LUT", "B6LUT", "C6LUT", "D6LUT", "E6LUT", "F6LUT", "G6LUT", "H6LUT" }; + int i, k, iVar; + char pBase[128], pFileName[132], pModuleName[160]; + FILE * pFile; + if ( p->nLutSize > 6 ) + { + printf( "Vivado LUT cascade dumping supports only LUTs with up to 6 inputs. Falling back to BLIF dumping.\n" ); + return 0; + } + Exa3_ManDumpVerilogName( p, pBase ); + snprintf( pFileName, sizeof(pFileName), "%s.v", pBase ); + snprintf( pModuleName, sizeof(pModuleName), "lut_cascade_%s", pBase ); + pFile = fopen( pFileName, "wb" ); + if ( pFile == NULL ) + return 0; + fprintf( pFile, "// Vivado LUT cascade for the %d-input function %s synthesized by ABC on %s\n", p->nVars, pBase, Extra_TimeStamp() ); + fprintf( pFile, "module %s (\n", pModuleName ); + fprintf( pFile, " input wire [%d:0] x,\n", p->nVars - 1 ); + fprintf( pFile, " output wire y\n" ); + fprintf( pFile, ");\n" ); + for ( i = 0; i < p->nNodes - 1; i++ ) + fprintf( pFile, " (* KEEP = \"yes\", DONT_TOUCH = \"yes\" *) wire n%d;\n", i ); + if ( p->nNodes > 1 ) + fprintf( pFile, "\n" ); + for ( i = p->nVars; i < p->nObjs; i++ ) + { + int iNode = i - p->nVars; + int iSlice = iNode / 8; + int iVarStart = 1 + p->LutMask * iNode; + word Truth = 0; + word Mask = p->nLutSize == 6 ? ~(word)0 : ((((word)1) << (1 << p->nLutSize)) - 1); + for ( k = 0; k < p->LutMask; k++ ) + if ( sat_solver_var_value(p->pSat, iVarStart + k) ) + Truth |= ((word)1) << (k + 1); + if ( i == p->nObjs - 1 && fCompl ) + Truth = (~Truth) & Mask; + if ( p->nLutSize < 6 ) + Truth = Abc_Tt6Stretch( Truth, p->nLutSize ); + fprintf( pFile, " (* HU_SET = \"hu_lut_cascade_%d\", RLOC = \"X0Y%d\", BEL = \"%s\", DONT_TOUCH = \"yes\", KEEP = \"yes\", IS_BEL_FIXED = \"yes\" *)\n", + iSlice, iSlice, pBels[iNode % 8] ); + fprintf( pFile, " LUT6 #(.INIT(64'h%016llX)) u_lut%d (\n", (unsigned long long)Truth, iNode ); + for ( k = 0; k < 6; k++ ) + { + fprintf( pFile, " .I%d(", k ); + if ( k < p->nLutSize ) + { + iVar = Exa3_ManFindFanin( p, i, k ); + if ( iVar < p->nVars ) + fprintf( pFile, "x[%d]", iVar ); + else + fprintf( pFile, "n%d", iVar - p->nVars ); + } + else + fprintf( pFile, "1'b0" ); + fprintf( pFile, "),\n" ); + } + if ( i == p->nObjs - 1 ) + fprintf( pFile, " .O(y)\n" ); + else + fprintf( pFile, " .O(n%d)\n", iNode ); + fprintf( pFile, " );\n\n" ); + } + fprintf( pFile, "endmodule\n\n" ); + fclose( pFile ); + printf( "Finished dumping the resulting LUT cascade into file \"%s\".\n", pFileName ); + return 1; +} +static int Exa3_ManDumpVerilog( Exa3_Man_t * p, int fCompl ) +{ + int i, k, iVar; + int nBits = 1 << p->nLutSize; + int nDigits = (nBits + 3) >> 2; + char pBase[128], pFileName[132], pModuleName[160]; + FILE * pFile; + if ( p->nLutSize > 6 ) + { + printf( "Vivado LUT dumping supports only LUTs with up to 6 inputs. Skipping Verilog dump.\n" ); + return 0; + } + Exa3_ManDumpVerilogName( p, pBase ); + snprintf( pFileName, sizeof(pFileName), "%s.v", pBase ); + snprintf( pModuleName, sizeof(pModuleName), "lut_net_%s", pBase ); + pFile = fopen( pFileName, "wb" ); + if ( pFile == NULL ) + return 0; + fprintf( pFile, "// Vivado LUT net for the %d-input function %s synthesized by ABC on %s\n", p->nVars, pBase, Extra_TimeStamp() ); + fprintf( pFile, "module %s (\n", pModuleName ); + fprintf( pFile, " input wire [%d:0] x,\n", p->nVars - 1 ); + fprintf( pFile, " output wire y\n" ); + fprintf( pFile, ");\n" ); + for ( i = 0; i < p->nNodes - 1; i++ ) + fprintf( pFile, " wire n%d;\n", i ); + if ( p->nNodes > 1 ) + fprintf( pFile, "\n" ); + for ( i = p->nVars; i < p->nObjs; i++ ) + { + int iNode = i - p->nVars; + int iVarStart = 1 + p->LutMask * iNode; + word Truth = 0; + word Mask = p->nLutSize == 6 ? ~(word)0 : ((((word)1) << nBits) - 1); + for ( k = 0; k < p->LutMask; k++ ) + if ( sat_solver_var_value(p->pSat, iVarStart + k) ) + Truth |= ((word)1) << (k + 1); + if ( i == p->nObjs - 1 && fCompl ) + Truth = (~Truth) & Mask; + fprintf( pFile, " LUT%d #(.INIT(%d'h%0*llX)) u_lut%d (\n", p->nLutSize, nBits, nDigits, (unsigned long long)Truth, iNode ); + for ( k = 0; k < p->nLutSize; k++ ) + { + fprintf( pFile, " .I%d(", k ); + iVar = Exa3_ManFindFanin( p, i, k ); + if ( iVar < p->nVars ) + fprintf( pFile, "x[%d]", iVar ); + else + fprintf( pFile, "n%d", iVar - p->nVars ); + fprintf( pFile, "),\n" ); + } + if ( i == p->nObjs - 1 ) + fprintf( pFile, " .O(y)\n" ); + else + fprintf( pFile, " .O(n%d)\n", iNode ); + fprintf( pFile, " );\n\n" ); + } + fprintf( pFile, "endmodule\n\n" ); + fclose( pFile ); + printf( "Finished dumping the resulting LUT network into file \"%s\".\n", pFileName ); + return 1; +} /**Function************************************************************* @@ -1445,7 +1596,16 @@ void Exa3_ManExactSynthesis2( Bmc_EsPar_t * pPars ) Exa3_ManPrintSolution( p, fCompl ); Abc_PrintTime( 1, "Total runtime", Abc_Clock() - clkTotal ); if ( iMint == -1 ) - Exa3_ManDumpBlif( p, fCompl ); + { + if ( pPars->fDumpBlif ) + { + Exa3_ManDumpBlif( p, fCompl ); + if ( pPars->fLutCascade ) + Exa3_ManDumpCascadeVerilog( p, fCompl ); + else + Exa3_ManDumpVerilog( p, fCompl ); + } + } if ( pPars->pSymStr ) ABC_FREE( pPars->pTtStr ); Exa3_ManFree( p ); @@ -1458,4 +1618,3 @@ void Exa3_ManExactSynthesis2( Bmc_EsPar_t * pPars ) ABC_NAMESPACE_IMPL_END - diff --git a/src/sat/bmc/bmcMaj7.c b/src/sat/bmc/bmcMaj7.c index dc36a61182..0a81756798 100644 --- a/src/sat/bmc/bmcMaj7.c +++ b/src/sat/bmc/bmcMaj7.c @@ -477,6 +477,161 @@ static void Exa7_ManPrintPerm( Exa7_Man_t * p ) } } } +static void Exa7_ManDumpVerilogName( Exa7_Man_t * p, char * pBase ) +{ + char Flags[32]; + int n = 0; + if ( p->pPars->pSymStr ) + snprintf( pBase, 128, "Y%.*s", 15, p->pPars->pSymStr ); + else + snprintf( pBase, 128, "%.*s", 16, p->pPars->pTtStr ); + if ( p->pPars->fUseIncr ) Flags[n++] = 'i'; + if ( p->pPars->fOnlyAnd ) Flags[n++] = 'a'; + if ( p->pPars->fFewerVars ) Flags[n++] = 'o'; + if ( p->pPars->fLutCascade ) Flags[n++] = 'r'; + if ( p->pPars->fLutInFixed ) Flags[n++] = 'f'; + if ( p->pPars->fGlucose ) Flags[n++] = 'g'; + if ( p->pPars->fCadical ) Flags[n++] = 'c'; + if ( p->pPars->fKissat ) Flags[n++] = 'k'; + if ( p->pPars->fDumpBlif ) Flags[n++] = 'd'; + if ( p->pPars->fMinNodes ) Flags[n++] = 'm'; + if ( p->pPars->fUsePerm ) Flags[n++] = 'p'; + Flags[n] = '\0'; + snprintf( pBase + strlen(pBase), 128 - strlen(pBase), "_K%d_M%d_%s", p->nLutSize, p->nNodes, Flags ); +} +static int Exa7_ManDumpCascadeVerilog( Exa7_Man_t * p, int fCompl ) +{ + static const char * pBels[8] = { "A6LUT", "B6LUT", "C6LUT", "D6LUT", "E6LUT", "F6LUT", "G6LUT", "H6LUT" }; + int i, k, iVar; + char pBase[128], pFileName[132], pModuleName[160]; + FILE * pFile; + if ( p->nLutSize > 6 ) + { + if ( !p->pPars->fSilent ) + printf( "Vivado LUT cascade dumping supports only LUTs with up to 6 inputs. Falling back to BLIF dumping.\n" ); + return 0; + } + Exa7_ManDumpVerilogName( p, pBase ); + snprintf( pFileName, sizeof(pFileName), "%s.v", pBase ); + snprintf( pModuleName, sizeof(pModuleName), "lut_cascade_%s", pBase ); + pFile = fopen( pFileName, "wb" ); + if ( pFile == NULL ) + return 0; + fprintf( pFile, "// Vivado LUT cascade for the %d-input function %s synthesized by ABC on %s\n", p->nVars, pBase, Extra_TimeStamp() ); + fprintf( pFile, "module %s (\n", pModuleName ); + fprintf( pFile, " input wire [%d:0] x,\n", p->nVars - 1 ); + fprintf( pFile, " output wire y\n" ); + fprintf( pFile, ");\n" ); + for ( i = 0; i < p->nNodes - 1; i++ ) + fprintf( pFile, " (* KEEP = \"yes\", DONT_TOUCH = \"yes\" *) wire n%d;\n", i ); + if ( p->nNodes > 1 ) + fprintf( pFile, "\n" ); + for ( i = p->nVars; i < p->nObjs; i++ ) + { + int iNode = i - p->nVars; + int iSlice = iNode / 8; + int iVarStart = 1 + p->LutMask * iNode; + word Truth = 0; + word Mask = p->nLutSize == 6 ? ~(word)0 : ((((word)1) << (1 << p->nLutSize)) - 1); + for ( k = 0; k < p->LutMask; k++ ) + if ( cadical_solver_get_var_value(p->pSat, iVarStart + k) ) + Truth |= ((word)1) << (k + 1); + if ( i == p->nObjs - 1 && fCompl ) + Truth = (~Truth) & Mask; + if ( p->nLutSize < 6 ) + Truth = Abc_Tt6Stretch( Truth, p->nLutSize ); + fprintf( pFile, " (* HU_SET = \"hu_lut_cascade_%d\", RLOC = \"X0Y%d\", BEL = \"%s\", DONT_TOUCH = \"yes\", KEEP = \"yes\", IS_BEL_FIXED = \"yes\" *)\n", + iSlice, iSlice, pBels[iNode % 8] ); + fprintf( pFile, " LUT6 #(.INIT(64'h%016llX)) u_lut%d (\n", (unsigned long long)Truth, iNode ); + for ( k = 0; k < 6; k++ ) + { + fprintf( pFile, " .I%d(", k ); + if ( k < p->nLutSize ) + { + iVar = Exa7_ManFindFanin( p, i, k ); + if ( iVar < p->nVars ) + fprintf( pFile, "x[%d]", iVar ); + else + fprintf( pFile, "n%d", iVar - p->nVars ); + } + else + fprintf( pFile, "1'b0" ); + fprintf( pFile, "),\n" ); + } + if ( i == p->nObjs - 1 ) + fprintf( pFile, " .O(y)\n" ); + else + fprintf( pFile, " .O(n%d)\n", iNode ); + fprintf( pFile, " );\n\n" ); + } + fprintf( pFile, "endmodule\n\n" ); + fclose( pFile ); + if ( !p->pPars->fSilent ) + printf( "Finished dumping the resulting LUT cascade into file \"%s\".\n", pFileName ); + return 1; +} +static int Exa7_ManDumpVerilog( Exa7_Man_t * p, int fCompl ) +{ + int i, k, iVar; + int nBits = 1 << p->nLutSize; + int nDigits = (nBits + 3) >> 2; + char pBase[128], pFileName[132], pModuleName[160]; + FILE * pFile; + if ( p->nLutSize > 6 ) + { + if ( !p->pPars->fSilent ) + printf( "Vivado LUT dumping supports only LUTs with up to 6 inputs. Skipping Verilog dump.\n" ); + return 0; + } + Exa7_ManDumpVerilogName( p, pBase ); + snprintf( pFileName, sizeof(pFileName), "%s.v", pBase ); + snprintf( pModuleName, sizeof(pModuleName), "lut_net_%s", pBase ); + pFile = fopen( pFileName, "wb" ); + if ( pFile == NULL ) + return 0; + fprintf( pFile, "// Vivado LUT net for the %d-input function %s synthesized by ABC on %s\n", p->nVars, pBase, Extra_TimeStamp() ); + fprintf( pFile, "module %s (\n", pModuleName ); + fprintf( pFile, " input wire [%d:0] x,\n", p->nVars - 1 ); + fprintf( pFile, " output wire y\n" ); + fprintf( pFile, ");\n" ); + for ( i = 0; i < p->nNodes - 1; i++ ) + fprintf( pFile, " wire n%d;\n", i ); + if ( p->nNodes > 1 ) + fprintf( pFile, "\n" ); + for ( i = p->nVars; i < p->nObjs; i++ ) + { + int iNode = i - p->nVars; + int iVarStart = 1 + p->LutMask * iNode; + word Truth = 0; + word Mask = p->nLutSize == 6 ? ~(word)0 : ((((word)1) << nBits) - 1); + for ( k = 0; k < p->LutMask; k++ ) + if ( cadical_solver_get_var_value(p->pSat, iVarStart + k) ) + Truth |= ((word)1) << (k + 1); + if ( i == p->nObjs - 1 && fCompl ) + Truth = (~Truth) & Mask; + fprintf( pFile, " LUT%d #(.INIT(%d'h%0*llX)) u_lut%d (\n", p->nLutSize, nBits, nDigits, (unsigned long long)Truth, iNode ); + for ( k = 0; k < p->nLutSize; k++ ) + { + fprintf( pFile, " .I%d(", k ); + iVar = Exa7_ManFindFanin( p, i, k ); + if ( iVar < p->nVars ) + fprintf( pFile, "x[%d]", iVar ); + else + fprintf( pFile, "n%d", iVar - p->nVars ); + fprintf( pFile, "),\n" ); + } + if ( i == p->nObjs - 1 ) + fprintf( pFile, " .O(y)\n" ); + else + fprintf( pFile, " .O(n%d)\n", iNode ); + fprintf( pFile, " );\n\n" ); + } + fprintf( pFile, "endmodule\n\n" ); + fclose( pFile ); + if ( !p->pPars->fSilent ) + printf( "Finished dumping the resulting LUT network into file \"%s\".\n", pFileName ); + return 1; +} /**Function************************************************************* @@ -829,7 +984,13 @@ int Exa7_ManExactSynthesis( Bmc_EsPar_t * pPars ) Exa7_ManPrintPerm( p ); printf( "\".\n" ); if ( pPars->fDumpBlif ) + { Exa7_ManDumpBlif( p, fCompl ); + if ( pPars->fLutCascade ) + Exa7_ManDumpCascadeVerilog( p, fCompl ); + else + Exa7_ManDumpVerilog( p, fCompl ); + } if ( p->pPars->fGenTruths ) { if ( p->pPars->vTruths ) Vec_WrdFreeP( &p->pPars->vTruths ); diff --git a/src/sat/bmc/bmcMaj8.c b/src/sat/bmc/bmcMaj8.c index b0c5391a9a..5b65fbbbf4 100644 --- a/src/sat/bmc/bmcMaj8.c +++ b/src/sat/bmc/bmcMaj8.c @@ -485,6 +485,161 @@ static void Exa8_ManPrintPerm( Exa8_Man_t * p ) } } } +static void Exa8_ManDumpVerilogName( Exa8_Man_t * p, char * pBase ) +{ + char Flags[32]; + int n = 0; + if ( p->pPars->pSymStr ) + snprintf( pBase, 128, "Y%.*s", 15, p->pPars->pSymStr ); + else + snprintf( pBase, 128, "%.*s", 16, p->pPars->pTtStr ); + if ( p->pPars->fUseIncr ) Flags[n++] = 'i'; + if ( p->pPars->fOnlyAnd ) Flags[n++] = 'a'; + if ( p->pPars->fFewerVars ) Flags[n++] = 'o'; + if ( p->pPars->fLutCascade ) Flags[n++] = 'r'; + if ( p->pPars->fLutInFixed ) Flags[n++] = 'f'; + if ( p->pPars->fGlucose ) Flags[n++] = 'g'; + if ( p->pPars->fCadical ) Flags[n++] = 'c'; + if ( p->pPars->fKissat ) Flags[n++] = 'k'; + if ( p->pPars->fDumpBlif ) Flags[n++] = 'd'; + if ( p->pPars->fMinNodes ) Flags[n++] = 'm'; + if ( p->pPars->fUsePerm ) Flags[n++] = 'p'; + Flags[n] = '\0'; + snprintf( pBase + strlen(pBase), 128 - strlen(pBase), "_K%d_M%d_%s", p->nLutSize, p->nNodes, Flags ); +} +static int Exa8_ManDumpCascadeVerilog( Exa8_Man_t * p, int fCompl ) +{ + static const char * pBels[8] = { "A6LUT", "B6LUT", "C6LUT", "D6LUT", "E6LUT", "F6LUT", "G6LUT", "H6LUT" }; + int i, k, iVar; + char pBase[128], pFileName[132], pModuleName[160]; + FILE * pFile; + if ( p->nLutSize > 6 ) + { + if ( !p->pPars->fSilent ) + printf( "Vivado LUT cascade dumping supports only LUTs with up to 6 inputs. Falling back to BLIF dumping.\n" ); + return 0; + } + Exa8_ManDumpVerilogName( p, pBase ); + snprintf( pFileName, sizeof(pFileName), "%s.v", pBase ); + snprintf( pModuleName, sizeof(pModuleName), "lut_cascade_%s", pBase ); + pFile = fopen( pFileName, "wb" ); + if ( pFile == NULL ) + return 0; + fprintf( pFile, "// Vivado LUT cascade for the %d-input function %s synthesized by ABC on %s\n", p->nVars, pBase, Extra_TimeStamp() ); + fprintf( pFile, "module %s (\n", pModuleName ); + fprintf( pFile, " input wire [%d:0] x,\n", p->nVars - 1 ); + fprintf( pFile, " output wire y\n" ); + fprintf( pFile, ");\n" ); + for ( i = 0; i < p->nNodes - 1; i++ ) + fprintf( pFile, " (* KEEP = \"yes\", DONT_TOUCH = \"yes\" *) wire n%d;\n", i ); + if ( p->nNodes > 1 ) + fprintf( pFile, "\n" ); + for ( i = p->nVars; i < p->nObjs; i++ ) + { + int iNode = i - p->nVars; + int iSlice = iNode / 8; + int iVarStart = 1 + p->LutMask * iNode; + word Truth = 0; + word Mask = p->nLutSize == 6 ? ~(word)0 : ((((word)1) << (1 << p->nLutSize)) - 1); + for ( k = 0; k < p->LutMask; k++ ) + if ( Exa8_KissatVarValue(p, iVarStart + k) ) + Truth |= ((word)1) << (k + 1); + if ( i == p->nObjs - 1 && fCompl ) + Truth = (~Truth) & Mask; + if ( p->nLutSize < 6 ) + Truth = Abc_Tt6Stretch( Truth, p->nLutSize ); + fprintf( pFile, " (* HU_SET = \"hu_lut_cascade_%d\", RLOC = \"X0Y%d\", BEL = \"%s\", DONT_TOUCH = \"yes\", KEEP = \"yes\", IS_BEL_FIXED = \"yes\" *)\n", + iSlice, iSlice, pBels[iNode % 8] ); + fprintf( pFile, " LUT6 #(.INIT(64'h%016llX)) u_lut%d (\n", (unsigned long long)Truth, iNode ); + for ( k = 0; k < 6; k++ ) + { + fprintf( pFile, " .I%d(", k ); + if ( k < p->nLutSize ) + { + iVar = Exa8_ManFindFanin( p, i, k ); + if ( iVar < p->nVars ) + fprintf( pFile, "x[%d]", iVar ); + else + fprintf( pFile, "n%d", iVar - p->nVars ); + } + else + fprintf( pFile, "1'b0" ); + fprintf( pFile, "),\n" ); + } + if ( i == p->nObjs - 1 ) + fprintf( pFile, " .O(y)\n" ); + else + fprintf( pFile, " .O(n%d)\n", iNode ); + fprintf( pFile, " );\n\n" ); + } + fprintf( pFile, "endmodule\n\n" ); + fclose( pFile ); + if ( !p->pPars->fSilent ) + printf( "Finished dumping the resulting LUT cascade into file \"%s\".\n", pFileName ); + return 1; +} +static int Exa8_ManDumpVerilog( Exa8_Man_t * p, int fCompl ) +{ + int i, k, iVar; + int nBits = 1 << p->nLutSize; + int nDigits = (nBits + 3) >> 2; + char pBase[128], pFileName[132], pModuleName[160]; + FILE * pFile; + if ( p->nLutSize > 6 ) + { + if ( !p->pPars->fSilent ) + printf( "Vivado LUT dumping supports only LUTs with up to 6 inputs. Skipping Verilog dump.\n" ); + return 0; + } + Exa8_ManDumpVerilogName( p, pBase ); + snprintf( pFileName, sizeof(pFileName), "%s.v", pBase ); + snprintf( pModuleName, sizeof(pModuleName), "lut_net_%s", pBase ); + pFile = fopen( pFileName, "wb" ); + if ( pFile == NULL ) + return 0; + fprintf( pFile, "// Vivado LUT net for the %d-input function %s synthesized by ABC on %s\n", p->nVars, pBase, Extra_TimeStamp() ); + fprintf( pFile, "module %s (\n", pModuleName ); + fprintf( pFile, " input wire [%d:0] x,\n", p->nVars - 1 ); + fprintf( pFile, " output wire y\n" ); + fprintf( pFile, ");\n" ); + for ( i = 0; i < p->nNodes - 1; i++ ) + fprintf( pFile, " wire n%d;\n", i ); + if ( p->nNodes > 1 ) + fprintf( pFile, "\n" ); + for ( i = p->nVars; i < p->nObjs; i++ ) + { + int iNode = i - p->nVars; + int iVarStart = 1 + p->LutMask * iNode; + word Truth = 0; + word Mask = p->nLutSize == 6 ? ~(word)0 : ((((word)1) << nBits) - 1); + for ( k = 0; k < p->LutMask; k++ ) + if ( Exa8_KissatVarValue(p, iVarStart + k) ) + Truth |= ((word)1) << (k + 1); + if ( i == p->nObjs - 1 && fCompl ) + Truth = (~Truth) & Mask; + fprintf( pFile, " LUT%d #(.INIT(%d'h%0*llX)) u_lut%d (\n", p->nLutSize, nBits, nDigits, (unsigned long long)Truth, iNode ); + for ( k = 0; k < p->nLutSize; k++ ) + { + fprintf( pFile, " .I%d(", k ); + iVar = Exa8_ManFindFanin( p, i, k ); + if ( iVar < p->nVars ) + fprintf( pFile, "x[%d]", iVar ); + else + fprintf( pFile, "n%d", iVar - p->nVars ); + fprintf( pFile, "),\n" ); + } + if ( i == p->nObjs - 1 ) + fprintf( pFile, " .O(y)\n" ); + else + fprintf( pFile, " .O(n%d)\n", iNode ); + fprintf( pFile, " );\n\n" ); + } + fprintf( pFile, "endmodule\n\n" ); + fclose( pFile ); + if ( !p->pPars->fSilent ) + printf( "Finished dumping the resulting LUT network into file \"%s\".\n", pFileName ); + return 1; +} /**Function************************************************************* @@ -789,7 +944,13 @@ int Exa8_ManExactSynthesis( Bmc_EsPar_t * pPars ) Exa8_ManPrintPerm(p); printf( "\".\n" ); if ( pPars->fDumpBlif ) + { Exa8_ManDumpBlif( p, fCompl ); + if ( pPars->fLutCascade ) + Exa8_ManDumpCascadeVerilog( p, fCompl ); + else + Exa8_ManDumpVerilog( p, fCompl ); + } if ( p->pPars->fGenTruths ) { if ( p->pPars->vTruths ) Vec_WrdFreeP( &p->pPars->vTruths ); From 24917213dfa5a4e1ad427c9a9bb2f8fe795cb086 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Thu, 19 Mar 2026 20:18:08 -0700 Subject: [PATCH 24/33] Updates to &if mapper. --- src/aig/gia/giaIf.c | 22 +++++++++++++++++++++- src/aig/gia/giaSpeedup.c | 4 ++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/aig/gia/giaIf.c b/src/aig/gia/giaIf.c index 682d7b1714..179b9c6308 100644 --- a/src/aig/gia/giaIf.c +++ b/src/aig/gia/giaIf.c @@ -2124,6 +2124,24 @@ void Gia_ManConfigPrint2( unsigned char * pConfigData, int nLeaves ) } } +static inline word Gia_ManFromIfPermuteTruth4( word Truth, int nLeaves, word z ) +{ + word TruthNew = 0; + int i, k, x; + assert( nLeaves >= 1 && nLeaves <= 4 ); + for ( i = 0; i < 16; i++ ) + { + x = 0; + for ( k = 0; k < nLeaves; k++ ) + { + int v = (int)((z >> (2 * k)) & 3); + x |= ((i >> k) & 1) << v; + } + TruthNew |= ((Truth >> x) & 1) << i; + } + return TruthNew; +} + /**Function************************************************************* Synopsis [Derive configurations.] @@ -2145,6 +2163,7 @@ void Gia_ManFromIfGetConfig2( Vec_Str_t * vConfigs2, If_Man_t * pIfMan, word * p { word z = If_CutPerformDeriveJ( pIfMan, (unsigned *)pTruth, nLeaves, nLeaves, NULL, 1, fDelay ); int fHavePerm = (z != 0) && ((z & ABC_CONST(0x4000000000000000)) != 0); + word Truth = pTruth[0]; // Cell type 0: Simple LUT4 CellId = 0; // Write CellId @@ -2158,7 +2177,8 @@ void Gia_ManFromIfGetConfig2( Vec_Str_t * vConfigs2, If_Man_t * pIfMan, word * p for ( ; i < 4; i++ ) Vec_StrPush( vConfigs2, 0 ); // Write truth table (16 bits for LUT4) - word Truth = pTruth[0]; + if ( fHavePerm ) + Truth = Gia_ManFromIfPermuteTruth4( Truth, nLeaves, z ); Vec_StrPush( vConfigs2, (char)((Truth >> 8) & 0xFF) ); Vec_StrPush( vConfigs2, (char)(Truth & 0xFF) ); assert( startPos + 7 == Vec_StrSize(vConfigs2) ); diff --git a/src/aig/gia/giaSpeedup.c b/src/aig/gia/giaSpeedup.c index e5caba8fcc..003acedcd5 100644 --- a/src/aig/gia/giaSpeedup.c +++ b/src/aig/gia/giaSpeedup.c @@ -57,7 +57,7 @@ static int Gia_ManConfig2GetBytePos( Gia_Man_t * p, int iObj ) } return -1; } -static int Gia_ManConfig2DerivePinDelays( Gia_Man_t * p, int iObj, If_LibCell_t * pCellLib, int * pPinDelay, int nLutSize ) +int Gia_ManConfig2DerivePinDelays( Gia_Man_t * p, int iObj, If_LibCell_t * pCellLib, int * pPinDelay, int nLutSize ) { int bytePos, i, nPins; unsigned char CellId; @@ -76,7 +76,7 @@ static int Gia_ManConfig2DerivePinDelays( Gia_Man_t * p, int iObj, If_LibCell_t { int v = (unsigned char)Vec_StrEntry( p->vConfigs2, bytePos + 1 + i ); if ( v >= 2 && v < 2 + nLutSize ) - pPinDelay[v - 2] = pCellLib->pCellPinDelays[CellId][i]; + pPinDelay[v - 2] = Abc_MaxInt( pPinDelay[v - 2], pCellLib->pCellPinDelays[CellId][i] ); } return 1; } From ceebb2d16727caaf624f7a8255a94a4623c0f8f7 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 23 Mar 2026 14:55:27 -0700 Subject: [PATCH 25/33] Updated to &sprove. --- src/base/abci/abc.c | 9 ++- src/proof/cec/cecProve.c | 162 +++++++++++++++++++++++++++++++-------- 2 files changed, 133 insertions(+), 38 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index e42dfb8a4d..1fb12e7f1c 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -51413,7 +51413,7 @@ int Abc_CommandAbc9SProve( Abc_Frame_t * pAbc, int argc, char ** argv ) { Gia_Man_t * pGiaUse = pAbc->pGia, * pGiaTemp = NULL; Wlc_Ntk_t * pWlc = (Wlc_Ntk_t *)pAbc->pAbcWlc; - int c, nProcs = 6, nTimeOut = 3, nTimeOut2 = 10, nTimeOut3 = 100, fUseUif = 0, fVerbose = 0, fVeryVerbose = 0, fSilent = 0; + int c, nProcs = 6, nProcsNew = 0, nTimeOut = 3, nTimeOut2 = 10, nTimeOut3 = 100, fUseUif = 0, fVerbose = 0, fVeryVerbose = 0, fSilent = 0; Extra_UtilGetoptReset(); while ( ( c = Extra_UtilGetopt( argc, argv, "PTUWusvwh" ) ) != EOF ) { @@ -51425,10 +51425,11 @@ int Abc_CommandAbc9SProve( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_Print( -1, "Command line switch \"-P\" should be followed by a positive integer.\n" ); goto usage; } - nProcs = atoi(argv[globalUtilOptind]); + nProcsNew = atoi(argv[globalUtilOptind]); globalUtilOptind++; - if ( nProcs <= 0 ) + if ( nProcsNew <= 0 || nProcsNew > 6 ) goto usage; + nProcs = nProcsNew; break; case 'T': if ( globalUtilOptind >= argc ) @@ -51526,7 +51527,7 @@ int Abc_CommandAbc9SProve( Abc_Frame_t * pAbc, int argc, char ** argv ) usage: Abc_Print( -2, "usage: &sprove [-PTUW num] [-usvwh]\n" ); Abc_Print( -2, "\t proves CEC problem by case-splitting\n" ); - Abc_Print( -2, "\t-P num : the number of concurrent processes [default = %d]\n", nProcs ); + Abc_Print( -2, "\t-P num : the number of concurrent processes (1 <= num <= 6) [default = %d]\n", nProcs ); Abc_Print( -2, "\t-T num : runtime limit in seconds per subproblem [default = %d]\n", nTimeOut ); Abc_Print( -2, "\t-U num : runtime limit in seconds per subproblem [default = %d]\n", nTimeOut2 ); Abc_Print( -2, "\t-W num : runtime limit in seconds per subproblem [default = %d]\n", nTimeOut3 ); diff --git a/src/proof/cec/cecProve.c b/src/proof/cec/cecProve.c index c3ed1fad71..cf8dfa7ed2 100644 --- a/src/proof/cec/cecProve.c +++ b/src/proof/cec/cecProve.c @@ -79,12 +79,15 @@ typedef struct Par_ThData_t_ Gia_Man_t * p; int iEngine; int fWorking; + int fStop; int nTimeOut; int Result; int fVerbose; int nTimeOutU; Wlc_Ntk_t * pWlc; Par_Share_t * pShare; + pthread_mutex_t Mutex; + pthread_cond_t Cond; } Par_ThData_t; typedef struct Cec_ScorrStop_t_ { @@ -98,12 +101,12 @@ static inline const char * Cec_SolveEngineName( int iEngine ) if ( iEngine == 0 ) return "rar"; if ( iEngine == 1 ) return "bmc"; if ( iEngine == 2 ) return "pdr"; - if ( iEngine == 3 ) return "bmc-glucose"; - if ( iEngine == 4 ) return "pdr-abs"; + if ( iEngine == 3 ) return "bmc-g"; + if ( iEngine == 4 ) return "pdr-t"; if ( iEngine == 5 ) return "bmcg"; if ( iEngine == PAR_ENGINE_UFAR ) return "ufar"; - if ( iEngine == PAR_ENGINE_SCORR1 ) return "scorr-new"; - if ( iEngine == PAR_ENGINE_SCORR2 ) return "scorr-old"; + if ( iEngine == PAR_ENGINE_SCORR1 ) return "scnew"; + if ( iEngine == PAR_ENGINE_SCORR2 ) return "scold"; if ( iEngine == PAR_ENGINE_GLA ) return "gla-q"; return "unknown"; } @@ -189,12 +192,12 @@ int Cec_GiaProveOne( Gia_Man_t * p, int iEngine, int nTimeOut, int fVerbose, Par if ( iEngine != PAR_ENGINE_UFAR && iEngine != PAR_ENGINE_GLA && Gia_ManRegNum(p) == 0 ) { if ( fVerbose ) - printf( "Engine %d skipped because the current miter is combinational.\n", iEngine ); + printf( "Engine %d (%-5s) skipped because the current miter is combinational.\n", iEngine, Cec_SolveEngineName(iEngine) ); return -1; } //abctime clkStop = nTimeOut * CLOCKS_PER_SEC + Abc_Clock(); if ( fVerbose ) - printf( "Calling engine %d with timeout %d sec.\n", iEngine, nTimeOut ); + printf( "Calling engine %d (%-5s) with timeout %d sec.\n", iEngine, Cec_SolveEngineName(iEngine), nTimeOut ); Abc_CexFreeP( &p->pCexSeq ); if ( iEngine == 0 ) { @@ -324,7 +327,7 @@ int Cec_GiaProveOne( Gia_Man_t * p, int iEngine, int nTimeOut, int fVerbose, Par if ( pThData && pThData->pShare && RetValue != -1 ) Cec_SProveCallback( (void *)pThData, 1, (unsigned)RetValue ); if ( fVerbose ) { - printf( "Engine %d finished and %ssolved the problem. ", iEngine, RetValue != -1 ? " " : "not " ); + printf( "Engine %d (%-5s) finished and %ssolved the problem. ", iEngine, Cec_SolveEngineName(iEngine), RetValue != -1 ? " " : "not " ); Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); } return RetValue; @@ -379,30 +382,86 @@ Gia_Man_t * Cec_GiaScorrNew( Gia_Man_t * p, int nTimeOut, Par_Share_t * pShare ) void * Cec_GiaProveWorkerThread( void * pArg ) { Par_ThData_t * pThData = (Par_ThData_t *)pArg; - volatile int * pPlace = &pThData->fWorking; + int status, Result; + status = pthread_mutex_lock( &pThData->Mutex ); + assert( status == 0 ); while ( 1 ) { - while ( *pPlace == 0 ); - assert( pThData->fWorking ); - if ( pThData->p == NULL ) + while ( !pThData->fWorking && !pThData->fStop ) { - pthread_exit( NULL ); - assert( 0 ); - return NULL; + status = pthread_cond_wait( &pThData->Cond, &pThData->Mutex ); + assert( status == 0 ); } - pThData->Result = Cec_GiaProveOne( pThData->p, pThData->iEngine, pThData->nTimeOut, pThData->fVerbose, pThData ); + if ( pThData->fStop ) + break; + status = pthread_mutex_unlock( &pThData->Mutex ); + assert( status == 0 ); + Result = Cec_GiaProveOne( pThData->p, pThData->iEngine, pThData->nTimeOut, pThData->fVerbose, pThData ); + status = pthread_mutex_lock( &pThData->Mutex ); + assert( status == 0 ); + pThData->Result = Result; pThData->fWorking = 0; + status = pthread_cond_broadcast( &pThData->Cond ); + assert( status == 0 ); } - assert( 0 ); + status = pthread_mutex_unlock( &pThData->Mutex ); + assert( status == 0 ); return NULL; } -void Cec_GiaInitThreads( Par_ThData_t * ThData, int nWorkers, Gia_Man_t * p, int nTimeOut, int nTimeOutU, Wlc_Ntk_t * pWlc, int fUseUif, int fVerbose, pthread_t * WorkerThread, Par_Share_t * pShare ) +static void Cec_GiaStartThreads( Par_ThData_t * ThData, int nWorkers ) +{ + int i, status; + for ( i = 0; i < nWorkers; i++ ) + { + status = pthread_mutex_lock( &ThData[i].Mutex ); + assert( status == 0 ); + assert( !ThData[i].fStop ); + assert( !ThData[i].fWorking ); + ThData[i].fWorking = 1; + status = pthread_cond_signal( &ThData[i].Cond ); + assert( status == 0 ); + status = pthread_mutex_unlock( &ThData[i].Mutex ); + assert( status == 0 ); + } +} +static void Cec_GiaInitThreads( Par_ThData_t * ThData, int nWorkers, Gia_Man_t * p, int nTimeOut, int nTimeOutU, Wlc_Ntk_t * pWlc, int fUseUif, int fVerbose, pthread_t * WorkerThread, Par_Share_t * pShare ) { int i, status; assert( nWorkers <= PAR_THR_MAX ); for ( i = 0; i < nWorkers; i++ ) { - ThData[i].p = Gia_ManDup(p); + if ( WorkerThread ) + { + ThData[i].p = Gia_ManDup( p ); + Cec_CopyGiaName( p, ThData[i].p ); + if ( fUseUif && i == nWorkers - 1 ) + ThData[i].iEngine = PAR_ENGINE_UFAR; + else if ( !fUseUif && nWorkers == 6 && i == 5 ) + ThData[i].iEngine = PAR_ENGINE_GLA; + else + ThData[i].iEngine = i; + ThData[i].fWorking = 0; + ThData[i].fStop = 0; + ThData[i].nTimeOut = nTimeOut; + ThData[i].Result = -1; + ThData[i].fVerbose = fVerbose; + ThData[i].nTimeOutU= nTimeOutU; + ThData[i].pWlc = pWlc; + ThData[i].pShare = pShare; + status = pthread_mutex_init( &ThData[i].Mutex, NULL ); + assert( status == 0 ); + status = pthread_cond_init( &ThData[i].Cond, NULL ); + assert( status == 0 ); + status = pthread_create( WorkerThread + i, NULL, Cec_GiaProveWorkerThread, (void *)(ThData + i) ); + assert( status == 0 ); + continue; + } + status = pthread_mutex_lock( &ThData[i].Mutex ); + assert( status == 0 ); + assert( !ThData[i].fStop ); + assert( !ThData[i].fWorking ); + Gia_ManStopP( &ThData[i].p ); + ThData[i].p = Gia_ManDup( p ); Cec_CopyGiaName( p, ThData[i].p ); if ( fUseUif && i == nWorkers - 1 ) ThData[i].iEngine = PAR_ENGINE_UFAR; @@ -411,31 +470,58 @@ void Cec_GiaInitThreads( Par_ThData_t * ThData, int nWorkers, Gia_Man_t * p, int else ThData[i].iEngine = i; ThData[i].nTimeOut = nTimeOut; - ThData[i].fWorking = 0; ThData[i].Result = -1; ThData[i].fVerbose = fVerbose; ThData[i].nTimeOutU= nTimeOutU; ThData[i].pWlc = pWlc; ThData[i].pShare = pShare; - if ( !WorkerThread ) - continue; - status = pthread_create( WorkerThread + i, NULL,Cec_GiaProveWorkerThread, (void *)(ThData + i) ); assert( status == 0 ); + status = pthread_mutex_unlock( &ThData[i].Mutex ); + assert( status == 0 ); } + Cec_GiaStartThreads( ThData, nWorkers ); +} +static void Cec_GiaStopThreads( Par_ThData_t * ThData, pthread_t * WorkerThread, int nWorkers ) +{ + int i, status; for ( i = 0; i < nWorkers; i++ ) - ThData[i].fWorking = 1; + { + status = pthread_mutex_lock( &ThData[i].Mutex ); + assert( status == 0 ); + ThData[i].fStop = 1; + status = pthread_cond_signal( &ThData[i].Cond ); + assert( status == 0 ); + status = pthread_mutex_unlock( &ThData[i].Mutex ); + assert( status == 0 ); + } + for ( i = 0; i < nWorkers; i++ ) + { + status = pthread_join( WorkerThread[i], NULL ); + assert( status == 0 ); + Gia_ManStopP( &ThData[i].p ); + status = pthread_cond_destroy( &ThData[i].Cond ); + assert( status == 0 ); + status = pthread_mutex_destroy( &ThData[i].Mutex ); + assert( status == 0 ); + } } -int Cec_GiaWaitThreads( Par_ThData_t * ThData, int nWorkers, Gia_Man_t * p, int RetValue, int * pRetEngine ) +static int Cec_GiaWaitThreads( Par_ThData_t * ThData, int nWorkers, Gia_Man_t * p, int RetValue, int * pRetEngine ) { - int i; + int i, status, fWorking; for ( i = 0; i < nWorkers; i++ ) { - if ( RetValue == -1 && !ThData[i].fWorking && ThData[i].Result != -1 ) { + status = pthread_mutex_lock( &ThData[i].Mutex ); + assert( status == 0 ); + fWorking = ThData[i].fWorking; + if ( RetValue == -1 && !fWorking && ThData[i].Result != -1 ) + { RetValue = ThData[i].Result; *pRetEngine = ThData[i].iEngine; if ( !p->pCexSeq && ThData[i].p->pCexSeq ) p->pCexSeq = Abc_CexDup( ThData[i].p->pCexSeq, -1 ); } - if ( ThData[i].fWorking ) + status = pthread_mutex_unlock( &ThData[i].Mutex ); + assert( status == 0 ); + if ( fWorking ) i = -1; } return RetValue; @@ -447,8 +533,10 @@ int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, in Par_ThData_t ThData[PAR_THR_MAX]; pthread_t WorkerThread[PAR_THR_MAX]; Par_Share_t Share; - int i, nWorkers = nProcs + (fUseUif ? 1 : 0), RetValue = -1, RetEngine = -1; + int nWorkers = nProcs + (fUseUif ? 1 : 0), RetValue = -1, RetEngine = -1; memset( &Share, 0, sizeof(Par_Share_t) ); + memset( ThData, 0, sizeof(ThData) ); + memset( WorkerThread, 0, sizeof(WorkerThread) ); Abc_CexFreeP( &p->pCexComb ); Abc_CexFreeP( &p->pCexSeq ); if ( !fSilent && fVerbose ) @@ -457,7 +545,7 @@ int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, in printf( "Processes = %d TimeOut = %d sec Verbose = %d.\n", nProcs, nTimeOut, fVerbose ); fflush( stdout ); - assert( nProcs == 3 || nProcs == 5 || nProcs == 6 ); + assert( nProcs >= 1 && nProcs <= 6 ); assert( nWorkers <= PAR_THR_MAX ); Cec_GiaInitThreads( ThData, nWorkers, p, nTimeOut, nTimeOut3, pWlc, fUseUif, fVerbose, WorkerThread, &Share ); @@ -465,7 +553,12 @@ int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, in Gia_Man_t * pScorr = Cec_GiaScorrNew( p, nTimeOut, &Share ); clkScorr = Abc_Clock() - clkTotal; if ( Gia_ManAndNum(pScorr) == 0 ) + { + Share.fSolved = 1; + Share.Result = 1; + Share.iEngine = PAR_ENGINE_SCORR1; RetValue = 1, RetEngine = PAR_ENGINE_SCORR1; + } RetValue = Cec_GiaWaitThreads( ThData, nWorkers, p, RetValue, &RetEngine ); if ( RetValue == -1 ) @@ -484,7 +577,12 @@ int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, in Gia_Man_t * pScorr2 = Cec_GiaScorrOld( pScorr, nTimeOut3, &Share ); clkScorr2 = Abc_Clock() - clkStart; if ( Gia_ManAndNum(pScorr2) == 0 ) + { + Share.fSolved = 1; + Share.Result = 1; + Share.iEngine = PAR_ENGINE_SCORR2; RetValue = 1, RetEngine = PAR_ENGINE_SCORR2; + } if ( RetValue == -1 ) { @@ -503,11 +601,7 @@ int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, in Gia_ManStop( pScorr ); // stop threads - for ( i = 0; i < nWorkers; i++ ) - { - ThData[i].p = NULL; - ThData[i].fWorking = 1; - } + Cec_GiaStopThreads( ThData, WorkerThread, nWorkers ); if ( !fSilent ) { char * pProbName = p->pSpec ? p->pSpec : Gia_ManName(p); From 3881f2de3777c36c2bcc2361836e62e8d0a064d4 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 23 Mar 2026 17:34:59 -0700 Subject: [PATCH 26/33] Updated to &sprove. --- src/aig/gia/giaIf.c | 8 +++++--- src/aig/gia/giaSpeedup.c | 19 +++++++++--------- src/map/if/if.h | 2 +- src/map/if/ifDecJ.c | 7 ++----- src/map/if/ifLibLut.c | 34 ++++++++++++++++++++++++++++++++ src/map/if/ifTrace.c | 42 ++++++++++++++++++++++++++++++++++++++++ src/map/if/ifTune.c | 9 +++++---- src/map/if/module.make | 1 + 8 files changed, 99 insertions(+), 23 deletions(-) create mode 100644 src/map/if/ifTrace.c diff --git a/src/aig/gia/giaIf.c b/src/aig/gia/giaIf.c index 179b9c6308..e981dcf33d 100644 --- a/src/aig/gia/giaIf.c +++ b/src/aig/gia/giaIf.c @@ -2157,6 +2157,8 @@ void Gia_ManFromIfGetConfig2( Vec_Str_t * vConfigs2, If_Man_t * pIfMan, word * p { int i, CellId; int startPos = Vec_StrSize(vConfigs2); + If_LibCell_t * pCellLib = pIfMan && pIfMan->pPars ? pIfMan->pPars->pCellLib : NULL; + assert( pCellLib != NULL ); // Determine cell type based on the number of leaves and configuration if ( nLeaves <= 4 ) // 7 bytes = 1 byte CellId + 4 bytes mapping + 2 bytes truth table @@ -2181,7 +2183,7 @@ void Gia_ManFromIfGetConfig2( Vec_Str_t * vConfigs2, If_Man_t * pIfMan, word * p Truth = Gia_ManFromIfPermuteTruth4( Truth, nLeaves, z ); Vec_StrPush( vConfigs2, (char)((Truth >> 8) & 0xFF) ); Vec_StrPush( vConfigs2, (char)(Truth & 0xFF) ); - assert( startPos + 7 == Vec_StrSize(vConfigs2) ); + assert( startPos + pCellLib->pCellRecordSizes[CellId] == Vec_StrSize(vConfigs2) ); //Gia_ManConfigPrint( Truth, 0, nLeaves ); } else // 12 bytes = 1 byte CellId + 7 bytes mapping + 4 bytes truth tables @@ -2226,7 +2228,7 @@ void Gia_ManFromIfGetConfig2( Vec_Str_t * vConfigs2, If_Man_t * pIfMan, word * p Vec_StrPush( vConfigs2, (char)(Truth1 & 0xFF) ); Vec_StrPush( vConfigs2, (char)((Truth2 >> 8) & 0xFF) ); Vec_StrPush( vConfigs2, (char)(Truth2 & 0xFF) ); - assert( startPos + 12 == Vec_StrSize(vConfigs2) ); + assert( startPos + pCellLib->pCellRecordSizes[CellId] == Vec_StrSize(vConfigs2) ); } else // 14 bytes = 1 byte CellId + 9 bytes mapping + 4 bytes truth tables { @@ -2251,7 +2253,7 @@ void Gia_ManFromIfGetConfig2( Vec_Str_t * vConfigs2, If_Man_t * pIfMan, word * p Vec_StrPush( vConfigs2, (char)(Truth1 & 0xFF) ); Vec_StrPush( vConfigs2, (char)((Truth2 >> 8) & 0xFF) ); Vec_StrPush( vConfigs2, (char)(Truth2 & 0xFF) ); - assert( startPos + 14 == Vec_StrSize(vConfigs2) ); + assert( startPos + pCellLib->pCellRecordSizes[CellId] == Vec_StrSize(vConfigs2) ); } } if ( pIfMan->pPars->fVerboseTrace ) diff --git a/src/aig/gia/giaSpeedup.c b/src/aig/gia/giaSpeedup.c index 003acedcd5..6986c84185 100644 --- a/src/aig/gia/giaSpeedup.c +++ b/src/aig/gia/giaSpeedup.c @@ -33,27 +33,26 @@ ABC_NAMESPACE_IMPL_START /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// -static int Gia_ManConfig2GetBytePos( Gia_Man_t * p, int iObj ) +static int Gia_ManConfig2GetBytePos( Gia_Man_t * p, int iObj, If_LibCell_t * pCellLib ) { int iLut, bytePos = 0; - if ( p == NULL || p->vConfigs2 == NULL ) + if ( p == NULL || p->vConfigs2 == NULL || pCellLib == NULL ) return -1; Gia_ManForEachLut( p, iLut ) { unsigned char CellId; + int nRecordSize; if ( bytePos >= Vec_StrSize(p->vConfigs2) ) return -1; if ( iLut == iObj ) return bytePos; CellId = (unsigned char)Vec_StrEntry( p->vConfigs2, bytePos ); - if ( CellId == 0 ) - bytePos += 7; - else if ( CellId == 1 ) - bytePos += 12; - else if ( CellId == 2 ) - bytePos += 14; - else + if ( CellId >= IF_MAX_LUTSIZE ) + return -1; + nRecordSize = pCellLib->pCellRecordSizes[CellId]; + if ( nRecordSize <= 0 ) return -1; + bytePos += nRecordSize; } return -1; } @@ -65,7 +64,7 @@ int Gia_ManConfig2DerivePinDelays( Gia_Man_t * p, int iObj, If_LibCell_t * pCell return 0; for ( i = 0; i < nLutSize; i++ ) pPinDelay[i] = 1; - bytePos = Gia_ManConfig2GetBytePos( p, iObj ); + bytePos = Gia_ManConfig2GetBytePos( p, iObj, pCellLib ); if ( bytePos < 0 || bytePos >= Vec_StrSize(p->vConfigs2) ) return 0; CellId = (unsigned char)Vec_StrEntry( p->vConfigs2, bytePos ); diff --git a/src/map/if/if.h b/src/map/if/if.h index bfc451c6c1..a76b66268f 100644 --- a/src/map/if/if.h +++ b/src/map/if/if.h @@ -203,6 +203,7 @@ struct If_LibCell_t_ char * pName; // the name of the LUT library int nCellNum; // the number of cells in the library int nCellInputs[IF_MAX_LUTSIZE]; + int pCellRecordSizes[IF_MAX_LUTSIZE]; char * pCellNames[IF_MAX_LUTSIZE]; float pCellAreas[IF_MAX_LUTSIZE]; int pCellPinDelays[IF_MAX_LUTSIZE][IF_MAX_LUTSIZE]; @@ -753,4 +754,3 @@ ABC_NAMESPACE_HEADER_END //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// - diff --git a/src/map/if/ifDecJ.c b/src/map/if/ifDecJ.c index d9676727b8..61b5c744f7 100644 --- a/src/map/if/ifDecJ.c +++ b/src/map/if/ifDecJ.c @@ -1,6 +1,6 @@ /**CFile**************************************************************** - FileName [ifDec07.c] + FileName [ifDecJ.c] SystemName [ABC: Logic synthesis and verification system.] @@ -14,7 +14,7 @@ Date [Ver. 1.0. Started - November 21, 2006.] - Revision [$Id: ifDec07.c,v 1.00 2006/11/21 00:00:00 alanmi Exp $] + Revision [$Id: ifDecJ.c,v 1.00 2006/11/21 00:00:00 alanmi Exp $] ***********************************************************************/ @@ -45,9 +45,6 @@ void If_CutComputeIntrinsicJ( If_Man_t * p, word Config, int nLeaves, int * pInt 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 ee819a2a1f..afb44e680c 100644 --- a/src/map/if/ifLibLut.c +++ b/src/map/if/ifLibLut.c @@ -388,6 +388,39 @@ If_LibCell_t * If_LibCellAlloc( void ) return p; } +/**Function************************************************************* + + Synopsis [Computes the record size.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static int If_LibCellComputeRecordSize( char * pFuncDesc, int nInputs ) +{ + int i, nMapBytes, nRecordSize; + assert( pFuncDesc != NULL ); + nMapBytes = (Abc_Base2Log(nInputs + 2) + 7) / 8; + nRecordSize = 1 + nInputs * nMapBytes; + for ( i = 0; pFuncDesc[i]; i++ ) + { + int nLutVars = 0; + if ( pFuncDesc[i] != '{' ) + continue; + for ( i++; pFuncDesc[i] && pFuncDesc[i] != '}'; i++ ) + if ( pFuncDesc[i] >= 'a' && pFuncDesc[i] <= 'z' ) + nLutVars++; + assert( nLutVars < 31 ); + nRecordSize += ((1 << nLutVars) + 7) / 8; + if ( pFuncDesc[i] == 0 ) + break; + } + return nRecordSize; +} + /**Function************************************************************* Synopsis [Reads the description of cells from the cell library file.] @@ -471,6 +504,7 @@ If_LibCell_t * If_LibCellRead( char * FileName ) nInputs = maxChar - 'a' + 1; } p->nCellInputs[CellId] = nInputs; + p->pCellRecordSizes[CellId] = If_LibCellComputeRecordSize( FuncDesc, nInputs ); // Read Area pToken = strtok( NULL, " \t\n" ); diff --git a/src/map/if/ifTrace.c b/src/map/if/ifTrace.c new file mode 100644 index 0000000000..5a1c0d7924 --- /dev/null +++ b/src/map/if/ifTrace.c @@ -0,0 +1,42 @@ +/**CFile**************************************************************** + + FileName [ifTrace.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [FPGA mapping based on priority cuts.] + + Synopsis [Public stub for delay trace dumping.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - March 23, 2026.] + + Revision [$Id: ifTrace.c,v 1.00 2026/03/23 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "if.h" +#include "aig/gia/gia.h" + +ABC_NAMESPACE_IMPL_START + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +void Gia_ManDelayTraceDump( Gia_Man_t * p, char * pFileName ) +{ +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + +ABC_NAMESPACE_IMPL_END diff --git a/src/map/if/ifTune.c b/src/map/if/ifTune.c index 98bdf8c25e..f54b74eb3c 100644 --- a/src/map/if/ifTune.c +++ b/src/map/if/ifTune.c @@ -1031,12 +1031,14 @@ void * If_ManDeriveGiaFromCells2( void * pGia ) { Gia_Man_t * p = (Gia_Man_t *)pGia; Gia_Man_t * pNew, * pTemp; + If_LibCell_t * pCellLib = (If_LibCell_t *)p->pCellLib; Vec_Int_t * vCover, * vLeaves; Gia_Obj_t * pObj; unsigned char * pConfigData; int k, i, iLut, iVar; int Count = 0; assert( p->vConfigs2 != NULL ); + assert( pCellLib != NULL ); assert( Gia_ManHasMapping(p) ); // create new manager pNew = Gia_ManStart( 6*Gia_ManObjNum(p)/5 + 100 ); @@ -1078,7 +1080,7 @@ void * If_ManDeriveGiaFromCells2( void * pGia ) Truth = Abc_Tt6Stretch( Truth, 4 ); extern int Kit_TruthToGia( Gia_Man_t * pMan, unsigned * pTruth, int nVars, Vec_Int_t * vMemory, Vec_Int_t * vLeaves, int fHash ); Gia_ManObj(p, iLut)->Value = Kit_TruthToGia( pNew, (unsigned *)&Truth, Vec_IntSize(vLeaves), vCover, vLeaves, 1 ); - bytePos += 7; // 1 byte CellId + 4 bytes mapping + 2 bytes truth table + bytePos += pCellLib->pCellRecordSizes[CellId]; } else if ( CellId == 1 ) { @@ -1122,7 +1124,7 @@ void * If_ManDeriveGiaFromCells2( void * pGia ) iObjLit2 = Kit_TruthToGia( pNew, (unsigned *)&Truth2, Vec_IntSize(vLeavesTemp), vCover, vLeavesTemp, 1 ); Gia_ManObj(p, iLut)->Value = iObjLit2; Vec_IntFree( vLeavesTemp ); - bytePos += 12; // 1 byte CellId + 7 bytes mapping + 4 bytes truth tables + bytePos += pCellLib->pCellRecordSizes[CellId]; } else if ( CellId == 2 ) { @@ -1177,7 +1179,7 @@ void * If_ManDeriveGiaFromCells2( void * pGia ) iObjLit3 = Gia_ManHashMux( pNew, iSelectLit, iObjLit2, iObjLit1 ); Gia_ManObj(p, iLut)->Value = iObjLit3; Vec_IntFree( vLeavesTemp ); - bytePos += 14; // 1 byte CellId + 9 bytes mapping + 4 bytes truth tables + bytePos += pCellLib->pCellRecordSizes[CellId]; } else { @@ -1755,4 +1757,3 @@ void Ifn_NtkRead() ABC_NAMESPACE_IMPL_END - diff --git a/src/map/if/module.make b/src/map/if/module.make index 96c90cab8a..6be4f663e1 100644 --- a/src/map/if/module.make +++ b/src/map/if/module.make @@ -10,6 +10,7 @@ SRC += src/map/if/ifCom.c \ src/map/if/ifDec66.c \ src/map/if/ifDec75.c \ src/map/if/ifDecJ.c \ + src/map/if/ifTrace.c \ src/map/if/ifDelay.c \ src/map/if/ifDsd.c \ src/map/if/ifLibBox.c \ From 7a28b20d8e689cb56bafa444e6e32eb6901e54e0 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 23 Mar 2026 17:44:06 -0700 Subject: [PATCH 27/33] Fix windows build. --- abclib.dsp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/abclib.dsp b/abclib.dsp index 7b36b34e8f..321b851dfc 100644 --- a/abclib.dsp +++ b/abclib.dsp @@ -4510,6 +4510,10 @@ SOURCE=.\src\map\if\ifUtil.c # End Source File # Begin Source File +SOURCE=.\src\map\if\ifTrace.c +# End Source File +# Begin Source File + SOURCE=.\src\map\if\ifDecJ.c # End Source File # End Group From 60e0303e3a622e26877cc707eefc5ae1a685e713 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Tue, 24 Mar 2026 20:16:09 -0700 Subject: [PATCH 28/33] Fix a mismatch in cut selection. --- src/map/if/ifMap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/map/if/ifMap.c b/src/map/if/ifMap.c index 6b710d6e09..f93b73edb0 100644 --- a/src/map/if/ifMap.c +++ b/src/map/if/ifMap.c @@ -168,7 +168,7 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep int fFunc0R, fFunc1R; int i, k, v, iCutDsd, fChange; int fSave0 = p->pPars->fDelayOpt || p->pPars->fDelayOptLut || p->pPars->fDsdBalance || p->pPars->fUserRecLib || p->pPars->fUserSesLib || p->pPars->fUserLutDec || p->pPars->fUserLut2D || - p->pPars->fUseDsdTune || p->pPars->fUseCofVars || p->pPars->fUseAndVars || p->pPars->fUse34Spec || p->pPars->pLutStruct || p->pPars->pFuncCell2 || p->pPars->fUseCheck1 || p->pPars->fUseCheck2; + p->pPars->fUseDsdTune || p->pPars->fUseCofVars || p->pPars->fUseAndVars || p->pPars->fUse34Spec || p->pPars->pLutStruct || p->pPars->pFuncCell2 || p->pPars->fUseCheck1 || p->pPars->fUseCheck2 || p->pPars->fEnableCheck07; int fUseAndCut = (p->pPars->nAndDelay > 0) || (p->pPars->nAndArea > 0); assert( !If_ObjIsAnd(pObj->pFanin0) || pObj->pFanin0->pCutSet->nCuts > 0 ); assert( !If_ObjIsAnd(pObj->pFanin1) || pObj->pFanin1->pCutSet->nCuts > 0 ); @@ -593,7 +593,7 @@ void If_ObjPerformMappingChoice( If_Man_t * p, If_Obj_t * pObj, int Mode, int fP If_Set_t * pCutSet; If_Obj_t * pTemp; If_Cut_t * pCutTemp, * pCut; - int i, fSave0 = p->pPars->fDelayOpt || p->pPars->fDelayOptLut || p->pPars->fDsdBalance || p->pPars->fUserRecLib || p->pPars->fUserSesLib || p->pPars->fUse34Spec || p->pPars->fUserLutDec || p->pPars->fUserLut2D; + int i, fSave0 = p->pPars->fDelayOpt || p->pPars->fDelayOptLut || p->pPars->fDsdBalance || p->pPars->fUserRecLib || p->pPars->fUserSesLib || p->pPars->fUse34Spec || p->pPars->fUserLutDec || p->pPars->fUserLut2D || p->pPars->fEnableCheck07; assert( pObj->pEquiv != NULL ); // prepare From 6aaf0db1e1201d72888a461463485b0b5595075a Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Wed, 25 Mar 2026 10:03:26 -0700 Subject: [PATCH 29/33] Fixing the required time problem. --- src/aig/gia/giaIf.c | 14 ++++++++++++++ src/map/if/ifTime.c | 21 ++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/aig/gia/giaIf.c b/src/aig/gia/giaIf.c index e981dcf33d..c2d8886c0a 100644 --- a/src/aig/gia/giaIf.c +++ b/src/aig/gia/giaIf.c @@ -3000,6 +3000,20 @@ Gia_Man_t * Gia_ManPerformMappingInt( Gia_Man_t * p, If_Par_t * pPars ) pPars->pTimesReq[i] = EntryF; } */ + if ( p->pManTime && pPars->pTimesArr == NULL ) + { + Tim_Man_t * pManTime = (Tim_Man_t *)p->pManTime; + pPars->pTimesArr = ABC_CALLOC( float, Gia_ManCiNum(p) ); + for ( i = 0; i < Gia_ManCiNum(p); i++ ) + pPars->pTimesArr[i] = Tim_ManGetCiArrival( pManTime, i ); + } + if ( p->pManTime && pPars->pTimesReq == NULL ) + { + Tim_Man_t * pManTime = (Tim_Man_t *)p->pManTime; + pPars->pTimesReq = ABC_CALLOC( float, Gia_ManCoNum(p) ); + for ( i = 0; i < Gia_ManCoNum(p); i++ ) + pPars->pTimesReq[i] = Tim_ManGetCoRequired( pManTime, i ); + } ABC_FREE( p->pCellStr ); Vec_IntFreeP( &p->vConfigs ); Vec_StrFreeP( &p->vConfigs2 ); diff --git a/src/map/if/ifTime.c b/src/map/if/ifTime.c index 2b3e21a5ad..81f88fd72e 100644 --- a/src/map/if/ifTime.c +++ b/src/map/if/ifTime.c @@ -477,7 +477,26 @@ void If_ManComputeRequired( If_Man_t * p ) return; // set the required times for the POs Tim_ManIncrementTravId( p->pManTim ); - if ( p->vCoAttrs ) + if ( p->pPars->pTimesReq ) + { + Counter = 0; + If_ManForEachCo( p, pObj, i ) + { + reqTime = p->pPars->pTimesReq[i]; + if ( If_ObjArrTime(If_ObjFanin0(pObj)) > reqTime + p->fEpsilon ) + { + reqTime = If_ObjArrTime(If_ObjFanin0(pObj)); + Counter++; + } + Tim_ManSetCoRequired( p->pManTim, i, reqTime ); + } + if ( Counter && !p->fReqTimeWarn ) + { + Abc_Print( 0, "Required times are exceeded at %d output%s. The earliest arrival times are used.\n", Counter, Counter > 1 ? "s":"" ); + p->fReqTimeWarn = 1; + } + } + else if ( p->vCoAttrs ) { assert( If_ManCoNum(p) == Vec_IntSize(p->vCoAttrs) ); If_ManForEachCo( p, pObj, i ) From b8059c310a6aa32fe70f49e04d640f099d87fee8 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Fri, 27 Mar 2026 19:24:31 -0700 Subject: [PATCH 30/33] Add support for second Verilog files in %ysoys and &cec --- src/base/abci/abc.c | 70 ++++++++++++++++++++++++++++++++++++------- src/base/wln/wlnCom.c | 49 ++++++++++++++++++++++++++---- src/base/wln/wlnRtl.c | 35 +++++++++++++++++++--- 3 files changed, 133 insertions(+), 21 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 1fb12e7f1c..6cc8df18fc 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -42600,7 +42600,7 @@ int Abc_CommandAbc9EquivFilter( Abc_Frame_t * pAbc, int argc, char ** argv ) SeeAlso [] ***********************************************************************/ -static Gia_Man_t * Abc_ReadAigerOrVerilogFile( char * pFileName, char * pTopModule, char * pDefines, int * pAbc_ReadAigerOrVerilogFileStatus ) +static Gia_Man_t * Abc_ReadAigerOrVerilogFile( char * pFileName, char * pFileName2, char * pTopModule, char * pDefines, int * pAbc_ReadAigerOrVerilogFileStatus ) { FILE * pFile; Gia_Man_t * pGia; @@ -42631,14 +42631,20 @@ static Gia_Man_t * Abc_ReadAigerOrVerilogFile( char * pFileName, char * pTopModu fVerilog = fSystemVerilog || Extra_FileIsType( pFileName, ".v", NULL, NULL ); if ( fVerilog ) { + extern Aig_Man_t * Abc_NtkToDar( Abc_Ntk_t * pNtk, int fExors, int fRegisters ); + Aig_Man_t * pAig = NULL; char pCommand[2000]; int RetValue; + int fSystemVerilog2 = pFileName2 && Extra_FileIsType( pFileName2, ".sv", NULL, NULL ); // Save the original filename before changing it pOrigFileName = pFileName; snprintf( pCommand, sizeof(pCommand), - "yosys -qp \"read_verilog %s%s %s%s; hierarchy %s%s; flatten; proc; opt; async2sync; opt; setundef -undriven -zero; techmap; memory -nomap; memory_map; dffunmap; opt_clean; opt_expr; aigmap; write_aiger -symbols _temp_.aig\"", + "yosys -qp \"read_verilog %s%s %s%s%s%s; hierarchy %s%s; flatten; proc; opt; async2sync; opt; setundef -undriven -zero; techmap; memory -nomap; memory_map; dffunmap; opt_clean; opt_expr; %saigmap; write_aiger -symbols _temp_.aig\"", pDefines ? "-D" : "", pDefines ? pDefines : "", - fSystemVerilog ? "-sv " : "", pFileName, pTopModule ? "-top " : "-auto-top", pTopModule ? pTopModule : "" ); + (fSystemVerilog || fSystemVerilog2) ? "-sv " : "", pFileName, + pFileName2 ? " " : "", pFileName2 ? pFileName2 : "", + pTopModule ? "-top " : "-auto-top", pTopModule ? pTopModule : "", + pFileName2 ? "delete t:\\$scopeinfo; " : "" ); #if defined(__wasm) RetValue = 1; #else @@ -42649,10 +42655,32 @@ static Gia_Man_t * Abc_ReadAigerOrVerilogFile( char * pFileName, char * pTopModu Abc_Print( -1, "Yosys command failed: \"%s\".\n", pCommand ); return NULL; } - pFileName = "_temp_.aig"; + if ( pFileName2 ) + { + Abc_Ntk_t * pNtk = Io_Read( "_temp_.aig", IO_FILE_AIGER, 1, 0 ); + if ( pNtk == NULL ) + { + Abc_Print( -1, "Reading AIGER from file \"%s\" has failed.\n", "_temp_.aig" ); + return NULL; + } + pAig = Abc_NtkToDar( pNtk, 0, 1 ); + Abc_NtkDelete( pNtk ); + if ( pAig == NULL ) + { + Abc_Print( -1, "Converting the AIGER network into an internal AIG has failed.\n" ); + return NULL; + } + pGia = Gia_ManFromAig( pAig ); + Aig_ManStop( pAig ); + } + else + { + pFileName = "_temp_.aig"; + pGia = Gia_AigerRead( pFileName, 0, 0, 0 ); + } } - - pGia = Gia_AigerRead( pFileName, 0, 0, 0 ); + else + pGia = Gia_AigerRead( pFileName, 0, 0, 0 ); if ( pGia == NULL ) { Abc_Print( -1, "Reading AIGER from file \"%s\" has failed.\n", pFileName ); @@ -42684,13 +42712,14 @@ int Abc_CommandAbc9Cec( Abc_Frame_t * pAbc, int argc, char ** argv ) { extern void Cec_ManPrintCexSummary( Gia_Man_t * p, Abc_Cex_t * pCex, Cec_ParCec_t * pPars ); Cec_ParCec_t ParsCec, * pPars = &ParsCec; + FILE * pFile; Gia_Man_t * pGias[2] = {NULL, NULL}, * pMiter; - char ** pArgvNew, * pTopModule = NULL, * pDefines = NULL; + char ** pArgvNew, * pTopModule = NULL, * pDefines = NULL, * pFileName2 = NULL; int c, nArgcNew, fUseSim = 0, fUseNewX = 0, fUseNewY = 0, fMiter = 0, fDualOutput = 0, fDumpMiter = 0, fSavedSpec = 0; int Abc_ReadAigerOrVerilogFileStatus = 0; Cec_ManCecSetDefaultParams( pPars ); Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "CTMDnmdbasxytvwh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "CTMDFnmdbasxytvwh" ) ) != EOF ) { switch ( c ) { @@ -42734,6 +42763,15 @@ int Abc_CommandAbc9Cec( Abc_Frame_t * pAbc, int argc, char ** argv ) pDefines = argv[globalUtilOptind]; globalUtilOptind++; break; + case 'F': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-F\" should be followed by a file name.\n" ); + goto usage; + } + pFileName2 = argv[globalUtilOptind]; + globalUtilOptind++; + break; case 'n': pPars->fNaive ^= 1; break; @@ -42778,6 +42816,15 @@ int Abc_CommandAbc9Cec( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_Print( 0, "It looks like the current AIG is derived by &st -m. Such AIG contains XOR gates and cannot be verified before &st is applied.\n" ); return 1; } + if ( pFileName2 ) + { + if ( (pFile = fopen( pFileName2, "r" )) == NULL ) + { + Abc_Print( -1, "Cannot open input file \"%s\".\n", pFileName2 ); + return 1; + } + fclose( pFile ); + } pArgvNew = argv + globalUtilOptind; nArgcNew = argc - globalUtilOptind; if ( fMiter ) @@ -42855,7 +42902,7 @@ int Abc_CommandAbc9Cec( Abc_Frame_t * pAbc, int argc, char ** argv ) int n; for ( n = 0; n < 2; n++ ) { - pGias[n] = Abc_ReadAigerOrVerilogFile( pFileNames[n], pTopModule, pDefines, &Abc_ReadAigerOrVerilogFileStatus ); + pGias[n] = Abc_ReadAigerOrVerilogFile( pFileNames[n], pFileName2, pTopModule, pDefines, &Abc_ReadAigerOrVerilogFileStatus ); if ( pGias[n] == NULL ) return Abc_ReadAigerOrVerilogFileStatus; } @@ -42891,7 +42938,7 @@ int Abc_CommandAbc9Cec( Abc_Frame_t * pAbc, int argc, char ** argv ) } FileName = pAbc->pGia->pSpec; } - pGias[1] = Abc_ReadAigerOrVerilogFile( FileName, pTopModule, pDefines, &Abc_ReadAigerOrVerilogFileStatus ); + pGias[1] = Abc_ReadAigerOrVerilogFile( FileName, pFileName2, pTopModule, pDefines, &Abc_ReadAigerOrVerilogFileStatus ); if ( pGias[1] == NULL ) return Abc_ReadAigerOrVerilogFileStatus; } @@ -43003,12 +43050,13 @@ int Abc_CommandAbc9Cec( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - Abc_Print( -2, "usage: &cec [-CT num] [-M str] [-D str] [-nmdbasxytvwh]\n" ); + Abc_Print( -2, "usage: &cec [-CT num] [-M str] [-D str] [-F str] [-nmdbasxytvwh]\n" ); Abc_Print( -2, "\t new combinational equivalence checker\n" ); Abc_Print( -2, "\t-C num : the max number of conflicts at a node [default = %d]\n", pPars->nBTLimit ); Abc_Print( -2, "\t-T num : approximate runtime limit in seconds [default = %d]\n", pPars->TimeLimit ); Abc_Print( -2, "\t-M str : top module name if Verilog file(s) are used [default = \"not used\"]\n" ); Abc_Print( -2, "\t-D str : defines to be used by Yosys for Verilog files [default = \"not used\"]\n" ); + Abc_Print( -2, "\t-F str : second Verilog/SystemVerilog file read together with each Verilog input [default = \"not used\"]\n" ); Abc_Print( -2, "\t-n : toggle using naive SAT-based checking [default = %s]\n", pPars->fNaive? "yes":"no"); Abc_Print( -2, "\t-m : toggle miter vs. two circuits [default = %s]\n", fMiter? "miter":"two circuits"); Abc_Print( -2, "\t-d : toggle using dual output miter [default = %s]\n", fDualOutput? "yes":"no"); diff --git a/src/base/wln/wlnCom.c b/src/base/wln/wlnCom.c index 1b76fab8fc..2436932cd3 100644 --- a/src/base/wln/wlnCom.c +++ b/src/base/wln/wlnCom.c @@ -93,11 +93,12 @@ void Wln_End( Abc_Frame_t * pAbc ) int Abc_CommandYosys( Abc_Frame_t * pAbc, int argc, char ** argv ) { extern Abc_Ntk_t * Wln_ReadMappedSystemVerilog( char * pFileName, char * pTopModule, char * pDefines, char * pLibrary, int fVerbose ); - extern Gia_Man_t * Wln_BlastSystemVerilog( char * pFileName, char * pTopModule, char * pDefines, int fSkipStrash, int fInvert, int fTechMap, int fLibInDir, int fSetUndef, int fVerbose ); + extern Gia_Man_t * Wln_BlastSystemVerilog( char * pFileName, char * pFileName2, char * pTopModule, char * pDefines, int fSkipStrash, int fInvert, int fTechMap, int fLibInDir, int fSetUndef, int fVerbose ); extern Rtl_Lib_t * Wln_ReadSystemVerilog( char * pFileName, char * pTopModule, char * pDefines, int fCollapse, int fVerbose ); FILE * pFile; char * pFileName = NULL; + char * pFileName2= NULL; char * pTopModule= NULL; char * pDefines = NULL; char * pLibrary = NULL; @@ -111,7 +112,7 @@ int Abc_CommandYosys( Abc_Frame_t * pAbc, int argc, char ** argv ) int fSetUndef = 0; int c, fVerbose = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "TMDLbdisumlcvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "TMDLFbdisumlcvh" ) ) != EOF ) { switch ( c ) { @@ -151,6 +152,15 @@ int Abc_CommandYosys( Abc_Frame_t * pAbc, int argc, char ** argv ) pLibrary = argv[globalUtilOptind]; globalUtilOptind++; break; + case 'F': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-F\" should be followed by a file name.\n" ); + goto usage; + } + pFileName2 = argv[globalUtilOptind]; + globalUtilOptind++; + break; case 'b': fBlast ^= 1; break; @@ -200,10 +210,24 @@ int Abc_CommandYosys( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; } fclose( pFile ); + if ( pFileName2 ) + { + if ( (pFile = fopen( pFileName2, "r" )) == NULL ) + { + Abc_Print( 1, "Cannot open input file \"%s\".\n", pFileName2 ); + return 0; + } + fclose( pFile ); + } // perform reading if ( pLibrary ) { + if ( pFileName2 ) + { + Abc_Print( 1, "Command line switch \"-F\" only applies in the default bit-blasting path.\n" ); + return 0; + } Abc_Ntk_t * pNtk = NULL; if ( !strcmp( Extra_FileNameExtension(pFileName), "v" ) ) pNtk = Wln_ReadMappedSystemVerilog( pFileName, pTopModule, pDefines, pLibrary, fVerbose ); @@ -220,11 +244,18 @@ int Abc_CommandYosys( Abc_Frame_t * pAbc, int argc, char ** argv ) { Gia_Man_t * pNew = NULL; if ( !strcmp( Extra_FileNameExtension(pFileName), "v" ) ) - pNew = Wln_BlastSystemVerilog( pFileName, pTopModule, pDefines, fSkipStrash, fInvert, fTechMap, fLibInDir, fSetUndef, fVerbose ); + pNew = Wln_BlastSystemVerilog( pFileName, pFileName2, pTopModule, pDefines, fSkipStrash, fInvert, fTechMap, fLibInDir, fSetUndef, fVerbose ); else if ( !strcmp( Extra_FileNameExtension(pFileName), "sv" ) ) - pNew = Wln_BlastSystemVerilog( pFileName, pTopModule, pDefines, fSkipStrash, fInvert, fTechMap, fLibInDir, fSetUndef, fVerbose ); + pNew = Wln_BlastSystemVerilog( pFileName, pFileName2, pTopModule, pDefines, fSkipStrash, fInvert, fTechMap, fLibInDir, fSetUndef, fVerbose ); else if ( !strcmp( Extra_FileNameExtension(pFileName), "rtlil" ) ) - pNew = Wln_BlastSystemVerilog( pFileName, pTopModule, pDefines, fSkipStrash, fInvert, fTechMap, fLibInDir, fSetUndef, fVerbose ); + { + if ( pFileName2 ) + { + Abc_Print( 1, "Command line switch \"-F\" is only supported when the main input is Verilog/SystemVerilog.\n" ); + return 0; + } + pNew = Wln_BlastSystemVerilog( pFileName, NULL, pTopModule, pDefines, fSkipStrash, fInvert, fTechMap, fLibInDir, fSetUndef, fVerbose ); + } else { printf( "Abc_CommandYosys(): Unknown file extension.\n" ); @@ -234,6 +265,11 @@ int Abc_CommandYosys( Abc_Frame_t * pAbc, int argc, char ** argv ) } else { + if ( pFileName2 ) + { + Abc_Print( 1, "Command line switch \"-F\" only applies in the default bit-blasting path.\n" ); + return 0; + } Rtl_Lib_t * pLib = NULL; if ( !strcmp( Extra_FileNameExtension(pFileName), "v" ) ) pLib = Wln_ReadSystemVerilog( pFileName, pTopModule, pDefines, fCollapse, fVerbose ); @@ -250,12 +286,13 @@ int Abc_CommandYosys( Abc_Frame_t * pAbc, int argc, char ** argv ) } return 0; usage: - Abc_Print( -2, "usage: %%yosys [-TM ] [-D ] [-L ] [-bdisumlcvh] \n" ); + Abc_Print( -2, "usage: %%yosys [-TM ] [-D ] [-L ] [-F ] [-bdisumlcvh] \n" ); Abc_Print( -2, "\t reads Verilog or SystemVerilog using Yosys\n" ); Abc_Print( -2, "\t-T : specify the top module name (default uses \"-auto-top\")\n" ); Abc_Print( -2, "\t-M : specify the top module name (default uses \"-auto-top\") (equivalent to \"-T\")\n" ); Abc_Print( -2, "\t-D : specify defines to be used by Yosys (default \"not used\")\n" ); Abc_Print( -2, "\t-L : specify the Liberty library to read a mapped design (default \"not used\")\n" ); + Abc_Print( -2, "\t-F : specify a second Verilog/SystemVerilog file for the default bit-blasting flow (default \"not used\")\n" ); Abc_Print( -2, "\t-b : toggle bit-blasting the design into an AIG using Yosys (this switch has no effect)\n" ); Abc_Print( -2, "\t-d : toggle bit-blasting the design into an AIG using Yosys [default = %s]\n", !fDontBlast? "yes": "no" ); Abc_Print( -2, "\t-i : toggle inverting the outputs (useful for miters) [default = %s]\n", fInvert? "yes": "no" ); diff --git a/src/base/wln/wlnRtl.c b/src/base/wln/wlnRtl.c index 5b9f05c45c..ffe8e457d7 100644 --- a/src/base/wln/wlnRtl.c +++ b/src/base/wln/wlnRtl.c @@ -19,6 +19,9 @@ ***********************************************************************/ #include "wln.h" +#include "aig/aig/aig.h" +#include "aig/gia/giaAig.h" +#include "base/io/ioAbc.h" #include "base/main/main.h" #ifdef WIN32 @@ -171,30 +174,54 @@ Rtl_Lib_t * Wln_ReadSystemVerilog( char * pFileName, char * pTopModule, char * p unlink( pFileTemp ); return pNtk; } -Gia_Man_t * Wln_BlastSystemVerilog( char * pFileName, char * pTopModule, char * pDefines, int fSkipStrash, int fInvert, int fTechMap, int fLibInDir, int fSetUndef, int fVerbose ) +Gia_Man_t * Wln_BlastSystemVerilog( char * pFileName, char * pFileName2, char * pTopModule, char * pDefines, int fSkipStrash, int fInvert, int fTechMap, int fLibInDir, int fSetUndef, int fVerbose ) { Gia_Man_t * pGia = NULL; char Command[1000]; char * pFileTemp = "_temp_.aig"; int fRtlil = strstr(pFileName, ".rtl") != NULL; - int fSVlog = strstr(pFileName, ".sv") != NULL; - sprintf( Command, "%s -qp \"%s %s%s %s%s; hierarchy %s%s; flatten; proc; opt; async2sync; opt; setundef -undriven -zero; %s%smemory -nomap; memory_map; dffunmap; opt_clean; opt_expr; aigmap; write_aiger -symbols %s\"", + int fSVlog = strstr(pFileName, ".sv") != NULL || (pFileName2 && strstr(pFileName2, ".sv") != NULL); + sprintf( Command, "%s -qp \"%s %s%s %s%s%s%s; hierarchy %s%s; flatten; proc; opt; async2sync; opt; setundef -undriven -zero; %s%smemory -nomap; memory_map; dffunmap; opt_clean; opt_expr; %saigmap; write_aiger -symbols %s\"", Wln_GetYosysName(), fRtlil ? "read_rtlil" : "read_verilog", pDefines ? "-D" : "", pDefines ? pDefines : "", fSVlog ? "-sv " : "", pFileName, + pFileName2 ? " " : "", + pFileName2 ? pFileName2 : "", pTopModule ? "-top " : "-auto-top", pTopModule ? pTopModule : "", fTechMap ? (fLibInDir ? "techmap -map techmap.v; " : "techmap; ") : "", fSetUndef ? "setundef -init -zero; " : "", + pFileName2 ? "delete t:\\$scopeinfo; " : "", pFileTemp ); if ( fVerbose ) printf( "%s\n", Command ); if ( !Wln_ConvertToRtl(Command, pFileTemp) ) return NULL; - pGia = Gia_AigerRead( pFileTemp, 0, fSkipStrash, 0 ); + if ( pFileName2 ) + { + extern Aig_Man_t * Abc_NtkToDar( Abc_Ntk_t * pNtk, int fExors, int fRegisters ); + Aig_Man_t * pAig = NULL; + Abc_Ntk_t * pNtk = Io_Read( pFileTemp, IO_FILE_AIGER, 1, 0 ); + if ( pNtk == NULL ) + { + printf( "Reading AIGER from file \"%s\" has failed.\n", pFileTemp ); + return NULL; + } + pAig = Abc_NtkToDar( pNtk, 0, 1 ); + Abc_NtkDelete( pNtk ); + if ( pAig == NULL ) + { + printf( "Converting the AIGER network into an internal AIG has failed.\n" ); + return NULL; + } + pGia = fSkipStrash ? Gia_ManFromAigSimple(pAig) : Gia_ManFromAig(pAig); + Aig_ManStop( pAig ); + } + else + pGia = Gia_AigerRead( pFileTemp, 0, fSkipStrash, 0 ); if ( pGia == NULL ) { printf( "Converting to AIG has failed.\n" ); From bef23270f8ad9c8d2c14f6e6adc4a15fc2ba047f Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Fri, 27 Mar 2026 20:09:54 -0700 Subject: [PATCH 31/33] Improvements to command "history". --- src/base/cmd/cmd.c | 44 ++++++++++++++++++----------------- src/base/cmd/cmdUtils.c | 50 ++++++++++++++++++++++++++++++++++++---- src/base/main/mainReal.c | 7 ++++++ 3 files changed, 75 insertions(+), 26 deletions(-) diff --git a/src/base/cmd/cmd.c b/src/base/cmd/cmd.c index bbe3b7d8e8..aae2f47d8d 100644 --- a/src/base/cmd/cmd.c +++ b/src/base/cmd/cmd.c @@ -98,6 +98,7 @@ void Cmd_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "Basic", "quit", CmdCommandQuit, 0 ); Cmd_CommandAdd( pAbc, "Basic", "abcrc", CmdCommandAbcrc, 0 ); Cmd_CommandAdd( pAbc, "Basic", "history", CmdCommandHistory, 0 ); + Cmd_CommandAdd( pAbc, "Basic", "hi", CmdCommandHistory, 0 ); Cmd_CommandAdd( pAbc, "Basic", "alias", CmdCommandAlias, 0 ); Cmd_CommandAdd( pAbc, "Basic", "unalias", CmdCommandUnalias, 0 ); Cmd_CommandAdd( pAbc, "Basic", "help", CmdCommandHelp, 0 ); @@ -441,38 +442,31 @@ int CmdCommandAbcrc( Abc_Frame_t * pAbc, int argc, char **argv ) int CmdCommandHistory( Abc_Frame_t * pAbc, int argc, char **argv ) { char * pName, * pStr = NULL; - int i, c; + char ** ppMatches = NULL; + int * pIds = NULL; + int i; int nPrints = 20; int nPrinted = 0; - Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "h" ) ) != EOF ) - { - switch ( c ) - { - case 'h': - goto usage; - default : - goto usage; - } - } - if ( argc > globalUtilOptind + 2 ) + if ( argc == 2 && !strcmp(argv[1], "-h") ) + goto usage; + if ( argc > 3 ) goto usage; // parse arguments: can be [substring] [number] in either order - if ( argc == globalUtilOptind + 1 ) + if ( argc == 2 ) { // one argument: either number or substring - pStr = argv[globalUtilOptind]; + pStr = argv[1]; if ( pStr && pStr[0] >= '1' && pStr[0] <= '9' ) { nPrints = atoi(pStr); pStr = NULL; } } - else if ( argc == globalUtilOptind + 2 ) + else if ( argc == 3 ) { // two arguments: substring and number - char * arg1 = argv[globalUtilOptind]; - char * arg2 = argv[globalUtilOptind + 1]; + char * arg1 = argv[1]; + char * arg2 = argv[2]; // Try to parse second argument as number if ( arg2[0] >= '1' && arg2[0] <= '9' ) @@ -500,14 +494,22 @@ int CmdCommandHistory( Abc_Frame_t * pAbc, int argc, char **argv ) fprintf( pAbc->Out, "%4d : %s\n", Vec_PtrSize(pAbc->aHistory)-i, pName ); } else { - // Search string provided, show up to nPrints matching entries - Vec_PtrForEachEntry( char *, pAbc->aHistory, pName, i ) + // Search string provided, select up to nPrints most recent matching entries + ppMatches = ABC_ALLOC( char *, nPrints ); + pIds = ABC_ALLOC( int, nPrints ); + Vec_PtrForEachEntryReverse( char *, pAbc->aHistory, pName, i ) if ( strstr(pName, pStr) ) { - fprintf( pAbc->Out, "%4d : %s\n", Vec_PtrSize(pAbc->aHistory)-i, pName ); + pIds[nPrinted] = Vec_PtrSize(pAbc->aHistory)-i; + ppMatches[nPrinted] = pName; if ( ++nPrinted >= nPrints ) break; } + // Print the selected entries in reverse so larger history indices appear first + for ( i = nPrinted - 1; i >= 0; i-- ) + fprintf( pAbc->Out, "%4d : %s\n", pIds[i], ppMatches[i] ); + ABC_FREE( pIds ); + ABC_FREE( ppMatches ); } return 0; diff --git a/src/base/cmd/cmdUtils.c b/src/base/cmd/cmdUtils.c index e8e28078f8..f0d8fc2dd5 100644 --- a/src/base/cmd/cmdUtils.c +++ b/src/base/cmd/cmdUtils.c @@ -25,7 +25,6 @@ #include ABC_NAMESPACE_IMPL_START - // proper declaration of isspace //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// @@ -393,9 +392,51 @@ int CmdApplyAlias( Abc_Frame_t * pAbc, int *argcp, char ***argvp, int *loop ) ***********************************************************************/ char * CmdHistorySubstitution( Abc_Frame_t * pAbc, char *line, int *changed ) { - // as of today, no history substitution - *changed = 0; - return line; + char * pBeg = line, * pEnd, * pStr; + int iRecall, nSize; + while ( *pBeg && isspace((unsigned char)*pBeg) ) + pBeg++; + if ( *pBeg == 0 ) + { + *changed = 0; + return line; + } + pEnd = pBeg; + while ( *pEnd && !isspace((unsigned char)*pEnd) ) + pEnd++; + if ( *pEnd ) + { + char * pTemp = pEnd; + while ( *pTemp && isspace((unsigned char)*pTemp) ) + pTemp++; + if ( *pTemp ) + { + *changed = 0; + return line; + } + } + if ( *pBeg < '1' || *pBeg > '9' ) + { + *changed = 0; + return line; + } + for ( pStr = pBeg; pStr < pEnd; pStr++ ) + if ( *pStr < '0' || *pStr > '9' ) + { + *changed = 0; + return line; + } + iRecall = atoi( pBeg ); + nSize = Vec_PtrSize( pAbc->aHistory ); + if ( iRecall < 1 || iRecall > nSize ) + { + fprintf( pAbc->Err, "History entry %d does not exist.\n", iRecall ); + line[0] = 0; + *changed = 0; + return line; + } + *changed = 1; + return (char *)Vec_PtrEntry( pAbc->aHistory, nSize - iRecall ); } /**Function************************************************************* @@ -905,4 +946,3 @@ void Cmd_CommandSGen( Abc_Frame_t * pAbc, int nParts, int nIters, int fVerbose ) /// END OF FILE /// //////////////////////////////////////////////////////////////////////// ABC_NAMESPACE_IMPL_END - diff --git a/src/base/main/mainReal.c b/src/base/main/mainReal.c index 3c5d67b3fe..9589d5239e 100644 --- a/src/base/main/mainReal.c +++ b/src/base/main/mainReal.c @@ -56,6 +56,7 @@ SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. #endif #include "base/abc/abc.h" +#include "base/cmd/cmdInt.h" #include "mainInt.h" #include "base/wlc/wlc.h" @@ -363,9 +364,15 @@ int Abc_RealMain( int argc, char * argv[] ) // execute commands given by the user while ( !feof(stdin) ) { + int did_subst; // print command line prompt and // get the command from the user sCommand = Abc_UtilsGetUsersInput( pAbc ); + sCommand = CmdHistorySubstitution( pAbc, sCommand, &did_subst ); + if ( sCommand == NULL ) + break; + if ( did_subst ) + fprintf( pAbc->Out, "%s\n", sCommand ); // execute the user's command fStatus = Cmd_CommandExecute( pAbc, sCommand ); From 2fb9b8438e02a460d7c4e88b9da889f81fd1b3ea Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 9 Aug 2025 01:24:17 -0400 Subject: [PATCH 32/33] Add Windows fixes so abc compiles natively with GCC. --- Makefile | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index eeff20d24d..dbf7198c4d 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,11 @@ $(call abc_info,$(MSG_PREFIX)Using AR=$(AR)) $(call abc_info,$(MSG_PREFIX)Using LD=$(LD)) PROG := abc + OS := $(shell uname -s) +ifneq ($(filter MINGW%,$(OS)),) +OS := MINGW +endif MODULES := \ $(wildcard src/ext*) \ @@ -151,10 +155,15 @@ ifneq ($(OS), $(filter $(OS), FreeBSD OpenBSD NetBSD)) LIBS += -ldl endif -ifneq ($(OS), $(filter $(OS), FreeBSD OpenBSD NetBSD Darwin)) +ifneq ($(OS), $(filter $(OS), FreeBSD OpenBSD NetBSD Darwin MINGW)) LIBS += -lrt endif +# For PathMatchSpecA. +ifeq ($(OS), MINGW) + LIBS += -lshlwapi +endif + ifdef ABC_USE_LIBSTDCXX LIBS += -lstdc++ $(call abc_info,$(MSG_PREFIX)Using explicit -lstdc++) @@ -164,7 +173,7 @@ $(call abc_info,$(MSG_PREFIX)Using CFLAGS=$(CFLAGS)) CXXFLAGS += $(CFLAGS) -std=c++17 -fno-exceptions SRC := -GARBAGE := core core.* *.stackdump ./tags $(PROG) arch_flags +GARBAGE := core core.* *.stackdump ./tags $(PROG) arch_flags $(PROG).in .PHONY: all default tags clean docs cmake_info @@ -231,9 +240,17 @@ clean: tags: etags `find . -type f -regex '.*\.\(c\|h\)'` +ifeq ($(OS), MINGW) +$(PROG): $(OBJ) + @echo "$(MSG_PREFIX)\`\` Constructing Response File:" $(notdir @$@.in) + $(file >$@.in,$^ $(LDFLAGS) $(LIBS)) + @echo "$(MSG_PREFIX)\`\` Building binary:" $(notdir $@) + $(VERBOSE)$(LD) -o $@ @$@.in +else $(PROG): $(OBJ) @echo "$(MSG_PREFIX)\`\` Building binary:" $(notdir $@) $(VERBOSE)$(LD) -o $@ $^ $(LDFLAGS) $(LIBS) +endif lib$(PROG).a: $(LIBOBJ) @echo "$(MSG_PREFIX)\`\` Linking:" $(notdir $@) From 59d061744b07fe3881a6906bc417f5b9f7ca744b Mon Sep 17 00:00:00 2001 From: Rob Taylor Date: Fri, 3 Apr 2026 00:03:19 +0100 Subject: [PATCH 33/33] CI: add MinGW/MSYS2 build workflow Add a new build-mingw.yml workflow that builds ABC using MinGW64/MSYS2 on windows-latest. This provides CI coverage for the MinGW build path added in the previous commit, using ABC_USE_STDINT_H=1 and -DWIN32 -DWIN32_NO_DLL to handle MinGW platform quirks. Co-developed-by: Claude Code v2.1.90 (claude-sonnet-4-6) --- .github/workflows/build-mingw.yml | 50 +++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .github/workflows/build-mingw.yml diff --git a/.github/workflows/build-mingw.yml b/.github/workflows/build-mingw.yml new file mode 100644 index 0000000000..f450380644 --- /dev/null +++ b/.github/workflows/build-mingw.yml @@ -0,0 +1,50 @@ +name: Build MinGW + +on: + push: + pull_request: + +jobs: + + build-mingw: + + runs-on: windows-latest + + defaults: + run: + shell: msys2 {0} + + steps: + + - name: Setup MSYS2 + uses: msys2/setup-msys2@v2 + with: + msystem: MINGW64 + update: false + install: >- + mingw-w64-x86_64-gcc + make + + - name: Git Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Build + run: | + ABC_USE_STDINT_H=1 make -j$(nproc) CFLAGS="-DWIN32 -DWIN32_NO_DLL" abc + + - name: Test Executable + run: | + ./abc.exe -c "r i10.aig; b; ps; b; rw -l; rw -lz; b; rw -lz; b; ps; cec" + + - name: Stage Executable + run: | + mkdir -p staging + cp abc.exe staging/ + + - name: Upload package artifact + uses: actions/upload-artifact@v4 + with: + name: package-mingw + path: staging/