-- Ortho specifications. -- Copyright (C) 2002, 2003, 2004, 2005 Tristan Gingold -- -- GHDL is free software; you can redistribute it and/or modify it under -- the terms of the GNU General Public License as published by the Free -- Software Foundation; either version 2, or (at your option) any later -- version. -- -- GHDL is distributed in the hope that it will be useful, but WITHOUT ANY -- WARRANTY; without even the implied warranty of MERCHANTABILITY or -- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- for more details. -- -- You should have received a copy of the GNU General Public License -- along with GCC; see the file COPYING. If not, write to the Free -- Software Foundation, 59 Temple Place - Suite 330, Boston, MA -- 02111-1307, USA. with Interfaces; use Interfaces; with Ortho_Ident; use Ortho_Ident; -- Interface to create nodes. package ORTHO_NODES is type O_Enode is private; type O_Cnode is private; type O_Lnode is private; type O_Tnode is private; type O_Snode is private; type O_Dnode is private; type O_Gnode is private; type O_Fnode is private; O_Cnode_Null : constant O_Cnode; O_Dnode_Null : constant O_Dnode; O_Gnode_Null : constant O_Gnode; O_Enode_Null : constant O_Enode; O_Fnode_Null : constant O_Fnode; O_Lnode_Null : constant O_Lnode; O_Snode_Null : constant O_Snode; O_Tnode_Null : constant O_Tnode; -- True if the code generated supports nested subprograms. Has_Nested_Subprograms : constant Boolean; ------------------------ -- Type definitions -- ------------------------ type O_Element_List is limited private; -- Build a record type. procedure Start_Record_Type (Elements : out O_Element_List); -- Add a field in the record; not constrained array are prohibited, since -- its size is unlimited. procedure New_Record_Field (Elements : in out O_Element_List; El : out O_Fnode; Ident : O_Ident; Etype : O_Tnode); -- Finish the record type. procedure Finish_Record_Type (Elements : in out O_Element_List; Res : out O_Tnode); -- Build an uncomplete record type: -- First call NEW_UNCOMPLETE_RECORD_TYPE, which returns a record type. -- This type can be declared or used to define access types on it. -- Then, complete (if necessary) the record type, by calling -- START_UNCOMPLETE_RECORD_TYPE, NEW_RECORD_FIELD and FINISH_RECORD_TYPE. procedure New_Uncomplete_Record_Type (Res : out O_Tnode); procedure Start_Uncomplete_Record_Type (Res : O_Tnode; Elements : out O_Element_List); -- Build an union type. procedure Start_Union_Type (Elements : out O_Element_List); procedure New_Union_Field (Elements : in out O_Element_List; El : out O_Fnode; Ident : O_Ident; Etype : O_Tnode); procedure Finish_Union_Type (Elements : in out O_Element_List; Res : out O_Tnode); -- Build an access type. -- DTYPE may be O_tnode_null in order to build an incomplete access type. -- It is completed with finish_access_type. function New_Access_Type (Dtype : O_Tnode) return O_Tnode; procedure Finish_Access_Type (Atype : O_Tnode; Dtype : O_Tnode); -- Build an array type. -- The array is not constrained and unidimensional. function New_Array_Type (El_Type : O_Tnode; Index_Type : O_Tnode) return O_Tnode; -- Build a constrained array type. function New_Constrained_Array_Type (Atype : O_Tnode; Length : O_Cnode) return O_Tnode; -- Build a scalar type; size may be 8, 16, 32 or 64. function New_Unsigned_Type (Size : Natural) return O_Tnode; function New_Signed_Type (Size : Natural) return O_Tnode; -- Build a float type. function New_Float_Type return O_Tnode; -- Build a boolean type. procedure New_Boolean_Type (Res : out O_Tnode; False_Id : O_Ident; False_E : out O_Cnode; True_Id : O_Ident; True_E : out O_Cnode); -- Create an enumeration type O_Enum_List is limited private; -- Elements are declared in order, the first is ordered from 0. procedure Start_Enum_Type (List : out O_Enum_List; Size : Natural); procedure New_Enum_Literal (List : in out O_Enum_List; Ident : O_Ident; Res : out O_Cnode); procedure Finish_Enum_Type (List : in out O_Enum_List; Res : out O_Tnode); ---------------- -- Literals -- ---------------- -- Create a literal from an integer. function New_Signed_Literal (Ltype : O_Tnode; Value : Integer_64) return O_Cnode; function New_Unsigned_Literal (Ltype : O_Tnode; Value : Unsigned_64) return O_Cnode; function New_Float_Literal (Ltype : O_Tnode; Value : IEEE_Float_64) return O_Cnode; -- Create a null access literal. function New_Null_Access (Ltype : O_Tnode) return O_Cnode; -- Create a literal with default (null) values. Can only be used to -- define the initial value of a static decalaration. function New_Default_Value (Ltype : O_Tnode) return O_Cnode; -- Build a record/array aggregate. -- The aggregate is constant, and therefore can be only used to initialize -- constant declaration. -- ATYPE must be either a record type or an array subtype. -- Elements must be added in the order, and must be literals or aggregates. type O_Record_Aggr_List is limited private; type O_Array_Aggr_List is limited private; procedure Start_Record_Aggr (List : out O_Record_Aggr_List; Atype : O_Tnode); procedure New_Record_Aggr_El (List : in out O_Record_Aggr_List; Value : O_Cnode); procedure Finish_Record_Aggr (List : in out O_Record_Aggr_List; Res : out O_Cnode); procedure Start_Array_Aggr (List : out O_Array_Aggr_List; Atype : O_Tnode; Len : Unsigned_32); procedure New_Array_Aggr_El (List : in out O_Array_Aggr_List; Value : O_Cnode); procedure Finish_Array_Aggr (List : in out O_Array_Aggr_List; Res : out O_Cnode); -- Build an union aggregate. function New_Union_Aggr (Atype : O_Tnode; Field : O_Fnode; Value : O_Cnode) return O_Cnode; -- Returns the size in bytes of ATYPE. The result is a literal of -- unsigned type RTYPE -- ATYPE cannot be an unconstrained array type. function New_Sizeof (Atype : O_Tnode; Rtype : O_Tnode) return O_Cnode; -- Returns the alignment in bytes for ATYPE. The result is a literal of -- unsgined type RTYPE. function New_Alignof (Atype : O_Tnode; Rtype : O_Tnode) return O_Cnode; -- Returns the offset of FIELD in its record ATYPE. The result is a -- literal of unsigned type or access type RTYPE. function New_Offsetof (Atype : O_Tnode; Field : O_Fnode; Rtype : O_Tnode) return O_Cnode; -- Get the address of a subprogram. function New_Subprogram_Address (Subprg : O_Dnode; Atype : O_Tnode) return O_Cnode; -- Get the address of LVALUE. -- ATYPE must be a type access whose designated type is the type of LVALUE. -- FIXME: what about arrays. function New_Global_Address (Lvalue : O_Gnode; Atype : O_Tnode) return O_Cnode; -- Same as New_Address but without any restriction. function New_Global_Unchecked_Address (Lvalue : O_Gnode; Atype : O_Tnode) return O_Cnode; ------------------- -- Expressions -- ------------------- type ON_Op_Kind is ( -- Not an operation; invalid. ON_Nil, -- Dyadic operations. ON_Add_Ov, -- ON_Dyadic_Op_Kind ON_Sub_Ov, -- ON_Dyadic_Op_Kind ON_Mul_Ov, -- ON_Dyadic_Op_Kind ON_Div_Ov, -- ON_Dyadic_Op_Kind ON_Rem_Ov, -- ON_Dyadic_Op_Kind ON_Mod_Ov, -- ON_Dyadic_Op_Kind -- Binary operations. ON_And, -- ON_Dyadic_Op_Kind ON_Or, -- ON_Dyadic_Op_Kind ON_Xor, -- ON_Dyadic_Op_Kind -- Monadic operations. ON_Not, -- ON_Monadic_Op_Kind ON_Neg_Ov, -- ON_Monadic_Op_Kind ON_Abs_Ov, -- ON_Monadic_Op_Kind -- Comparaisons ON_Eq, -- ON_Compare_Op_Kind ON_Neq, -- ON_Compare_Op_Kind ON_Le, -- ON_Compare_Op_Kind ON_Lt, -- ON_Compare_Op_Kind ON_Ge, -- ON_Compare_Op_Kind ON_Gt -- ON_Compare_Op_Kind ); subtype ON_Dyadic_Op_Kind is ON_Op_Kind range ON_Add_Ov .. ON_Xor; subtype ON_Monadic_Op_Kind is ON_Op_Kind range ON_Not .. ON_Abs_Ov; subtype ON_Compare_Op_Kind is ON_Op_Kind range ON_Eq .. ON_Gt; type O_Storage is (O_Storage_External, O_Storage_Public, O_Storage_Private, O_Storage_Local); -- Specifies the storage kind of a declaration. -- O_STORAGE_EXTERNAL: -- The declaration do not either reserve memory nor generate code, and -- is imported either from an other file or from a later place in the -- current file. -- O_STORAGE_PUBLIC, O_STORAGE_PRIVATE: -- The declaration reserves memory or generates code. -- With O_STORAGE_PUBLIC, the declaration is exported outside of the -- file while with O_STORAGE_PRIVATE, the declaration is local to the -- file. Type_Error : exception; Syntax_Error : exception; -- Create a value from a literal. function New_Lit (Lit : O_Cnode) return O_Enode; -- Create a dyadic operation. -- Left and right nodes must have the same type. -- Binary operation is allowed only on boolean types. -- The result is of the type of the operands. function New_Dyadic_Op (Kind : ON_Dyadic_Op_Kind; Left, Right : O_Enode) return O_Enode; -- Create a monadic operation. -- Result is of the type of operand. function New_Monadic_Op (Kind : ON_Monadic_Op_Kind; Operand : O_Enode) return O_Enode; -- Create a comparaison operator. -- NTYPE is the type of the result and must be a boolean type. function New_Compare_Op (Kind : ON_Compare_Op_Kind; Left, Right : O_Enode; Ntype : O_Tnode) return O_Enode; type O_Inter_List is limited private; type O_Assoc_List is limited private; type O_If_Block is limited private; type O_Case_Block is limited private; -- Get an element of an array. -- INDEX must be of the type of the array index. function New_Indexed_Element (Arr : O_Lnode; Index : O_Enode) return O_Lnode; -- Get a slice of an array; this is equivalent to a conversion between -- an array or an array subtype and an array subtype. -- RES_TYPE must be an array_sub_type whose base type is the same as the -- base type of ARR. -- INDEX must be of the type of the array index. function New_Slice (Arr : O_Lnode; Res_Type : O_Tnode; Index : O_Enode) return O_Lnode; -- Get an element of a record or a union. -- Type of REC must be a record or a union type. function New_Selected_Element (Rec : O_Lnode; El : O_Fnode) return O_Lnode; function New_Global_Selected_Element (Rec : O_Gnode; El : O_Fnode) return O_Gnode; -- Reference an access. -- Type of ACC must be an access type. function New_Access_Element (Acc : O_Enode) return O_Lnode; -- Do a conversion. -- Allowed conversions are: -- FIXME: to write. function New_Convert_Ov (Val : O_Enode; Rtype : O_Tnode) return O_Enode; function New_Convert (Val : O_Enode; Rtype : O_Tnode) return O_Enode; -- Get the address of LVALUE. -- ATYPE must be a type access whose designated type is the type of LVALUE. -- FIXME: what about arrays. function New_Address (Lvalue : O_Lnode; Atype : O_Tnode) return O_Enode; -- Same as New_Address but without any restriction. function New_Unchecked_Address (Lvalue : O_Lnode; Atype : O_Tnode) return O_Enode; -- Get the value of an Lvalue. function New_Value (Lvalue : O_Lnode) return O_Enode; function New_Obj_Value (Obj : O_Dnode) return O_Enode; -- Get an lvalue from a declaration. function New_Obj (Obj : O_Dnode) return O_Lnode; -- Get a global lvalue from a declaration. function New_Global (Decl : O_Dnode) return O_Gnode; -- Return a pointer of type RTPE to SIZE bytes allocated on the stack. function New_Alloca (Rtype : O_Tnode; Size : O_Enode) return O_Enode; -- Declare a type. -- This simply gives a name to a type. procedure New_Type_Decl (Ident : O_Ident; Atype : O_Tnode); --------------------- -- Declarations. -- --------------------- -- Filename of the next declaration. procedure New_Debug_Filename_Decl (Filename : String); -- Line number of the next declaration. procedure New_Debug_Line_Decl (Line : Natural); -- Add a comment in the declarative region. procedure New_Debug_Comment_Decl (Comment : String); -- Declare a constant. -- This simply gives a name to a constant value or aggregate. -- A constant cannot be modified and its storage cannot be local. -- ATYPE must be constrained. procedure New_Const_Decl (Res : out O_Dnode; Ident : O_Ident; Storage : O_Storage; Atype : O_Tnode); -- Set the value of a non-external constant or variable. procedure Start_Init_Value (Decl : in out O_Dnode); procedure Finish_Init_Value (Decl : in out O_Dnode; Val : O_Cnode); -- Create a variable declaration. -- A variable can be local only inside a function. -- ATYPE must be constrained. procedure New_Var_Decl (Res : out O_Dnode; Ident : O_Ident; Storage : O_Storage; Atype : O_Tnode); -- Start a subprogram declaration. -- Note: nested subprograms are allowed, ie o_storage_local subprograms can -- be declared inside a subprograms. It is not allowed to declare -- o_storage_external subprograms inside a subprograms. -- Return type and interfaces cannot be a composite type. procedure Start_Function_Decl (Interfaces : out O_Inter_List; Ident : O_Ident; Storage : O_Storage; Rtype : O_Tnode); -- For a subprogram without return value. procedure Start_Procedure_Decl (Interfaces : out O_Inter_List; Ident : O_Ident; Storage : O_Storage); -- Add an interface declaration to INTERFACES. procedure New_Interface_Decl (Interfaces : in out O_Inter_List; Res : out O_Dnode; Ident : O_Ident; Atype : O_Tnode); -- Finish the function declaration, get the node and a statement list. procedure Finish_Subprogram_Decl (Interfaces : in out O_Inter_List; Res : out O_Dnode); -- Start a subprogram body. -- Note: the declaration may have an external storage, in this case it -- becomes public. procedure Start_Subprogram_Body (Func : O_Dnode); -- Finish a subprogram body. procedure Finish_Subprogram_Body; ------------------- -- Statements. -- ------------------- -- Add a line number as a statement. procedure New_Debug_Line_Stmt (Line : Natural); -- Add a comment as a statement. procedure New_Debug_Comment_Stmt (Comment : String); -- Start a declarative region. procedure Start_Declare_Stmt; procedure Finish_Declare_Stmt; -- Create a function call or a procedure call. procedure Start_Association (Assocs : out O_Assoc_List; Subprg : O_Dnode); procedure New_Association (Assocs : in out O_Assoc_List; Val : O_Enode); function New_Function_Call (Assocs : O_Assoc_List) return O_Enode; procedure New_Procedure_Call (Assocs : in out O_Assoc_List); -- Assign VALUE to TARGET, type must be the same or compatible. -- FIXME: what about slice assignment? procedure New_Assign_Stmt (Target : O_Lnode; Value : O_Enode); -- Exit from the subprogram and return VALUE. procedure New_Return_Stmt (Value : O_Enode); -- Exit from the subprogram, which doesn't return value. procedure New_Return_Stmt; -- Build an IF statement. procedure Start_If_Stmt (Block : in out O_If_Block; Cond : O_Enode); procedure New_Else_Stmt (Block : in out O_If_Block); procedure Finish_If_Stmt (Block : in out O_If_Block); -- Create a infinite loop statement. procedure Start_Loop_Stmt (Label : out O_Snode); procedure Finish_Loop_Stmt (Label : in out O_Snode); -- Exit from a loop stmt or from a for stmt. procedure New_Exit_Stmt (L : O_Snode); -- Go to the start of a loop stmt or of a for stmt. -- Loops/Fors between L and the current points are exited. procedure New_Next_Stmt (L : O_Snode); -- Case statement. -- VALUE is the selector and must be a discrete type. procedure Start_Case_Stmt (Block : in out O_Case_Block; Value : O_Enode); -- A choice branch is composed of expr, range or default choices. -- A choice branch is enclosed between a Start_Choice and a Finish_Choice. -- The statements are after the finish_choice. procedure Start_Choice (Block : in out O_Case_Block); procedure New_Expr_Choice (Block : in out O_Case_Block; Expr : O_Cnode); procedure New_Range_Choice (Block : in out O_Case_Block; Low, High : O_Cnode); procedure New_Default_Choice (Block : in out O_Case_Block); procedure Finish_Choice (Block : in out O_Case_Block); procedure Finish_Case_Stmt (Block : in out O_Case_Block); private --- PRIVATE PART is defined by ortho_nodes.ads in one of the subdirectory. end ORTHO_NODES; id='n441' href='#n441'>441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
/**CFile****************************************************************
FileName [ioReadAiger.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [Command processing package.]
Synopsis [Procedures to read binary AIGER format developed by
Armin Biere, Johannes Kepler University (http://fmv.jku.at/)]
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - December 16, 2006.]
Revision [$Id: ioReadAiger.c,v 1.00 2006/12/16 00:00:00 alanmi Exp $]
***********************************************************************/
// The code in this file is developed in collaboration with Mark Jarvin of Toronto.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "misc/bzlib/bzlib.h"
#include "misc/zlib/zlib.h"
#include "ioAbc.h"
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis [Extracts one unsigned AIG edge from the input buffer.]
Description [This procedure is a slightly modified version of Armin Biere's
procedure "unsigned decode (FILE * file)". ]
SideEffects [Updates the current reading position.]
SeeAlso []
***********************************************************************/
static inline unsigned Io_ReadAigerDecode( char ** ppPos )
{
unsigned x = 0, i = 0;
unsigned char ch;
// while ((ch = getnoneofch (file)) & 0x80)
while ((ch = *(*ppPos)++) & 0x80)
x |= (ch & 0x7f) << (7 * i++);
return x | (ch << (7 * i));
}
/**Function*************************************************************
Synopsis [Decodes the encoded array of literals.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Vec_Int_t * Io_WriteDecodeLiterals( char ** ppPos, int nEntries )
{
Vec_Int_t * vLits;
int Lit, LitPrev, Diff, i;
vLits = Vec_IntAlloc( nEntries );
LitPrev = Io_ReadAigerDecode( ppPos );
Vec_IntPush( vLits, LitPrev );
for ( i = 1; i < nEntries; i++ )
{
// Diff = Lit - LitPrev;
// Diff = (Lit < LitPrev)? -Diff : Diff;
// Diff = ((2 * Diff) << 1) | (int)(Lit < LitPrev);
Diff = Io_ReadAigerDecode( ppPos );
Diff = (Diff & 1)? -(Diff >> 1) : Diff >> 1;
Lit = Diff + LitPrev;
Vec_IntPush( vLits, Lit );
LitPrev = Lit;
}
return vLits;
}
/**Function*************************************************************
Synopsis [Reads the file into a character buffer.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
typedef struct buflist {
char buf[1<<20];
int nBuf;
struct buflist * next;
} buflist;
static char * Ioa_ReadLoadFileBz2Aig( char * pFileName, int * pFileSize )
{
FILE * pFile;
int nFileSize = 0;
char * pContents;
BZFILE * b;
int bzError;
struct buflist * pNext;
buflist * bufHead = NULL, * buf = NULL;
int RetValue;
pFile = fopen( pFileName, "rb" );
if ( pFile == NULL )
{
printf( "Ioa_ReadLoadFileBz2(): The file is unavailable (absent or open).\n" );
return NULL;
}
b = BZ2_bzReadOpen(&bzError,pFile,0,0,NULL,0);
if (bzError != BZ_OK) {
printf( "Ioa_ReadLoadFileBz2(): BZ2_bzReadOpen() failed with error %d.\n",bzError );
return NULL;
}
do {
if (!bufHead)
buf = bufHead = ABC_ALLOC( buflist, 1 );
else
buf = buf->next = ABC_ALLOC( buflist, 1 );
nFileSize += buf->nBuf = BZ2_bzRead(&bzError,b,buf->buf,1<<20);
buf->next = NULL;
} while (bzError == BZ_OK);
if (bzError == BZ_STREAM_END) {
// we're okay
char * p;
int nBytes = 0;
BZ2_bzReadClose(&bzError,b);
p = pContents = ABC_ALLOC( char, nFileSize + 10 );
buf = bufHead;
do {
memcpy(p+nBytes,buf->buf,(size_t)buf->nBuf);
nBytes += buf->nBuf;
// } while((buf = buf->next));
pNext = buf->next;
ABC_FREE( buf );
} while((buf = pNext));
} else if (bzError == BZ_DATA_ERROR_MAGIC) {
// not a BZIP2 file
BZ2_bzReadClose(&bzError,b);
fseek( pFile, 0, SEEK_END );
nFileSize = ftell( pFile );
if ( nFileSize == 0 )
{
printf( "Ioa_ReadLoadFileBz2(): The file is empty.\n" );
return NULL;
}
pContents = ABC_ALLOC( char, nFileSize + 10 );
rewind( pFile );
RetValue = fread( pContents, nFileSize, 1, pFile );
} else {
// Some other error.
printf( "Ioa_ReadLoadFileBz2(): Unable to read the compressed BLIF.\n" );
return NULL;
}
fclose( pFile );
// finish off the file with the spare .end line
// some benchmarks suddenly break off without this line
// strcpy( pContents + nFileSize, "\n.end\n" );
*pFileSize = nFileSize;
return pContents;
}
/**Function*************************************************************
Synopsis [Reads the file into a character buffer.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static char * Ioa_ReadLoadFileGzAig( char * pFileName, int * pFileSize )
{
const int READ_BLOCK_SIZE = 100000;
gzFile pFile;
char * pContents;
int amtRead, readBlock, nFileSize = 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 );
readBlock = 0;
while ((amtRead = gzread(pFile, pContents + readBlock * READ_BLOCK_SIZE, READ_BLOCK_SIZE)) == READ_BLOCK_SIZE) {
//printf("%d: read %d bytes\n", readBlock, amtRead);
nFileSize += READ_BLOCK_SIZE;
pContents = ABC_REALLOC(char, pContents, nFileSize);
++readBlock;
}
//printf("%d: read %d bytes\n", readBlock, amtRead);
assert( amtRead != -1 ); // indicates a zlib error
nFileSize -= (READ_BLOCK_SIZE - amtRead);
gzclose(pFile);
*pFileSize = nFileSize;
return pContents;
}
/**Function*************************************************************
Synopsis [Reads the AIG in the binary AIGER format.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Abc_Ntk_t * Io_ReadAiger( char * pFileName, int fCheck )
{
ProgressBar * pProgress;
FILE * pFile;
Vec_Ptr_t * vNodes, * vTerms;
Vec_Int_t * vLits = NULL;
Abc_Obj_t * pObj, * pNode0, * pNode1;
Abc_Ntk_t * pNtkNew;
int nTotal, nInputs, nOutputs, nLatches, nAnds;
int nBad = 0, nConstr = 0, nJust = 0, nFair = 0;
int nFileSize = -1, iTerm, nDigits, i;
char * pContents, * pDrivers = NULL, * pSymbols, * pCur, * pName, * pType;
unsigned uLit0, uLit1, uLit;
int RetValue;
// read the file into the buffer
if ( !strncmp(pFileName+strlen(pFileName)-4,".bz2",4) )
pContents = Ioa_ReadLoadFileBz2Aig( pFileName, &nFileSize );
else if ( !strncmp(pFileName+strlen(pFileName)-3,".gz",3) )
pContents = Ioa_ReadLoadFileGzAig( pFileName, &nFileSize );
else
{
// pContents = Ioa_ReadLoadFile( pFileName );
nFileSize = Extra_FileSize( pFileName );
pFile = fopen( pFileName, "rb" );
pContents = ABC_ALLOC( char, nFileSize );
RetValue = fread( pContents, nFileSize, 1, pFile );
fclose( pFile );
}
// check if the input file format is correct
if ( strncmp(pContents, "aig", 3) != 0 || (pContents[3] != ' ' && pContents[3] != '2') )
{
fprintf( stdout, "Wrong input file format.\n" );
ABC_FREE( pContents );
return NULL;
}
// read the parameters (M I L O A + B C J F)
pCur = pContents; while ( *pCur != ' ' ) pCur++; pCur++;
// read the number of objects
nTotal = atoi( pCur ); while ( *pCur != ' ' ) pCur++; pCur++;
// read the number of inputs
nInputs = atoi( pCur ); while ( *pCur != ' ' ) pCur++; pCur++;
// read the number of latches
nLatches = atoi( pCur ); while ( *pCur != ' ' ) pCur++; pCur++;
// read the number of outputs
nOutputs = atoi( pCur ); while ( *pCur != ' ' ) pCur++; pCur++;
// read the number of nodes
nAnds = atoi( pCur ); while ( *pCur != ' ' && *pCur != '\n' ) pCur++;
if ( *pCur == ' ' )
{
// assert( nOutputs == 0 );
// read the number of properties
pCur++;
nBad = atoi( pCur ); while ( *pCur != ' ' && *pCur != '\n' ) pCur++;
nOutputs += nBad;
}
if ( *pCur == ' ' )
{
// read the number of properties
pCur++;
nConstr = atoi( pCur ); while ( *pCur != ' ' && *pCur != '\n' ) pCur++;
nOutputs += nConstr;
}
if ( *pCur == ' ' )
{
// read the number of properties
pCur++;
nJust = atoi( pCur ); while ( *pCur != ' ' && *pCur != '\n' ) pCur++;
nOutputs += nJust;
}
if ( *pCur == ' ' )
{
// read the number of properties
pCur++;
nFair = atoi( pCur ); while ( *pCur != ' ' && *pCur != '\n' ) pCur++;
nOutputs += nFair;
}
if ( *pCur != '\n' )
{
fprintf( stdout, "The parameter line is in a wrong format.\n" );
ABC_FREE( pContents );
return NULL;
}
pCur++;
// check the parameters
if ( nTotal != nInputs + nLatches + nAnds )
{
fprintf( stdout, "The number of objects does not match.\n" );
ABC_FREE( pContents );
return NULL;
}
if ( nJust || nFair )
{
fprintf( stdout, "Reading AIGER files with liveness properties is currently not supported.\n" );
ABC_FREE( pContents );
return NULL;
}
if ( nConstr )
{
if ( nConstr == 1 )
fprintf( stdout, "Warning: The last output is interpreted as a constraint.\n" );
else
fprintf( stdout, "Warning: The last %d outputs are interpreted as constraints.\n", nConstr );
}
// allocate the empty AIG
pNtkNew = Abc_NtkAlloc( ABC_NTK_STRASH, ABC_FUNC_AIG, 1 );
pName = Extra_FileNameGeneric( pFileName );
pNtkNew->pName = Extra_UtilStrsav( pName );
pNtkNew->pSpec = Extra_UtilStrsav( pFileName );
ABC_FREE( pName );
pNtkNew->nConstrs = nConstr;
// prepare the array of nodes
vNodes = Vec_PtrAlloc( 1 + nInputs + nLatches + nAnds );
Vec_PtrPush( vNodes, Abc_ObjNot( Abc_AigConst1(pNtkNew) ) );
// create the PIs
for ( i = 0; i < nInputs; i++ )
{
pObj = Abc_NtkCreatePi(pNtkNew);
Vec_PtrPush( vNodes, pObj );
}
// create the POs
for ( i = 0; i < nOutputs; i++ )
{
pObj = Abc_NtkCreatePo(pNtkNew);
}
// create the latches
nDigits = Abc_Base10Log( nLatches );
for ( i = 0; i < nLatches; i++ )
{
pObj = Abc_NtkCreateLatch(pNtkNew);
Abc_LatchSetInit0( pObj );
pNode0 = Abc_NtkCreateBi(pNtkNew);
pNode1 = Abc_NtkCreateBo(pNtkNew);
Abc_ObjAddFanin( pObj, pNode0 );
Abc_ObjAddFanin( pNode1, pObj );
Vec_PtrPush( vNodes, pNode1 );
// assign names to latch and its input
// Abc_ObjAssignName( pObj, Abc_ObjNameDummy("_L", i, nDigits), NULL );
// printf( "Creating latch %s with input %d and output %d.\n", Abc_ObjName(pObj), pNode0->Id, pNode1->Id );
}
if ( pContents[3] == ' ' ) // standard AIGER
{
// remember the beginning of latch/PO literals
pDrivers = pCur;
// scroll to the beginning of the binary data
for ( i = 0; i < nLatches + nOutputs; )
if ( *pCur++ == '\n' )
i++;
}
else // modified AIGER
{
vLits = Io_WriteDecodeLiterals( &pCur, nLatches + nOutputs );
}
// create the AND gates
pProgress = Extra_ProgressBarStart( stdout, nAnds );
for ( i = 0; i < nAnds; i++ )
{
Extra_ProgressBarUpdate( pProgress, i, NULL );
uLit = ((i + 1 + nInputs + nLatches) << 1);
uLit1 = uLit - Io_ReadAigerDecode( &pCur );
uLit0 = uLit1 - Io_ReadAigerDecode( &pCur );
// assert( uLit1 > uLit0 );
pNode0 = Abc_ObjNotCond( (Abc_Obj_t *)Vec_PtrEntry(vNodes, uLit0 >> 1), uLit0 & 1 );
pNode1 = Abc_ObjNotCond( (Abc_Obj_t *)Vec_PtrEntry(vNodes, uLit1 >> 1), uLit1 & 1 );
assert( Vec_PtrSize(vNodes) == i + 1 + nInputs + nLatches );
Vec_PtrPush( vNodes, Abc_AigAnd((Abc_Aig_t *)pNtkNew->pManFunc, pNode0, pNode1) );
}
Extra_ProgressBarStop( pProgress );
// remember the place where symbols begin
pSymbols = pCur;
// read the latch driver literals
pCur = pDrivers;
if ( pContents[3] == ' ' ) // standard AIGER
{
Abc_NtkForEachLatchInput( pNtkNew, pObj, i )
{
uLit0 = atoi( pCur ); while ( *pCur != ' ' && *pCur != '\n' ) pCur++;
if ( *pCur == ' ' ) // read initial value
{
int Init;
pCur++;
Init = atoi( pCur );
if ( Init == 0 )
Abc_LatchSetInit0( Abc_NtkBox(pNtkNew, i) );
else if ( Init == 1 )
Abc_LatchSetInit1( Abc_NtkBox(pNtkNew, i) );
else
{
assert( Init == Abc_Var2Lit(1+Abc_NtkPiNum(pNtkNew)+i, 0) );
// unitialized value of the latch is the latch literal according to http://fmv.jku.at/hwmcc11/beyond1.pdf
Abc_LatchSetInitDc( Abc_NtkBox(pNtkNew, i) );
}
while ( *pCur != ' ' && *pCur != '\n' ) pCur++;
}
if ( *pCur != '\n' )
{
fprintf( stdout, "The initial value of latch number %d is not recongnized.\n", i );
return NULL;
}
pCur++;
pNode0 = Abc_ObjNotCond( (Abc_Obj_t *)Vec_PtrEntry(vNodes, uLit0 >> 1), (uLit0 & 1) );//^ (uLit0 < 2) );
Abc_ObjAddFanin( pObj, pNode0 );
}
// read the PO driver literals
Abc_NtkForEachPo( pNtkNew, pObj, i )
{
uLit0 = atoi( pCur ); while ( *pCur++ != '\n' );
pNode0 = Abc_ObjNotCond( (Abc_Obj_t *)Vec_PtrEntry(vNodes, uLit0 >> 1), (uLit0 & 1) );//^ (uLit0 < 2) );
Abc_ObjAddFanin( pObj, pNode0 );
}
}
else
{
// read the latch driver literals
Abc_NtkForEachLatchInput( pNtkNew, pObj, i )
{
uLit0 = Vec_IntEntry( vLits, i );
pNode0 = Abc_ObjNotCond( (Abc_Obj_t *)Vec_PtrEntry(vNodes, uLit0 >> 1), (uLit0 & 1) );
Abc_ObjAddFanin( pObj, pNode0 );
}
// read the PO driver literals
Abc_NtkForEachPo( pNtkNew, pObj, i )
{
uLit0 = Vec_IntEntry( vLits, i+Abc_NtkLatchNum(pNtkNew) );
pNode0 = Abc_ObjNotCond( (Abc_Obj_t *)Vec_PtrEntry(vNodes, uLit0 >> 1), (uLit0 & 1) );
Abc_ObjAddFanin( pObj, pNode0 );
}
Vec_IntFree( vLits );
}
// read the names if present
pCur = pSymbols;
if ( pCur < pContents + nFileSize && *pCur != 'c' )
{
int Counter = 0;
while ( pCur < pContents + nFileSize && *pCur != 'c' )
{
// get the terminal type
pType = pCur;
if ( *pCur == 'i' )
vTerms = pNtkNew->vPis;
else if ( *pCur == 'l' )
vTerms = pNtkNew->vBoxes;
else if ( *pCur == 'o' || *pCur == 'b' || *pCur == 'c' || *pCur == 'j' || *pCur == 'f' )
vTerms = pNtkNew->vPos;
else
{
// fprintf( stdout, "Wrong terminal type.\n" );
return NULL;
}
// get the terminal number
iTerm = atoi( ++pCur ); while ( *pCur++ != ' ' );
// get the node
if ( iTerm >= Vec_PtrSize(vTerms) )
{
fprintf( stdout, "The number of terminal is out of bound.\n" );
return NULL;
}
pObj = (Abc_Obj_t *)Vec_PtrEntry( vTerms, iTerm );
if ( *pType == 'l' )
pObj = Abc_ObjFanout0(pObj);
// assign the name
pName = pCur; while ( *pCur++ != '\n' );
// assign this name
*(pCur-1) = 0;
Abc_ObjAssignName( pObj, pName, NULL );
if ( *pType == 'l' )
{
Abc_ObjAssignName( Abc_ObjFanin0(pObj), Abc_ObjName(pObj), "L" );
Abc_ObjAssignName( Abc_ObjFanin0(Abc_ObjFanin0(pObj)), Abc_ObjName(pObj), "_in" );
}
// mark the node as named
pObj->pCopy = (Abc_Obj_t *)Abc_ObjName(pObj);
}
// assign the remaining names
Abc_NtkForEachPi( pNtkNew, pObj, i )
{
if ( pObj->pCopy ) continue;
Abc_ObjAssignName( pObj, Abc_ObjName(pObj), NULL );
Counter++;
}
Abc_NtkForEachLatchOutput( pNtkNew, pObj, i )
{
if ( pObj->pCopy ) continue;
Abc_ObjAssignName( pObj, Abc_ObjName(pObj), NULL );
Abc_ObjAssignName( Abc_ObjFanin0(pObj), Abc_ObjName(pObj), "L" );
Abc_ObjAssignName( Abc_ObjFanin0(Abc_ObjFanin0(pObj)), Abc_ObjName(pObj), "_in" );
Counter++;
}
Abc_NtkForEachPo( pNtkNew, pObj, i )
{
if ( pObj->pCopy ) continue;
Abc_ObjAssignName( pObj, Abc_ObjName(pObj), NULL );
Counter++;
}
// if ( Counter )
// printf( "Io_ReadAiger(): Added %d default names for nameless I/O/register objects.\n", Counter );
}
else
{
// printf( "Io_ReadAiger(): I/O/register names are not given. Generating short names.\n" );
Abc_NtkShortNames( pNtkNew );
}
// read the name of the model if given
pCur = pSymbols;
if ( pCur + 1 < pContents + nFileSize && *pCur == 'c' )
{
pCur++;
if ( *pCur == 'n' )
{
pCur++;
// read model name
if ( strlen(pCur) > 0 )
{
ABC_FREE( pNtkNew->pName );
pNtkNew->pName = Extra_UtilStrsav( pCur );
}
}
}
// skipping the comments
ABC_FREE( pContents );
Vec_PtrFree( vNodes );
// remove the extra nodes
Abc_AigCleanup( (Abc_Aig_t *)pNtkNew->pManFunc );
// update polarity of the additional outputs
if ( nBad || nConstr || nJust || nFair )
Abc_NtkInvertConstraints( pNtkNew );
// check the result
if ( fCheck && !Abc_NtkCheckRead( pNtkNew ) )
{
printf( "Io_ReadAiger: The network check has failed.\n" );
Abc_NtkDelete( pNtkNew );
return NULL;
}
return pNtkNew;
}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END