Skip to content

Commit 3cdb1c4

Browse files
committed
Dumping LUT-mapped networks in Vivado-readable Verilog.
1 parent 8475386 commit 3cdb1c4

File tree

2 files changed

+238
-4
lines changed

2 files changed

+238
-4
lines changed

src/base/abc/abcHieGia.c

Lines changed: 214 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1292,12 +1292,201 @@ static void GiaHie_DumpInterfaceAssigns( Gia_Man_t * p, char * pFileName )
12921292
fclose( pFile );
12931293
}
12941294

1295+
/**Function*************************************************************
1296+
1297+
Synopsis [Dumps mapped AIG as LUT6 instances in Verilog]
1298+
1299+
Description []
1300+
1301+
SideEffects []
1302+
1303+
SeeAlso []
1304+
1305+
***********************************************************************/
1306+
static void GiaHie_DumpMappedLuts( Gia_Man_t * p, char * pFileName )
1307+
{
1308+
int i, k, iFanin, nLutSize, nDigits;
1309+
FILE * pFile;
1310+
Vec_Int_t * vLeaves;
1311+
word * pTruth;
1312+
Gia_Obj_t * pObj;
1313+
1314+
// Check if AIG is mapped
1315+
if ( !Gia_ManHasMapping(p) )
1316+
{
1317+
printf( "Cannot write LUT-based Verilog because AIG is not mapped.\n" );
1318+
return;
1319+
}
1320+
1321+
pFile = fopen( pFileName, "wb" );
1322+
if ( pFile == NULL )
1323+
{
1324+
printf( "Cannot open output file \"%s\".\n", pFileName );
1325+
return;
1326+
}
1327+
1328+
nDigits = Abc_Base10Log( Gia_ManObjNum(p) );
1329+
if ( nDigits < 3 )
1330+
nDigits = 3;
1331+
1332+
// Write header
1333+
fprintf( pFile, "`timescale 1ns/1ps\n\n" );
1334+
1335+
// Write LUT module definitions for Yosys compatibility (compact version)
1336+
fprintf( pFile, "module LUT2 #( parameter INIT = 04\'h0 ) ( output O, input I0, I1 );\n" );
1337+
fprintf( pFile, " assign O = INIT[ {I1, I0} ];\n" );
1338+
fprintf( pFile, "endmodule\n" );
1339+
1340+
fprintf( pFile, "module LUT3 #( parameter INIT = 08\'h0 ) ( output O, input I0, I1, I2 );\n" );
1341+
fprintf( pFile, " assign O = INIT[ {I2, I1, I0} ];\n" );
1342+
fprintf( pFile, "endmodule\n" );
1343+
1344+
fprintf( pFile, "module LUT4 #( parameter INIT = 16\'h0 ) ( output O, input I0, I1, I2, I3 );\n" );
1345+
fprintf( pFile, " assign O = INIT[ {I3, I2, I1, I0} ];\n" );
1346+
fprintf( pFile, "endmodule\n" );
1347+
1348+
fprintf( pFile, "module LUT5 #( parameter INIT = 32\'h0 ) ( output O, input I0, I1, I2, I3, I4 );\n" );
1349+
fprintf( pFile, " assign O = INIT[ {I4, I3, I2, I1, I0} ];\n" );
1350+
fprintf( pFile, "endmodule\n" );
1351+
1352+
fprintf( pFile, "module LUT6 #( parameter INIT = 64\'h0 ) ( output O, input I0, I1, I2, I3, I4, I5 );\n" );
1353+
fprintf( pFile, " assign O = INIT[ {I5, I4, I3, I2, I1, I0} ];\n" );
1354+
fprintf( pFile, "endmodule\n\n" );
1355+
1356+
// Write main module
1357+
fprintf( pFile, "module " );
1358+
GiaHie_DumpModuleName( pFile, p->pName );
1359+
fprintf( pFile, " (\n" );
1360+
GiaHie_DumpPortDecls( p, pFile );
1361+
fprintf( pFile, "\n);\n\n" );
1362+
1363+
// Declare wires for inputs (using object IDs like regular &write_ver)
1364+
if ( Gia_ManCiNum(p) )
1365+
{
1366+
fprintf( pFile, " wire " );
1367+
GiaHie_WriteObjRange( pFile, p, 0, Gia_ManCiNum(p), nDigits, 7, 4, 0, 1 );
1368+
fprintf( pFile, ";\n\n" );
1369+
GiaHie_DumpInputAssigns( p, pFile, nDigits );
1370+
fprintf( pFile, "\n" );
1371+
}
1372+
1373+
// Declare wires for outputs (using object IDs like regular &write_ver)
1374+
if ( Gia_ManCoNum(p) )
1375+
{
1376+
fprintf( pFile, " wire " );
1377+
GiaHie_WriteObjRange( pFile, p, 0, Gia_ManCoNum(p), nDigits, 7, 4, 0, 0 );
1378+
fprintf( pFile, ";\n\n" );
1379+
GiaHie_DumpOutputAssigns( p, pFile, nDigits );
1380+
fprintf( pFile, "\n" );
1381+
}
1382+
1383+
// Declare internal wires for LUT outputs (10 per line)
1384+
{
1385+
int nWiresPerLine = 10;
1386+
int nWireCount = 0;
1387+
int fFirst = 1;
1388+
Gia_ManForEachLut( p, i )
1389+
{
1390+
if ( nWireCount == 0 )
1391+
fprintf( pFile, " wire " );
1392+
if ( !fFirst )
1393+
fprintf( pFile, ", " );
1394+
fprintf( pFile, "n%0*d", nDigits, i );
1395+
fFirst = 0;
1396+
nWireCount++;
1397+
if ( nWireCount == nWiresPerLine )
1398+
{
1399+
fprintf( pFile, ";\n" );
1400+
nWireCount = 0;
1401+
fFirst = 1;
1402+
}
1403+
}
1404+
if ( nWireCount > 0 )
1405+
fprintf( pFile, ";\n" );
1406+
}
1407+
fprintf( pFile, "\n" );
1408+
1409+
// Initialize truth table computation
1410+
vLeaves = Vec_IntAlloc( 6 );
1411+
Gia_ObjComputeTruthTableStart( p, 6 );
1412+
1413+
// Write LUT6 instances
1414+
Gia_ManForEachLut( p, i )
1415+
{
1416+
nLutSize = Gia_ObjLutSize( p, i );
1417+
1418+
// Collect LUT inputs
1419+
Vec_IntClear( vLeaves );
1420+
Gia_LutForEachFanin( p, i, iFanin, k )
1421+
Vec_IntPush( vLeaves, iFanin );
1422+
1423+
// Compute truth table
1424+
pTruth = Gia_ObjComputeTruthTableCut( p, Gia_ManObj(p, i), vLeaves );
1425+
1426+
// Write LUT instance - use appropriate size LUT based on inputs
1427+
if ( nLutSize <= 1 )
1428+
nLutSize = 2; // minimum LUT size is 2
1429+
1430+
// Determine INIT width and padding
1431+
int nInitBits = (1 << nLutSize);
1432+
unsigned long long truthValue = (nLutSize <= 6) ? pTruth[0] : 0;
1433+
1434+
// Mask truth value to the appropriate number of bits
1435+
if ( nLutSize < 6 )
1436+
truthValue &= ((1ULL << nInitBits) - 1);
1437+
1438+
// Write LUT instance with padding for alignment
1439+
fprintf( pFile, " (* DONT_TOUCH = \"yes\" *) LUT%d #(", nLutSize );
1440+
1441+
// Write INIT parameter with appropriate width and padding aligned to 64-bit width
1442+
if ( nLutSize == 2 )
1443+
fprintf( pFile, ".INIT(04'h%01llx )) u_lut%0*d (", truthValue, nDigits, i );
1444+
else if ( nLutSize == 3 )
1445+
fprintf( pFile, ".INIT(08'h%02llx )) u_lut%0*d (", truthValue, nDigits, i );
1446+
else if ( nLutSize == 4 )
1447+
fprintf( pFile, ".INIT(16'h%04llx )) u_lut%0*d (", truthValue, nDigits, i );
1448+
else if ( nLutSize == 5 )
1449+
fprintf( pFile, ".INIT(32'h%08llx )) u_lut%0*d (", truthValue, nDigits, i );
1450+
else // nLutSize == 6
1451+
fprintf( pFile, ".INIT(64'h%016llx)) u_lut%0*d (", truthValue, nDigits, i );
1452+
1453+
// Write LUT inputs - only the ones actually used by this LUT size
1454+
for ( k = 0; k < nLutSize; k++ )
1455+
{
1456+
iFanin = Vec_IntEntry( vLeaves, k );
1457+
if ( k > 0 )
1458+
fprintf( pFile, ", " );
1459+
fprintf( pFile, ".I%d(n%0*d)", k, nDigits, iFanin );
1460+
}
1461+
1462+
// Write LUT output
1463+
fprintf( pFile, ", .O(n%0*d));\n", nDigits, i );
1464+
}
1465+
1466+
// Cleanup truth table computation
1467+
Gia_ObjComputeTruthTableStop( p );
1468+
Vec_IntFree( vLeaves );
1469+
1470+
fprintf( pFile, "\n" );
1471+
1472+
// Connect internal nodes to outputs (like regular &write_ver)
1473+
Gia_ManForEachCo( p, pObj, i )
1474+
{
1475+
fprintf( pFile, " assign n%0*d = ", nDigits, Gia_ManCoIdToId(p, i) );
1476+
GiaHie_PrintObjLit( pFile, Gia_ObjFaninId0p(p, pObj), Gia_ObjFaninC0(pObj), nDigits );
1477+
fprintf( pFile, ";\n" );
1478+
}
1479+
1480+
fprintf( pFile, "\nendmodule\n" );
1481+
fclose( pFile );
1482+
}
1483+
12951484
/**Function*************************************************************
12961485
12971486
Synopsis []
12981487
12991488
Description []
1300-
1489+
13011490
SideEffects []
13021491
13031492
SeeAlso []
@@ -1314,6 +1503,30 @@ void Gia_WriteVerilog( char * pFileName, Gia_Man_t * pGia, int fUseGates, int fV
13141503
GiaHie_DumpInterfaceAssigns( pGia, pFileName );
13151504
}
13161505

1506+
/**Function*************************************************************
1507+
1508+
Synopsis [Writes mapped AIG as LUT6-based Verilog]
1509+
1510+
Description []
1511+
1512+
SideEffects []
1513+
1514+
SeeAlso []
1515+
1516+
***********************************************************************/
1517+
void Gia_WriteMappedVerilog( char * pFileName, Gia_Man_t * pGia, int fVerbose )
1518+
{
1519+
(void)fVerbose;
1520+
if ( pFileName == NULL || pGia == NULL )
1521+
return;
1522+
if ( !Gia_ManHasMapping(pGia) )
1523+
{
1524+
printf( "Cannot write LUT-based Verilog because AIG is not mapped.\n" );
1525+
return;
1526+
}
1527+
GiaHie_DumpMappedLuts( pGia, pFileName );
1528+
}
1529+
13171530
////////////////////////////////////////////////////////////////////////
13181531
/// END OF FILE ///
13191532
////////////////////////////////////////////////////////////////////////

src/base/abci/abc.c

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35109,15 +35109,17 @@ int Abc_CommandAbc9LoadAig( Abc_Frame_t * pAbc, int argc, char ** argv )
3510935109
int Abc_CommandAbc9WriteVer( Abc_Frame_t * pAbc, int argc, char ** argv )
3511035110
{
3511135111
extern void Gia_WriteVerilog( char * pFileName, Gia_Man_t * pGia, int fUseGates, int fVerbose );
35112+
extern void Gia_WriteMappedVerilog( char * pFileName, Gia_Man_t * pGia, int fVerbose );
3511235113
char * pFileSpec = NULL;
3511335114
Abc_Ntk_t * pNtkSpec = NULL;
3511435115
char * pFileName;
3511535116
char ** pArgvNew;
3511635117
int c, nArgcNew;
3511735118
int fUseGates = 0;
35119+
int fUseLuts = 0;
3511835120
int fVerbose = 0;
3511935121
Extra_UtilGetoptReset();
35120-
while ( ( c = Extra_UtilGetopt( argc, argv, "Sgvh" ) ) != EOF )
35122+
while ( ( c = Extra_UtilGetopt( argc, argv, "Sglvh" ) ) != EOF )
3512135123
{
3512235124
switch ( c )
3512335125
{
@@ -35133,6 +35135,9 @@ int Abc_CommandAbc9WriteVer( Abc_Frame_t * pAbc, int argc, char ** argv )
3513335135
case 'g':
3513435136
fUseGates ^= 1;
3513535137
break;
35138+
case 'l':
35139+
fUseLuts ^= 1;
35140+
break;
3513635141
case 'v':
3513735142
fVerbose ^= 1;
3513835143
break;
@@ -35157,7 +35162,21 @@ int Abc_CommandAbc9WriteVer( Abc_Frame_t * pAbc, int argc, char ** argv )
3515735162
Abc_Print( -1, "There is no AIG to write.\n" );
3515835163
return 1;
3515935164
}
35160-
Gia_WriteVerilog( pFileName, pAbc->pGia, fUseGates, fVerbose );
35165+
// Check if we should write LUT-based Verilog
35166+
if ( fUseLuts || (Gia_ManHasMapping(pAbc->pGia) && !fUseGates) )
35167+
{
35168+
if ( !Gia_ManHasMapping(pAbc->pGia) )
35169+
{
35170+
Abc_Print( -1, "Cannot write LUT-based Verilog because AIG is not mapped.\n" );
35171+
Abc_Print( -1, "Use \"&if\" to map the AIG first, or omit the -l flag.\n" );
35172+
return 1;
35173+
}
35174+
Gia_WriteMappedVerilog( pFileName, pAbc->pGia, fVerbose );
35175+
}
35176+
else
35177+
{
35178+
Gia_WriteVerilog( pFileName, pAbc->pGia, fUseGates, fVerbose );
35179+
}
3516135180
}
3516235181
else
3516335182
{
@@ -35179,13 +35198,15 @@ int Abc_CommandAbc9WriteVer( Abc_Frame_t * pAbc, int argc, char ** argv )
3517935198
return 0;
3518035199

3518135200
usage:
35182-
Abc_Print( -2, "usage: &write_ver [-S <file>] [-gvh] <file>\n" );
35201+
Abc_Print( -2, "usage: &write_ver [-S <file>] [-glvh] <file>\n" );
3518335202
Abc_Print( -2, "\t writes hierarchical Verilog\n" );
3518435203
Abc_Print( -2, "\t-S file : file name for the original design (required when hierarchy is present)\n" );
3518535204
Abc_Print( -2, "\t-g : toggle output gates vs assign-statements [default = %s]\n", fUseGates? "gates": "assigns" );
35205+
Abc_Print( -2, "\t-l : write LUT6-based Verilog for mapped AIGs [default = %s]\n", fUseLuts? "yes": "no" );
3518635206
Abc_Print( -2, "\t-v : toggle verbose output [default = %s]\n", fVerbose? "yes": "no" );
3518735207
Abc_Print( -2, "\t-h : print the command usage\n");
3518835208
Abc_Print( -2, "\t<file> : the file name\n");
35209+
Abc_Print( -2, "\tNote: When AIG is mapped and -l is not specified, LUT-based output is automatically used.\n");
3518935210
return 1;
3519035211
}
3519135212

0 commit comments

Comments
 (0)