mirror of https://github.com/YosysHQ/abc.git
Updates to NDR format (flops, memories, signed mult, etc).
This commit is contained in:
parent
89c981c6ee
commit
f23ea8e33f
|
|
@ -138,8 +138,8 @@ typedef enum {
|
|||
ABC_OPER_LATCH, // 86
|
||||
ABC_OPER_LATCHRS, // 87
|
||||
ABC_OPER_DFF, // 88
|
||||
ABC_OPER_DFFCPL, // 89
|
||||
ABC_OPER_DFFRS, // 90
|
||||
ABC_OPER_DFFRSE, // 89
|
||||
ABC_OPER_DFFLAST, // 90
|
||||
|
||||
ABC_OPER_SLICE, // 91
|
||||
ABC_OPER_CONCAT, // 92
|
||||
|
|
|
|||
|
|
@ -42,61 +42,51 @@ ABC_NAMESPACE_HEADER_START
|
|||
/*
|
||||
For the lack of a better name, this format is called New Data Representation (NDR).
|
||||
|
||||
NDR is based on the following principles:
|
||||
- complex data is composed of individual records
|
||||
- a record has one of several known types (module, name, range, fanins, etc)
|
||||
- a record can be atomic, for example, a name or an operator type
|
||||
- a record can be composed of other records (for example, a module is composed of objects, etc)
|
||||
- the stored data should be easy to write into and read from a file, or pass around as a memory buffer
|
||||
- the format should be simple, easy to use, low-memory, and extensible
|
||||
- new record types can be added by the user as needed
|
||||
NDR is designed as an interchange format to pass hierarchical word-level designs between the tools.
|
||||
It is relatively simple, uses little memory, and can be easily converted into other ABC data-structures.
|
||||
|
||||
The implementation is based on the following ideas:
|
||||
- a record is composed of two parts (the header followed by the body)
|
||||
- the header contains two items (the record type and the body size, measured in terms of 4-byte integers)
|
||||
- the body contains as many entries as stated in the record size
|
||||
- if a record is composed of other records, its body contains these records
|
||||
This tutorial discusses how to construct the NDR representation of a hierarchical word-level design.
|
||||
|
||||
As an example, consider a name. It can be a module name, an object name, or a net name.
|
||||
A record storing one name has a header {NDR_NAME, 1} containing record type (NDR_NAME) and size (1),
|
||||
The body of the record is composed of one unsigned integer representing the name (say, 357).
|
||||
So the complete record looks as follows: { <header>, <body> } = { {NDR_NAME, 1}, {357} }.
|
||||
First, all names used in the design (including the design name, module names, port names, net names,
|
||||
instance names, etc) are hashed into 1-based integers called "name IDs". Nets are not explicitly represented.
|
||||
The connectivity of a design object is established by specifying name IDs of the nets connected to the object.
|
||||
Object inputs are name IDs of the driving nets; object outputs are name IDs of the driven nets.
|
||||
|
||||
As another example, consider a two-input AND-gate. In this case, the recent is composed
|
||||
of a header {NDR_OBJECT, 4} containing record type (NDR_OBJECT) and the body size (4), followed
|
||||
by an array of records creating the AND-gate: (a) name, (b) operation type, (c) fanins.
|
||||
The complete record looks as follows: { {NDR_OBJECT, 5}, {{{NDR_NAME, 1}, 357}, {{NDR_OPERTYPE, 1}, ABC_OPER_LOGIC_AND},
|
||||
{{NDR_INPUT, 2}, {<id_fanin1>, <id_fanin2>}}} }. Please note that only body entries are counted towards size.
|
||||
In the case of one name, there is only one body entry. In the case of the AND-gate, there are 4 body entries
|
||||
(name ID, gate type, first fanin, second fanin).
|
||||
The design is initialized using procedure Ndr_Create(), which takes the design name as an argument.
|
||||
A module in the design is initialized using procedure Ndr_AddModule(), which take the design and
|
||||
the module name as arguments. Objects are added to a module in any order using procedure Ndr_AddObject().
|
||||
|
||||
Headers and bodies of all objects are stored differently. Headers are stored in an array of unsigned chars,
|
||||
while bodies are stored in the array of 4-byte unsigned integers. This is important for memory efficiency.
|
||||
However, the user does not see these details.
|
||||
Primary input and primary output objects should be explicitly created, as shown in the examples below.
|
||||
|
||||
To estimate memory usage, we can assume that each header takes 1 byte and each body entry contains 4 bytes.
|
||||
A name takes 5 bytes, and an AND-gate takes 1 * NumHeaders + 4 * NumBodyEntries = 1 * 4 + 4 * 4 = 20 bytes.
|
||||
Not bad. The same as memory usage in a well-designed AIG package with structural hashing.
|
||||
Instances of known operators listed in file "abcOper.h" are assumed to have one output. The only known
|
||||
issue due to this restriction concerns an adder, which produces a sum and a carry-out. To make sure the
|
||||
adder instance has only one output, the carry-out has to be concatenated with the sum before the adder
|
||||
instance is created in the NDR format.
|
||||
|
||||
Comments:
|
||||
- it is assumed that all port names, net names, and instance names are hashed into 1-based integer numbers called name IDs
|
||||
- nets are not explicitly represented but their name ID are used to establish connectivity between the objects
|
||||
- primary input and primary output objects have to be explicitly created (as shown in the example below)
|
||||
- object inputs are name IDs of the driving nets; object outputs are name IDs of the driven nets
|
||||
- objects can be added to a module in any order
|
||||
- if the ordering of inputs/outputs/flops of a module is not provided as a separate record,
|
||||
their ordering is determined by the order of their appearance of their records in the body of the module
|
||||
- if range limits and signedness are all 0, it is assumed that it is a Boolean object
|
||||
- if left limit and right limit of a range are equal, it is assumed that the range contains one bit
|
||||
- instances of known operators can have types defined by Wlc_ObjType_t below
|
||||
- instances of user modules have type equal to the name ID of the module plus 1000
|
||||
- initial states of the flops are given as char-strings containing 0, 1, and 'x'
|
||||
(for example, "4'b10XX" is an init state of a 4-bit flop with bit-level init states const1, const0, unknown, unknown)
|
||||
- word-level constants are represented as char-strings given in the same way as they would appear in a Verilog file
|
||||
(for example, the 16-bit constant 10 is represented as a string "4'b1010". This string contains 8 bytes,
|
||||
including the char '\0' to denote the end of the string. It will take 2 unsigned ints, therefore
|
||||
its record will look as follows { {NDR_FUNCTION, 2}, {"4'b1010"} }, but the user does not see these details.
|
||||
The user only gives "4'b1010" as an argument (char * pFunction) to the above procedure Ndr_AddObject().
|
||||
Instances of hierarchical modules defined by the user can have multiple outputs.
|
||||
|
||||
Bit-slice and concatenation operators should be represented as separate objects.
|
||||
|
||||
If the ordering of inputs/outputs/flops of a module is not provided as a separate record in NDR format,
|
||||
their ordering is determined by the order of their appearance of their records in the body of the module.
|
||||
|
||||
If left limit and right limit of a range are equal, it is assumed that the range contains one bit
|
||||
If range limits and signedness are all 0, it is assumed that it is the bit-width is equal to 1.
|
||||
|
||||
Word-level constants are represented as char-strings given in the same way as they would appear in a Verilog
|
||||
file. For example, the 16-bit constant 10 is represented as a string "4'b1010" and is given as an argument
|
||||
(char * pFunction) to the procedure Ndr_AddObject().
|
||||
|
||||
Currently two types of flops are supported: a simple flop with implicit clock with two fanins (data and init)
|
||||
and a complex flop with 7 fanins (clock, data, reset, set, enable, async, init), as shown in the examples below.
|
||||
|
||||
The initial value of a flop is represented by input "init", which can be driven by a constant or by a primary
|
||||
input of the module. If it is a primary input, is it assumed that the flop is not initialized. If the input
|
||||
"init" is not driven, it is assumed that the flop is initialized to 0.
|
||||
|
||||
Memory read and write ports are supported, as shown in the example below.
|
||||
|
||||
(to be continued)
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -377,7 +367,7 @@ static inline void Ndr_WriteVerilogModule( FILE * pFile, void * pDesign, int Mod
|
|||
if ( Type >= 256 )
|
||||
{
|
||||
fprintf( pFile, " %s ", pNames[Ndr_ObjReadEntry(p, Type-256, NDR_NAME)] );
|
||||
if ( Ndr_ObjReadBody(p, Obj, NDR_NAME) )
|
||||
if ( Ndr_ObjReadBody(p, Obj, NDR_NAME) > 0 )
|
||||
fprintf( pFile, "%s ", pNames[Ndr_ObjReadBody(p, Obj, NDR_NAME)] );
|
||||
fprintf( pFile, "( " );
|
||||
nArray = Ndr_ObjReadArray( p, Obj, NDR_INPUT, &pArray );
|
||||
|
|
@ -386,6 +376,64 @@ static inline void Ndr_WriteVerilogModule( FILE * pFile, void * pDesign, int Mod
|
|||
fprintf( pFile, ");\n" );
|
||||
continue;
|
||||
}
|
||||
if ( Type == ABC_OPER_DFF )
|
||||
{
|
||||
fprintf( pFile, " %s ", "ABC_DFF" );
|
||||
if ( Ndr_ObjReadBody(p, Obj, NDR_NAME) > 0 )
|
||||
fprintf( pFile, "%s ", pNames[Ndr_ObjReadBody(p, Obj, NDR_NAME)] );
|
||||
fprintf( pFile, "( " );
|
||||
nArray = Ndr_ObjReadArray( p, Obj, NDR_INPUT, &pArray );
|
||||
fprintf( pFile, ".q(%s), ", Ndr_ObjReadOutName(p, Obj, pNames) );
|
||||
fprintf( pFile, ".d(%s), ", pNames[pArray[0]] );
|
||||
fprintf( pFile, ".init(%s) ", pNames[pArray[1]] );
|
||||
fprintf( pFile, ");\n" );
|
||||
continue;
|
||||
}
|
||||
if ( Type == ABC_OPER_DFFRSE )
|
||||
{
|
||||
fprintf( pFile, " %s ", "ABC_DFFRSE" );
|
||||
if ( Ndr_ObjReadBody(p, Obj, NDR_NAME) > 0 )
|
||||
fprintf( pFile, "%s ", pNames[Ndr_ObjReadBody(p, Obj, NDR_NAME)] );
|
||||
fprintf( pFile, "( " );
|
||||
nArray = Ndr_ObjReadArray( p, Obj, NDR_INPUT, &pArray );
|
||||
fprintf( pFile, ".q(%s), ", Ndr_ObjReadOutName(p, Obj, pNames) );
|
||||
fprintf( pFile, ".d(%s), ", pNames[pArray[0]] );
|
||||
fprintf( pFile, ".clk(%s), ", pNames[pArray[1]] );
|
||||
fprintf( pFile, ".reset(%s), ", pNames[pArray[2]] );
|
||||
fprintf( pFile, ".set(%s), ", pNames[pArray[3]] );
|
||||
fprintf( pFile, ".enable(%s), ", pNames[pArray[4]] );
|
||||
fprintf( pFile, ".async(%s), ", pNames[pArray[5]] );
|
||||
fprintf( pFile, ".init(%s) ", pNames[pArray[6]] );
|
||||
fprintf( pFile, ");\n" );
|
||||
continue;
|
||||
}
|
||||
if ( Type == ABC_OPER_RAMR )
|
||||
{
|
||||
fprintf( pFile, " %s ", "ABC_READ" );
|
||||
if ( Ndr_ObjReadBody(p, Obj, NDR_NAME) > 0 )
|
||||
fprintf( pFile, "%s ", pNames[Ndr_ObjReadBody(p, Obj, NDR_NAME)] );
|
||||
fprintf( pFile, "( " );
|
||||
nArray = Ndr_ObjReadArray( p, Obj, NDR_INPUT, &pArray );
|
||||
fprintf( pFile, ".data(%s), ", Ndr_ObjReadOutName(p, Obj, pNames) );
|
||||
fprintf( pFile, ".mem_in(%s), ", pNames[pArray[0]] );
|
||||
fprintf( pFile, ".addr(%s) ", pNames[pArray[1]] );
|
||||
fprintf( pFile, ");\n" );
|
||||
continue;
|
||||
}
|
||||
if ( Type == ABC_OPER_RAMW )
|
||||
{
|
||||
fprintf( pFile, " %s ", "ABC_WRITE" );
|
||||
if ( Ndr_ObjReadBody(p, Obj, NDR_NAME) > 0 )
|
||||
fprintf( pFile, "%s ", pNames[Ndr_ObjReadBody(p, Obj, NDR_NAME)] );
|
||||
fprintf( pFile, "( " );
|
||||
nArray = Ndr_ObjReadArray( p, Obj, NDR_INPUT, &pArray );
|
||||
fprintf( pFile, ".mem_out(%s), ", Ndr_ObjReadOutName(p, Obj, pNames) );
|
||||
fprintf( pFile, ".mem_in(%s), ", pNames[pArray[0]] );
|
||||
fprintf( pFile, ".addr(%s), ", pNames[pArray[1]] );
|
||||
fprintf( pFile, ".data(%s) ", pNames[pArray[2]] );
|
||||
fprintf( pFile, ");\n" );
|
||||
continue;
|
||||
}
|
||||
fprintf( pFile, " assign %s = ", Ndr_ObjReadOutName(p, Obj, pNames) );
|
||||
nArray = Ndr_ObjReadArray( p, Obj, NDR_INPUT, &pArray );
|
||||
if ( nArray == 0 )
|
||||
|
|
@ -551,7 +599,7 @@ static inline void Ndr_Write( char * pFileName, void * pDesign )
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// This testing procedure creates and writes into a Verilog file
|
||||
// for the following design composed of one module
|
||||
// the following design composed of one module
|
||||
|
||||
// module add10 ( input [3:0] a, output [3:0] s );
|
||||
// wire [3:0] const10 = 4'b1010;
|
||||
|
|
@ -589,7 +637,7 @@ static inline void Ndr_ModuleTest()
|
|||
|
||||
|
||||
// This testing procedure creates and writes into a Verilog file
|
||||
// for the following design composed of one adder divided into two
|
||||
// the following design composed of one adder divided into two
|
||||
|
||||
// module add8 ( input [7:0] a, input [7:0] b, output [7:0] s, output co );
|
||||
// wire [3:0] a0 = a[3:0];
|
||||
|
|
@ -676,7 +724,7 @@ static inline void Ndr_ModuleTestAdder()
|
|||
}
|
||||
|
||||
// This testing procedure creates and writes into a Verilog file
|
||||
// for the following hierarchical design composed of three modules
|
||||
// the following hierarchical design composed of two modules
|
||||
|
||||
// module mux21w ( input sel, input [3:0] d1, input [3:0] d0, output [3:0] out );
|
||||
// assign out = sel ? d1 : d0;
|
||||
|
|
@ -761,6 +809,141 @@ static inline void Ndr_ModuleTestHierarchy()
|
|||
}
|
||||
|
||||
|
||||
// This testing procedure creates and writes into a Verilog file
|
||||
// the following design with read/write memory ports
|
||||
|
||||
// module test ( input clk, input [8:0] raddr, input [8:0] waddr, input [31:0] data, input [16383:0] mem_init, output out );
|
||||
//
|
||||
// wire [31:0] read1, read2;
|
||||
//
|
||||
// wire [16383:0] mem_fo1, mem_fo2, mem_fi1, mem_fi2;
|
||||
//
|
||||
// ABC_FF i_reg1 ( .q(mem_fo1), .d(mem_fi1), .init(mem_init) );
|
||||
// ABC_FF i_reg2 ( .q(mem_fo2), .d(mem_fi2), .init(mem_init) );
|
||||
//
|
||||
// ABC_WRITE i_write1 ( .mem_out(mem_fi1), .mem_in(mem_fo1), .addr(waddr), .data(data) );
|
||||
// ABC_WRITE i_write2 ( .mem_out(mem_fi2), .mem_in(mem_fo2), .addr(waddr), .data(data) );
|
||||
//
|
||||
// ABC_READ i_read1 ( .data(read1), .mem_in(mem_fi1), .addr(raddr) );
|
||||
// ABC_READ i_read2 ( .data(read2), .mem_in(mem_fi2), .addr(raddr) );
|
||||
//
|
||||
// assign out = read1 != read2;
|
||||
//endmodule
|
||||
|
||||
static inline void Ndr_ModuleTestMemory()
|
||||
{
|
||||
// map name IDs into char strings
|
||||
char * ppNames[20] = { NULL,
|
||||
"clk", "raddr", "waddr", "data", "mem_init", "out", // 1, 2, 3, 4, 5, 6
|
||||
"read1", "read2", // 7. 8
|
||||
"mem_fo1", "mem_fo2", "mem_fi1", "mem_fi2", // 9, 10, 11, 12
|
||||
"i_reg1", "i_reg2", // 13, 14
|
||||
"i_read1", "i_read2", // 15, 16
|
||||
"i_write1", "i_write2", "memtest" // 17, 18, 19
|
||||
};
|
||||
// inputs
|
||||
int NameIdClk = 1;
|
||||
int NameIdRaddr = 2;
|
||||
int NameIdWaddr = 3;
|
||||
int NameIdData = 4;
|
||||
int NameIdMemInit = 5;
|
||||
// flops
|
||||
int NameIdFF1 = 9;
|
||||
int NameIdFF2 = 10;
|
||||
int FaninsFF1[2] = { 11, 5 };
|
||||
int FaninsFF2[2] = { 12, 5 };
|
||||
// writes
|
||||
int NameIdWrite1 = 11;
|
||||
int NameIdWrite2 = 12;
|
||||
int FaninsWrite1[3] = { 9, 3, 4 };
|
||||
int FaninsWrite2[3] = { 10, 3, 4 };
|
||||
// reads
|
||||
int NameIdRead1 = 7;
|
||||
int NameIdRead2 = 8;
|
||||
int FaninsRead1[2] = { 11, 2 };
|
||||
int FaninsRead2[2] = { 12, 2 };
|
||||
// compare
|
||||
int NameIdComp = 6;
|
||||
int FaninsComp[2] = { 7, 8 };
|
||||
|
||||
// create a new module
|
||||
void * pDesign = Ndr_Create( 19 ); // create design named "memtest"
|
||||
|
||||
int ModuleID = Ndr_AddModule( pDesign, 19 ); // create module named "memtest"
|
||||
|
||||
// add objects to the module
|
||||
Ndr_AddObject( pDesign, ModuleID, ABC_OPER_CI, 0, 0, 0, 0, 0, NULL, 1, &NameIdClk, NULL );
|
||||
Ndr_AddObject( pDesign, ModuleID, ABC_OPER_CI, 0, 8, 0, 0, 0, NULL, 1, &NameIdRaddr, NULL );
|
||||
Ndr_AddObject( pDesign, ModuleID, ABC_OPER_CI, 0, 8, 0, 0, 0, NULL, 1, &NameIdWaddr, NULL );
|
||||
Ndr_AddObject( pDesign, ModuleID, ABC_OPER_CI, 0, 31, 0, 0, 0, NULL, 1, &NameIdData, NULL );
|
||||
Ndr_AddObject( pDesign, ModuleID, ABC_OPER_CI, 0, 16383, 0, 0, 0, NULL, 1, &NameIdMemInit, NULL );
|
||||
|
||||
Ndr_AddObject( pDesign, ModuleID, ABC_OPER_CO, 0, 0, 0, 0, 1, &NameIdComp, 0, NULL, NULL );
|
||||
|
||||
Ndr_AddObject( pDesign, ModuleID, ABC_OPER_DFF, 13, 16383, 0, 0, 2, FaninsFF1, 1, &NameIdFF1, NULL );
|
||||
Ndr_AddObject( pDesign, ModuleID, ABC_OPER_DFF, 14, 16383, 0, 0, 2, FaninsFF2, 1, &NameIdFF2, NULL );
|
||||
|
||||
Ndr_AddObject( pDesign, ModuleID, ABC_OPER_RAMW, 17, 16383, 0, 0, 3, FaninsWrite1, 1, &NameIdWrite1, NULL );
|
||||
Ndr_AddObject( pDesign, ModuleID, ABC_OPER_RAMW, 18, 16383, 0, 0, 3, FaninsWrite2, 1, &NameIdWrite2, NULL );
|
||||
|
||||
Ndr_AddObject( pDesign, ModuleID, ABC_OPER_RAMR, 15, 31, 0, 0, 2, FaninsRead1, 1, &NameIdRead1, NULL );
|
||||
Ndr_AddObject( pDesign, ModuleID, ABC_OPER_RAMR, 16, 31, 0, 0, 2, FaninsRead2, 1, &NameIdRead2, NULL );
|
||||
|
||||
Ndr_AddObject( pDesign, ModuleID, ABC_OPER_COMP_NOTEQU, 0, 0, 0, 0, 2, FaninsComp, 1, &NameIdComp, NULL );
|
||||
|
||||
// write Verilog for verification
|
||||
Ndr_WriteVerilog( NULL, pDesign, ppNames );
|
||||
Ndr_Write( "memtest.ndr", pDesign );
|
||||
Ndr_Delete( pDesign );
|
||||
}
|
||||
|
||||
// This testing procedure creates and writes into a Verilog file
|
||||
// the following design composed of one word-level flop
|
||||
|
||||
// module flop ( input [3:0] data, input clk, input reset, input set, input enable, input async, input [3:0] init, output [3:0] q );
|
||||
// ABC_DFFRSE reg1 ( .d(data), .clk(clk), .reset(reset), .set(set), .enable(enable), .async(async), .init(init), .q(q) ) ;
|
||||
// endmodule
|
||||
|
||||
static inline void Ndr_ModuleTestFlop()
|
||||
{
|
||||
// map name IDs into char strings
|
||||
char * ppNames[10] = { NULL, "flop", "data", "clk", "reset", "set", "enable", "async", "init", "q" };
|
||||
// name IDs
|
||||
int NameIdData = 2;
|
||||
int NameIdClk = 3;
|
||||
int NameIdReset = 4;
|
||||
int NameIdSet = 5;
|
||||
int NameIdEnable = 6;
|
||||
int NameIdAsync = 7;
|
||||
int NameIdInit = 8;
|
||||
int NameIdQ = 9;
|
||||
// array of fanins of node s
|
||||
int Fanins[7] = { NameIdData, NameIdClk, NameIdReset, NameIdSet, NameIdEnable, NameIdAsync, NameIdInit };
|
||||
|
||||
// create a new module
|
||||
void * pDesign = Ndr_Create( 1 );
|
||||
|
||||
int ModuleID = Ndr_AddModule( pDesign, 1 );
|
||||
|
||||
// add objects to the modele
|
||||
Ndr_AddObject( pDesign, ModuleID, ABC_OPER_CI, 0, 3, 0, 0, 0, NULL, 1, &NameIdData, NULL );
|
||||
Ndr_AddObject( pDesign, ModuleID, ABC_OPER_CI, 0, 0, 0, 0, 0, NULL, 1, &NameIdClk, NULL );
|
||||
Ndr_AddObject( pDesign, ModuleID, ABC_OPER_CI, 0, 0, 0, 0, 0, NULL, 1, &NameIdReset, NULL );
|
||||
Ndr_AddObject( pDesign, ModuleID, ABC_OPER_CI, 0, 0, 0, 0, 0, NULL, 1, &NameIdSet, NULL );
|
||||
Ndr_AddObject( pDesign, ModuleID, ABC_OPER_CI, 0, 0, 0, 0, 0, NULL, 1, &NameIdEnable, NULL );
|
||||
Ndr_AddObject( pDesign, ModuleID, ABC_OPER_CI, 0, 0, 0, 0, 0, NULL, 1, &NameIdAsync, NULL );
|
||||
Ndr_AddObject( pDesign, ModuleID, ABC_OPER_CI, 0, 3, 0, 0, 0, NULL, 1, &NameIdInit, NULL );
|
||||
|
||||
Ndr_AddObject( pDesign, ModuleID, ABC_OPER_DFFRSE, 0, 3, 0, 0, 7, Fanins, 1, &NameIdQ, NULL );
|
||||
|
||||
Ndr_AddObject( pDesign, ModuleID, ABC_OPER_CO, 0, 3, 0, 0, 1, &NameIdQ, 0, NULL, NULL );
|
||||
|
||||
// write Verilog for verification
|
||||
Ndr_WriteVerilog( NULL, pDesign, ppNames );
|
||||
Ndr_Write( "flop.ndr", pDesign );
|
||||
Ndr_Delete( pDesign );
|
||||
}
|
||||
|
||||
ABC_NAMESPACE_HEADER_END
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ static inline void Acb_NtkFreeObjCnfs( Acb_Ntk_t * p ) { V
|
|||
|
||||
static inline Acb_ObjType_t Acb_ObjType( Acb_Ntk_t * p, int i ) { assert(i>0); return (Acb_ObjType_t)(int)(unsigned char)Vec_StrEntry(&p->vObjType, i); }
|
||||
static inline void Acb_ObjCleanType( Acb_Ntk_t * p, int i ) { assert(i>0); Vec_StrWriteEntry( &p->vObjType, i, (char)ABC_OPER_NONE ); }
|
||||
static inline int Acb_TypeIsSeq( Acb_ObjType_t Type ) { return Type >= ABC_OPER_RAM && Type <= ABC_OPER_DFFRS; }
|
||||
static inline int Acb_TypeIsSeq( Acb_ObjType_t Type ) { return Type >= ABC_OPER_RAM && Type <= ABC_OPER_DFFLAST; }
|
||||
static inline int Acb_TypeIsUnary( Acb_ObjType_t Type ) { return Type == ABC_OPER_BIT_BUF || Type == ABC_OPER_BIT_INV || Type == ABC_OPER_LOGIC_NOT || Type == ABC_OPER_ARI_MIN || Type == ABC_OPER_ARI_SQRT || Type == ABC_OPER_ARI_ABS || (Type >= ABC_OPER_RED_AND && Type <= ABC_OPER_RED_NXOR); }
|
||||
static inline int Acb_TypeIsMux( Acb_ObjType_t Type ) { return Type == ABC_OPER_BIT_MUX || Type == ABC_OPER_SEL_NMUX || Type == ABC_OPER_SEL_SEL || Type == ABC_OPER_SEL_PSEL; }
|
||||
|
||||
|
|
|
|||
|
|
@ -44,10 +44,10 @@ ABC_NAMESPACE_HEADER_START
|
|||
typedef enum {
|
||||
WLC_OBJ_NONE = 0, // 00: unknown
|
||||
WLC_OBJ_PI, // 01: primary input
|
||||
WLC_OBJ_PO, // 02: primary output (unused)
|
||||
WLC_OBJ_PO, // 02: primary output
|
||||
WLC_OBJ_FO, // 03: flop output
|
||||
WLC_OBJ_FI, // 04: flop input (unused)
|
||||
WLC_OBJ_FF, // 05: flop (unused)
|
||||
WLC_OBJ_FF, // 05: flop
|
||||
WLC_OBJ_CONST, // 06: constant
|
||||
WLC_OBJ_BUF, // 07: buffer
|
||||
WLC_OBJ_MUX, // 08: multiplexer
|
||||
|
|
@ -98,7 +98,8 @@ typedef enum {
|
|||
WLC_OBJ_TABLE, // 53: bit table
|
||||
WLC_OBJ_READ, // 54: read port
|
||||
WLC_OBJ_WRITE, // 55: write port
|
||||
WLC_OBJ_NUMBER // 56: unused
|
||||
WLC_OBJ_ARI_ADDSUB, // 56: adder-subtractor
|
||||
WLC_OBJ_NUMBER // 57: unused
|
||||
} Wlc_ObjType_t;
|
||||
// when adding new types, remember to update table Wlc_Names in "wlcNtk.c"
|
||||
|
||||
|
|
@ -142,6 +143,8 @@ struct Wlc_Ntk_t_
|
|||
int nObjs[WLC_OBJ_NUMBER]; // counter of objects of each type
|
||||
int nAnds[WLC_OBJ_NUMBER]; // counter of AND gates after blasting
|
||||
int fSmtLib; // the network comes from an SMT-LIB file
|
||||
int fMemPorts; // the network contains memory ports
|
||||
int fEasyFfs; // the network contains simple flops
|
||||
int nAssert; // the number of asserts
|
||||
// memory for objects
|
||||
Wlc_Obj_t * pObjs;
|
||||
|
|
|
|||
|
|
@ -1642,7 +1642,7 @@ usage:
|
|||
int Abc_CommandTest( Abc_Frame_t * pAbc, int argc, char ** argv )
|
||||
{
|
||||
extern void Wlc_NtkSimulateTest( Wlc_Ntk_t * p );
|
||||
Wlc_Ntk_t * pNtk = Wlc_AbcGetNtk(pAbc);
|
||||
//Wlc_Ntk_t * pNtk = Wlc_AbcGetNtk(pAbc);
|
||||
int c, fVerbose = 0;
|
||||
Extra_UtilGetoptReset();
|
||||
while ( ( c = Extra_UtilGetopt( argc, argv, "vh" ) ) != EOF )
|
||||
|
|
@ -1658,11 +1658,12 @@ int Abc_CommandTest( Abc_Frame_t * pAbc, int argc, char ** argv )
|
|||
goto usage;
|
||||
}
|
||||
}
|
||||
if ( pNtk == NULL )
|
||||
{
|
||||
Abc_Print( 1, "Abc_CommandTest(): There is no current design.\n" );
|
||||
return 0;
|
||||
}
|
||||
// if ( pNtk == NULL )
|
||||
// {
|
||||
// Abc_Print( 1, "Abc_CommandTest(): There is no current design.\n" );
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// transform
|
||||
//pNtk = Wlc_NtkUifNodePairs( pNtk, NULL );
|
||||
//pNtk = Wlc_NtkAbstractNodes( pNtk, NULL );
|
||||
|
|
@ -1671,9 +1672,9 @@ int Abc_CommandTest( Abc_Frame_t * pAbc, int argc, char ** argv )
|
|||
//Wlc_NtkSimulateTest( (Wlc_Ntk_t *)pAbc->pAbcWlc );
|
||||
//pNtk = Wlc_NtkDupSingleNodes( pNtk );
|
||||
//Wlc_AbcUpdateNtk( pAbc, pNtk );
|
||||
//Wlc_ReadNdrTest( pNtk );
|
||||
pNtk = Wlc_NtkMemAbstractTest( pNtk );
|
||||
Wlc_AbcUpdateNtk( pAbc, pNtk );
|
||||
Ndr_ModuleTestMemory();
|
||||
//pNtk = Wlc_NtkMemAbstractTest( pNtk );
|
||||
//Wlc_AbcUpdateNtk( pAbc, pNtk );
|
||||
return 0;
|
||||
usage:
|
||||
Abc_Print( -2, "usage: %%test [-vh]\n" );
|
||||
|
|
|
|||
|
|
@ -366,6 +366,8 @@ Wlc_Ntk_t * Wlc_NtkAbstractMemory( Wlc_Ntk_t * p, Vec_Int_t * vMemObjs, Vec_Int_
|
|||
Wlc_NtkCleanCopy( p );
|
||||
pNew = Wlc_NtkAlloc( p->pName, p->nObjsAlloc + 1000 );
|
||||
pNew->fSmtLib = p->fSmtLib;
|
||||
pNew->fMemPorts = p->fMemPorts;
|
||||
pNew->fEasyFfs = p->fEasyFfs;
|
||||
pNew->vInits = Vec_IntAlloc( 100 );
|
||||
|
||||
// duplicate PIs
|
||||
|
|
|
|||
|
|
@ -91,6 +91,12 @@ int Ndr_TypeNdr2Wlc( int Type )
|
|||
if ( Type == ABC_OPER_ARI_MIN ) return WLC_OBJ_ARI_MINUS; // 50: arithmetic minus
|
||||
if ( Type == ABC_OPER_ARI_SQRT ) return WLC_OBJ_ARI_SQRT; // 51: integer square root
|
||||
if ( Type == ABC_OPER_ARI_SQUARE ) return WLC_OBJ_ARI_SQUARE; // 52: integer square
|
||||
if ( Type == ABC_OPER_ARI_ADDSUB ) return WLC_OBJ_ARI_ADDSUB; // 56: adder-subtractor
|
||||
if ( Type == ABC_OPER_ARI_SMUL ) return WLC_OBJ_ARI_MULTI; // 45: signed multiplier
|
||||
if ( Type == ABC_OPER_DFF ) return WLC_OBJ_FO; // 03: flop
|
||||
if ( Type == ABC_OPER_DFFRSE ) return WLC_OBJ_FF; // 05: flop
|
||||
if ( Type == ABC_OPER_RAMR ) return WLC_OBJ_READ; // 54: read port
|
||||
if ( Type == ABC_OPER_RAMW ) return WLC_OBJ_WRITE; // 55: write port
|
||||
return -1;
|
||||
}
|
||||
int Ndr_TypeWlc2Ndr( int Type )
|
||||
|
|
@ -142,6 +148,12 @@ int Ndr_TypeWlc2Ndr( int Type )
|
|||
if ( Type == WLC_OBJ_ARI_MINUS ) return ABC_OPER_ARI_MIN; // 50: arithmetic minus
|
||||
if ( Type == WLC_OBJ_ARI_SQRT ) return ABC_OPER_ARI_SQRT; // 51: integer square root
|
||||
if ( Type == WLC_OBJ_ARI_SQUARE ) return ABC_OPER_ARI_SQUARE; // 52: integer square
|
||||
if ( Type == WLC_OBJ_ARI_ADDSUB ) return ABC_OPER_ARI_ADDSUB; // 56: adder-subtractor
|
||||
if ( Type == WLC_OBJ_ARI_MULTI ) return ABC_OPER_ARI_SMUL; // 45: signed multiplier
|
||||
if ( Type == WLC_OBJ_FO ) return ABC_OPER_DFF; // 03: flop
|
||||
if ( Type == WLC_OBJ_FF ) return ABC_OPER_DFFRSE; // 05: flop
|
||||
if ( Type == WLC_OBJ_READ ) return ABC_OPER_RAMR; // 54: read port
|
||||
if ( Type == WLC_OBJ_WRITE ) return ABC_OPER_RAMW; // 55: write port
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -337,6 +349,7 @@ Wlc_Ntk_t * Wlc_NtkFromNdr( void * pData )
|
|||
int Mod = 2, i, k, Obj, * pArray, nDigits, fFound, NameId, NameIdMax;
|
||||
Wlc_Ntk_t * pTemp, * pNtk = Wlc_NtkAlloc( "top", Ndr_DataObjNum(p, Mod)+1 );
|
||||
Wlc_NtkCheckIntegrity( pData );
|
||||
Vec_IntClear( &pNtk->vFfs );
|
||||
//pNtk->pSpec = Abc_UtilStrsav( pFileName );
|
||||
// construct network and save name IDs
|
||||
Wlc_NtkCleanNameId( pNtk );
|
||||
|
|
@ -357,6 +370,25 @@ Wlc_Ntk_t * Wlc_NtkFromNdr( void * pData )
|
|||
int NameId = Ndr_ObjReadBody( p, Obj, NDR_OUTPUT );
|
||||
Vec_IntClear( vFanins );
|
||||
Vec_IntAppend( vFanins, vTemp );
|
||||
if ( Type == ABC_OPER_DFF )
|
||||
{
|
||||
// save init state
|
||||
if ( pNtk->vInits == NULL )
|
||||
pNtk->vInits = Vec_IntAlloc( 100 );
|
||||
if ( Vec_IntSize(vFanins) == 2 )
|
||||
Vec_IntPush( pNtk->vInits, Vec_IntPop(vFanins) );
|
||||
else // assume const0 if init is not given
|
||||
Vec_IntPush( pNtk->vInits, -(End-Beg+1) );
|
||||
// save flop output
|
||||
pObj = Wlc_NtkObj(pNtk, iObj);
|
||||
assert( Wlc_ObjType(pObj) == WLC_OBJ_FO );
|
||||
Wlc_ObjSetNameId( pNtk, iObj, NameId );
|
||||
Vec_IntPush( &pNtk->vFfs, NameId );
|
||||
// save flop input
|
||||
assert( Vec_IntSize(vFanins) == 1 );
|
||||
Vec_IntPush( &pNtk->vFfs, Vec_IntEntry(vFanins, 0) );
|
||||
continue;
|
||||
}
|
||||
if ( Type == ABC_OPER_SLICE )
|
||||
Vec_IntPushTwo( vFanins, End, Beg );
|
||||
else if ( Type == ABC_OPER_CONST )
|
||||
|
|
@ -365,6 +397,13 @@ Wlc_Ntk_t * Wlc_NtkFromNdr( void * pData )
|
|||
ABC_SWAP( int, Vec_IntEntryP(vFanins, 1)[0], Vec_IntEntryP(vFanins, 2)[0] );
|
||||
Wlc_ObjAddFanins( pNtk, Wlc_NtkObj(pNtk, iObj), vFanins );
|
||||
Wlc_ObjSetNameId( pNtk, iObj, NameId );
|
||||
if ( Type == ABC_OPER_ARI_SMUL )
|
||||
{
|
||||
pObj = Wlc_NtkObj(pNtk, iObj);
|
||||
assert( Wlc_ObjFaninNum(pObj) == 2 );
|
||||
Wlc_ObjFanin0(pNtk, pObj)->Signed = 1;
|
||||
Wlc_ObjFanin1(pNtk, pObj)->Signed = 1;
|
||||
}
|
||||
}
|
||||
// mark primary outputs
|
||||
Ndr_ModForEachPo( p, Mod, Obj )
|
||||
|
|
@ -388,6 +427,27 @@ Wlc_Ntk_t * Wlc_NtkFromNdr( void * pData )
|
|||
for ( k = 0; k < Wlc_ObjFaninNum(pObj); k++ )
|
||||
pFanins[k] = Vec_IntEntry(vName2Obj, pFanins[k]);
|
||||
}
|
||||
if ( pNtk->vInits )
|
||||
{
|
||||
Vec_IntForEachEntry( &pNtk->vFfs, NameId, i )
|
||||
Vec_IntWriteEntry( &pNtk->vFfs, i, Vec_IntEntry(vName2Obj, NameId) );
|
||||
Vec_IntForEachEntry( pNtk->vInits, NameId, i )
|
||||
if ( NameId > 0 )
|
||||
Vec_IntWriteEntry( pNtk->vInits, i, Vec_IntEntry(vName2Obj, NameId) );
|
||||
// move FO/FI to be part of CI/CO
|
||||
assert( (Vec_IntSize(&pNtk->vFfs) & 1) == 0 );
|
||||
assert( Vec_IntSize(&pNtk->vFfs) == 2 * Vec_IntSize(pNtk->vInits) );
|
||||
Wlc_NtkForEachFf( pNtk, pObj, i )
|
||||
if ( i & 1 )
|
||||
Wlc_ObjSetCo( pNtk, pObj, 1 );
|
||||
//else
|
||||
// Wlc_ObjSetCi( pNtk, pObj );
|
||||
Vec_IntClear( &pNtk->vFfs );
|
||||
// convert init values into binary string
|
||||
//Vec_IntPrint( &p->pNtk->vInits );
|
||||
pNtk->pInits = Wlc_PrsConvertInitValues( pNtk );
|
||||
//printf( "%s", p->pNtk->pInits );
|
||||
}
|
||||
Vec_IntFree(vName2Obj);
|
||||
// create fake object names
|
||||
NameIdMax = Vec_IntFindMax(&pNtk->vNameIds);
|
||||
|
|
@ -395,14 +455,17 @@ Wlc_Ntk_t * Wlc_NtkFromNdr( void * pData )
|
|||
pNtk->pManName = Abc_NamStart( NameIdMax+1, 10 );
|
||||
for ( i = 1; i <= NameIdMax; i++ )
|
||||
{
|
||||
char pName[20]; sprintf( pName, "n%0*d", nDigits, i );
|
||||
char pName[20]; sprintf( pName, "s%0*d", nDigits, i );
|
||||
NameId = Abc_NamStrFindOrAdd( pNtk->pManName, pName, &fFound );
|
||||
assert( !fFound && i == NameId );
|
||||
}
|
||||
//Ndr_NtkPrintNodes( pNtk );
|
||||
// derive topological order
|
||||
pNtk = Wlc_NtkDupDfs( pTemp = pNtk, 0, 1 );
|
||||
Wlc_NtkFree( pTemp );
|
||||
//Ndr_NtkPrintNodes( pNtk );
|
||||
pNtk->fMemPorts = 1; // the network contains memory ports
|
||||
pNtk->fEasyFfs = 1; // the network contains simple flops
|
||||
return pNtk;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -860,6 +860,7 @@ void Wlc_NtkDupDfs_rec( Wlc_Ntk_t * pNew, Wlc_Ntk_t * p, int iObj, Vec_Int_t * v
|
|||
int i, iFanin;
|
||||
if ( Wlc_ObjCopy(p, iObj) )
|
||||
return;
|
||||
//printf( "Visiting node %d\n", iObj );
|
||||
pObj = Wlc_NtkObj( p, iObj );
|
||||
Wlc_ObjForEachFanin( pObj, iFanin, i )
|
||||
Wlc_NtkDupDfs_rec( pNew, p, iFanin, vFanins );
|
||||
|
|
@ -876,6 +877,8 @@ Wlc_Ntk_t * Wlc_NtkDupDfsSimple( Wlc_Ntk_t * p )
|
|||
vFanins = Vec_IntAlloc( 100 );
|
||||
pNew = Wlc_NtkAlloc( p->pName, p->nObjsAlloc );
|
||||
pNew->fSmtLib = p->fSmtLib;
|
||||
pNew->fMemPorts = p->fMemPorts;
|
||||
pNew->fEasyFfs = p->fEasyFfs;
|
||||
Wlc_NtkForEachCi( p, pObj, i )
|
||||
Wlc_ObjDup( pNew, p, Wlc_ObjId(p, pObj), vFanins );
|
||||
Wlc_NtkForEachCo( p, pObj, i )
|
||||
|
|
@ -902,6 +905,8 @@ Wlc_Ntk_t * Wlc_NtkDupDfs( Wlc_Ntk_t * p, int fMarked, int fSeq )
|
|||
Wlc_NtkCleanCopy( p );
|
||||
pNew = Wlc_NtkAlloc( p->pName, p->nObjsAlloc );
|
||||
pNew->fSmtLib = p->fSmtLib;
|
||||
pNew->fMemPorts = p->fMemPorts;
|
||||
pNew->fEasyFfs = p->fEasyFfs;
|
||||
Wlc_NtkForEachCi( p, pObj, i )
|
||||
if ( !fMarked || pObj->Mark )
|
||||
{
|
||||
|
|
@ -951,6 +956,8 @@ Wlc_Ntk_t * Wlc_NtkDupDfsAbs( Wlc_Ntk_t * p, Vec_Int_t * vPisOld, Vec_Int_t * vP
|
|||
Wlc_NtkCleanCopy( p );
|
||||
pNew = Wlc_NtkAlloc( p->pName, p->nObjsAlloc );
|
||||
pNew->fSmtLib = p->fSmtLib;
|
||||
pNew->fMemPorts = p->fMemPorts;
|
||||
pNew->fEasyFfs = p->fEasyFfs;
|
||||
|
||||
// duplicate marked PIs
|
||||
vFanins = Vec_IntAlloc( 100 );
|
||||
|
|
@ -1132,6 +1139,8 @@ Wlc_Ntk_t * Wlc_NtkDupSingleNodes( Wlc_Ntk_t * p )
|
|||
vFanins = Vec_IntAlloc( 100 );
|
||||
pNew = Wlc_NtkAlloc( p->pName, p->nObjsAlloc );
|
||||
pNew->fSmtLib = p->fSmtLib;
|
||||
pNew->fMemPorts = p->fMemPorts;
|
||||
pNew->fEasyFfs = p->fEasyFfs;
|
||||
Wlc_NtkForEachObj( p, pObj, i )
|
||||
{
|
||||
if ( Wlc_ObjIsCi(pObj) )
|
||||
|
|
|
|||
|
|
@ -1275,6 +1275,123 @@ startword:
|
|||
// printf( "Created flop %s with range %d and init value %d (nameId = %d)\n",
|
||||
// Abc_NamStr(p->pNtk->pManName, NameIdOut), Wlc_ObjRange(pObj), nBits, NameId );
|
||||
}
|
||||
else if ( Wlc_PrsStrCmp( pStart, "ABC_DFFRSE" ) )
|
||||
{
|
||||
int NameId[8], fFound, nBits = 1, fFlopIn, fFlopOut, fFlopClk, fFlopRst, fFlopSet, fFlopEna, fFlopAsync, fFlopInit;
|
||||
pStart += strlen("ABC_DFF");
|
||||
while ( 1 )
|
||||
{
|
||||
pStart = Wlc_PrsFindSymbol( pStart, '.' );
|
||||
if ( pStart == NULL )
|
||||
break;
|
||||
pStart = Wlc_PrsSkipSpaces( pStart+1 );
|
||||
fFlopIn = (pStart[0] == 'd');
|
||||
fFlopOut = (pStart[0] == 'q');
|
||||
fFlopClk = (pStart[0] == 'c');
|
||||
fFlopRst = (pStart[0] == 'r');
|
||||
fFlopSet = (pStart[0] == 's');
|
||||
fFlopEna = (pStart[0] == 'e');
|
||||
fFlopAsync = (pStart[0] == 'a');
|
||||
fFlopInit = (pStart[0] == 'i');
|
||||
pStart = Wlc_PrsFindSymbol( pStart, '(' );
|
||||
if ( pStart == NULL )
|
||||
return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read opening parenthesis in the flop description." );
|
||||
pStart = Wlc_PrsFindName( pStart+1, &pName );
|
||||
if ( pStart == NULL )
|
||||
return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read name inside flop description." );
|
||||
if ( fFlopIn )
|
||||
NameId[0] = Abc_NamStrFindOrAdd( p->pNtk->pManName, pName, &fFound );
|
||||
else if ( fFlopOut )
|
||||
NameId[7] = Abc_NamStrFindOrAdd( p->pNtk->pManName, pName, &fFound );
|
||||
else if ( fFlopClk )
|
||||
NameId[1] = Abc_NamStrFindOrAdd( p->pNtk->pManName, pName, &fFound );
|
||||
else if ( fFlopRst )
|
||||
NameId[2] = Abc_NamStrFindOrAdd( p->pNtk->pManName, pName, &fFound );
|
||||
else if ( fFlopSet )
|
||||
NameId[3] = Abc_NamStrFindOrAdd( p->pNtk->pManName, pName, &fFound );
|
||||
else if ( fFlopEna )
|
||||
NameId[4] = Abc_NamStrFindOrAdd( p->pNtk->pManName, pName, &fFound );
|
||||
else if ( fFlopAsync )
|
||||
NameId[5] = Abc_NamStrFindOrAdd( p->pNtk->pManName, pName, &fFound );
|
||||
else if ( fFlopInit )
|
||||
NameId[6] = Abc_NamStrFindOrAdd( p->pNtk->pManName, pName, &fFound );
|
||||
else
|
||||
assert( 0 );
|
||||
if ( !fFound )
|
||||
return Wlc_PrsWriteErrorMessage( p, pStart, "Name %s is not declared.", pName );
|
||||
}
|
||||
if ( NameId[0] == -1 || NameId[7] == -1 )
|
||||
return Wlc_PrsWriteErrorMessage( p, pStart, "Name of flop input or flop output is missing." );
|
||||
// create output
|
||||
pObj = Wlc_NtkObj( p->pNtk, NameId[7] );
|
||||
Wlc_ObjUpdateType( p->pNtk, pObj, WLC_OBJ_FF );
|
||||
Vec_IntClear( p->vFanins );
|
||||
Vec_IntPush( p->vFanins, NameId[0] );
|
||||
Vec_IntPush( p->vFanins, NameId[1] );
|
||||
Vec_IntPush( p->vFanins, NameId[2] );
|
||||
Vec_IntPush( p->vFanins, NameId[3] );
|
||||
Vec_IntPush( p->vFanins, NameId[4] );
|
||||
Vec_IntPush( p->vFanins, NameId[5] );
|
||||
Vec_IntPush( p->vFanins, NameId[6] );
|
||||
Wlc_ObjAddFanins( p->pNtk, pObj, p->vFanins );
|
||||
}
|
||||
else if ( Wlc_PrsStrCmp( pStart, "ABC_DFF" ) )
|
||||
{
|
||||
int NameId = -1, NameIdIn = -1, NameIdOut = -1, fFound, nBits = 1, fFlopIn, fFlopOut;
|
||||
pStart += strlen("ABC_DFFRSE");
|
||||
while ( 1 )
|
||||
{
|
||||
pStart = Wlc_PrsFindSymbol( pStart, '.' );
|
||||
if ( pStart == NULL )
|
||||
break;
|
||||
pStart = Wlc_PrsSkipSpaces( pStart+1 );
|
||||
fFlopIn = (pStart[0] == 'd');
|
||||
fFlopOut = (pStart[0] == 'q');
|
||||
pStart = Wlc_PrsFindSymbol( pStart, '(' );
|
||||
if ( pStart == NULL )
|
||||
return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read opening parenthesis in the flop description." );
|
||||
pStart = Wlc_PrsFindName( pStart+1, &pName );
|
||||
if ( pStart == NULL )
|
||||
return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read name inside flop description." );
|
||||
if ( fFlopIn )
|
||||
NameIdIn = Abc_NamStrFindOrAdd( p->pNtk->pManName, pName, &fFound );
|
||||
else if ( fFlopOut )
|
||||
NameIdOut = Abc_NamStrFindOrAdd( p->pNtk->pManName, pName, &fFound );
|
||||
else
|
||||
NameId = Abc_NamStrFindOrAdd( p->pNtk->pManName, pName, &fFound );
|
||||
if ( !fFound )
|
||||
return Wlc_PrsWriteErrorMessage( p, pStart, "Name %s is not declared.", pName );
|
||||
}
|
||||
if ( NameIdIn == -1 || NameIdOut == -1 )
|
||||
return Wlc_PrsWriteErrorMessage( p, pStart, "Name of flop input or flop output is missing." );
|
||||
// create flop output
|
||||
pObj = Wlc_NtkObj( p->pNtk, NameIdOut );
|
||||
Wlc_ObjUpdateType( p->pNtk, pObj, WLC_OBJ_FO );
|
||||
Vec_IntPush( &p->pNtk->vFfs, NameIdOut );
|
||||
nBits = Wlc_ObjRange(Wlc_NtkObj(p->pNtk, NameIdOut));
|
||||
// create flop input
|
||||
pObj = Wlc_NtkObj( p->pNtk, NameIdIn );
|
||||
Vec_IntPush( &p->pNtk->vFfs, NameIdIn );
|
||||
// compare bit-width
|
||||
if ( Wlc_ObjRange(Wlc_NtkObj(p->pNtk, NameIdIn)) != nBits )
|
||||
printf( "Warning! Flop input \"%s\" bit-width (%d) is different from that of flop output (%d)\n",
|
||||
Abc_NamStr(p->pNtk->pManName, NameId), Wlc_ObjRange(Wlc_NtkObj(p->pNtk, NameIdIn)), nBits );
|
||||
// save flop init value
|
||||
if ( NameId == -1 )
|
||||
printf( "Initial value of flop \"%s\" is not specified. Zero is assumed.\n", Abc_NamStr(p->pNtk->pManName, NameIdOut) );
|
||||
else
|
||||
{
|
||||
if ( Wlc_ObjRange(Wlc_NtkObj(p->pNtk, NameId)) != nBits )
|
||||
printf( "Warning! Flop init signal \"%s\" bit-width (%d) is different from that of flop output (%d)\n",
|
||||
Abc_NamStr(p->pNtk->pManName, NameId), Wlc_ObjRange(Wlc_NtkObj(p->pNtk, NameId)), nBits );
|
||||
}
|
||||
if ( p->pNtk->vInits == NULL )
|
||||
p->pNtk->vInits = Vec_IntAlloc( 100 );
|
||||
Vec_IntPush( p->pNtk->vInits, NameId > 0 ? NameId : -Wlc_ObjRange(Wlc_NtkObj(p->pNtk, NameIdOut)) );
|
||||
// printf( "Created flop %s with range %d and init value %d (nameId = %d)\n",
|
||||
// Abc_NamStr(p->pNtk->pManName, NameIdOut), Wlc_ObjRange(pObj), nBits, NameId );
|
||||
p->pNtk->fEasyFfs = 1;
|
||||
}
|
||||
else if ( Wlc_PrsStrCmp( pStart, "CPL_MEM_" ) )
|
||||
{
|
||||
int * pNameId = NULL, NameOutput, NameMi = -1, NameMo = -1, NameAddr = -1, NameDi = -1, NameDo = -1, fFound, fRead = 1;
|
||||
|
|
@ -1324,6 +1441,87 @@ startword:
|
|||
//printf( "Memory %s ", fRead ? "Read" : "Write" ); printf( "Fanins: " ); Vec_IntPrint( p->vFanins );
|
||||
Wlc_ObjAddFanins( p->pNtk, pObj, p->vFanins );
|
||||
}
|
||||
else if ( Wlc_PrsStrCmp( pStart, "ABC_READ" ) )
|
||||
{
|
||||
int * pNameId = NULL, NameMemIn = -1, NameData = -1, NameAddr = -1, fFound;
|
||||
pStart += strlen("ABC_READ");
|
||||
while ( 1 )
|
||||
{
|
||||
pStart = Wlc_PrsFindSymbol( pStart, '.' );
|
||||
if ( pStart == NULL )
|
||||
break;
|
||||
pStart = Wlc_PrsSkipSpaces( pStart+1 );
|
||||
if ( !strncmp(pStart, "mem_in", 6) )
|
||||
pNameId = &NameMemIn;
|
||||
else if ( !strncmp(pStart, "addr", 4) )
|
||||
pNameId = &NameAddr;
|
||||
else if ( !strncmp(pStart, "data", 4) )
|
||||
pNameId = &NameData;
|
||||
else
|
||||
return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read name of the input/output port." );
|
||||
pStart = Wlc_PrsFindSymbol( pStart, '(' );
|
||||
if ( pStart == NULL )
|
||||
return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read opening parenthesis in the flop description." );
|
||||
pStart = Wlc_PrsFindName( pStart+1, &pName );
|
||||
if ( pStart == NULL )
|
||||
return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read name inside flop description." );
|
||||
*pNameId = Abc_NamStrFindOrAdd( p->pNtk->pManName, pName, &fFound );
|
||||
if ( !fFound )
|
||||
return Wlc_PrsWriteErrorMessage( p, pStart, "Name %s is not declared.", pName );
|
||||
}
|
||||
if ( NameMemIn == -1 || NameAddr == -1 || NameData == -1 )
|
||||
return Wlc_PrsWriteErrorMessage( p, pStart, "Name of one of signals of read port is missing." );
|
||||
// create output
|
||||
pObj = Wlc_NtkObj( p->pNtk, NameData );
|
||||
Wlc_ObjUpdateType( p->pNtk, pObj, WLC_OBJ_READ );
|
||||
Vec_IntClear( p->vFanins );
|
||||
Vec_IntPush( p->vFanins, NameMemIn );
|
||||
Vec_IntPush( p->vFanins, NameAddr );
|
||||
Wlc_ObjAddFanins( p->pNtk, pObj, p->vFanins );
|
||||
p->pNtk->fMemPorts = 1;
|
||||
}
|
||||
else if ( Wlc_PrsStrCmp( pStart, "ABC_WRITE" ) )
|
||||
{
|
||||
int * pNameId = NULL, NameMemIn = -1, NameMemOut = -1, NameData = -1, NameAddr = -1, fFound;
|
||||
pStart += strlen("ABC_WRITE");
|
||||
while ( 1 )
|
||||
{
|
||||
pStart = Wlc_PrsFindSymbol( pStart, '.' );
|
||||
if ( pStart == NULL )
|
||||
break;
|
||||
pStart = Wlc_PrsSkipSpaces( pStart+1 );
|
||||
if ( !strncmp(pStart, "mem_in", 6) )
|
||||
pNameId = &NameMemIn;
|
||||
else if ( !strncmp(pStart, "mem_out", 7) )
|
||||
pNameId = &NameMemOut;
|
||||
else if ( !strncmp(pStart, "data", 4) )
|
||||
pNameId = &NameData;
|
||||
else if ( !strncmp(pStart, "addr", 4) )
|
||||
pNameId = &NameAddr;
|
||||
else
|
||||
return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read name of the input/output port." );
|
||||
pStart = Wlc_PrsFindSymbol( pStart, '(' );
|
||||
if ( pStart == NULL )
|
||||
return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read opening parenthesis in the flop description." );
|
||||
pStart = Wlc_PrsFindName( pStart+1, &pName );
|
||||
if ( pStart == NULL )
|
||||
return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read name inside flop description." );
|
||||
*pNameId = Abc_NamStrFindOrAdd( p->pNtk->pManName, pName, &fFound );
|
||||
if ( !fFound )
|
||||
return Wlc_PrsWriteErrorMessage( p, pStart, "Name %s is not declared.", pName );
|
||||
}
|
||||
if ( NameMemIn == -1 || NameAddr == -1 || NameData == -1 || NameMemOut == -1 )
|
||||
return Wlc_PrsWriteErrorMessage( p, pStart, "Name of one of signals of write port is missing." );
|
||||
// create output
|
||||
pObj = Wlc_NtkObj( p->pNtk, NameMemOut );
|
||||
Wlc_ObjUpdateType( p->pNtk, pObj, WLC_OBJ_WRITE );
|
||||
Vec_IntClear( p->vFanins );
|
||||
Vec_IntPush( p->vFanins, NameMemIn );
|
||||
Vec_IntPush( p->vFanins, NameAddr );
|
||||
Vec_IntPush( p->vFanins, NameData );
|
||||
Wlc_ObjAddFanins( p->pNtk, pObj, p->vFanins );
|
||||
p->pNtk->fMemPorts = 1;
|
||||
}
|
||||
else if ( pStart[0] == '(' && pStart[1] == '*' ) // skip comments
|
||||
{
|
||||
while ( *pStart++ != ')' );
|
||||
|
|
|
|||
|
|
@ -186,13 +186,13 @@ void Wlc_WriteVerInt( FILE * pFile, Wlc_Ntk_t * p, int fNoFlops )
|
|||
continue;
|
||||
Range[0] = 0;
|
||||
}
|
||||
if ( pObj->fIsPo || (fNoFlops && pObj->fIsFi) )
|
||||
if ( (pObj->fIsPo || (fNoFlops && pObj->fIsFi)) && pObj->Type != WLC_OBJ_FF )
|
||||
{
|
||||
if ( Wlc_ObjFaninNum(pObj) == 0 )
|
||||
continue;
|
||||
fprintf( pFile, " assign " );
|
||||
}
|
||||
else if ( pObj->Type == WLC_OBJ_MUX && Wlc_ObjFaninNum(pObj) > 3 )
|
||||
else if ( (pObj->Type == WLC_OBJ_MUX && Wlc_ObjFaninNum(pObj) > 3) || pObj->Type == WLC_OBJ_FF )
|
||||
fprintf( pFile, "reg %s ", Range );
|
||||
else
|
||||
fprintf( pFile, "wire %s ", Range );
|
||||
|
|
@ -255,17 +255,41 @@ void Wlc_WriteVerInt( FILE * pFile, Wlc_Ntk_t * p, int fNoFlops )
|
|||
}
|
||||
else if ( pObj->Type == WLC_OBJ_READ || pObj->Type == WLC_OBJ_WRITE )
|
||||
{
|
||||
int nBitsMem = Wlc_ObjRange( Wlc_ObjFanin(p, pObj, 0) );
|
||||
//int nBitsAddr = Wlc_ObjRange( Wlc_ObjFanin(p, pObj, 1) );
|
||||
int nBitsDat = pObj->Type == WLC_OBJ_READ ? Wlc_ObjRange(pObj) : Wlc_ObjRange(Wlc_ObjFanin(p, pObj, 2));
|
||||
int Depth = nBitsMem / nBitsDat;
|
||||
assert( nBitsMem % nBitsDat == 0 );
|
||||
if ( p->fMemPorts )
|
||||
{
|
||||
fprintf( pFile, "%s ;\n", Wlc_ObjName(p, i) );
|
||||
fprintf( pFile, " " );
|
||||
fprintf( pFile, "%s (", pObj->Type == WLC_OBJ_READ ? "ABC_READ" : "ABC_WRITE" );
|
||||
Wlc_ObjForEachFanin( pObj, iFanin, k )
|
||||
fprintf( pFile, " .%s(%s)", k==0 ? "mem_in" : (k==1 ? "addr": "data"), Wlc_ObjName(p, iFanin) );
|
||||
fprintf( pFile, " .%s(%s) ) ;\n", pObj->Type == WLC_OBJ_READ ? "data" : "mem_out", Wlc_ObjName(p, i) );
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
int nBitsMem = Wlc_ObjRange( Wlc_ObjFanin(p, pObj, 0) );
|
||||
//int nBitsAddr = Wlc_ObjRange( Wlc_ObjFanin(p, pObj, 1) );
|
||||
int nBitsDat = pObj->Type == WLC_OBJ_READ ? Wlc_ObjRange(pObj) : Wlc_ObjRange(Wlc_ObjFanin(p, pObj, 2));
|
||||
int Depth = nBitsMem / nBitsDat;
|
||||
assert( nBitsMem % nBitsDat == 0 );
|
||||
fprintf( pFile, "%s ;\n", Wlc_ObjName(p, i) );
|
||||
fprintf( pFile, " " );
|
||||
fprintf( pFile, "%s_%d (", pObj->Type == WLC_OBJ_READ ? "CPL_MEM_READ" : "CPL_MEM_WRITE", Depth );
|
||||
Wlc_ObjForEachFanin( pObj, iFanin, k )
|
||||
fprintf( pFile, " .%s(%s)", k==0 ? "mem_data_in" : (k==1 ? "addr_in": "data_in"), Wlc_ObjName(p, iFanin) );
|
||||
fprintf( pFile, " .%s(%s) ) ;\n", "data_out", Wlc_ObjName(p, i) );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if ( pObj->Type == WLC_OBJ_FF )
|
||||
{
|
||||
char * pInNames[7] = {"d", "clk", "reset", "set", "enable", "async", "init"};
|
||||
fprintf( pFile, "%s ;\n", Wlc_ObjName(p, i) );
|
||||
fprintf( pFile, " " );
|
||||
fprintf( pFile, "%s_%d (", pObj->Type == WLC_OBJ_READ ? "CPL_MEM_READ" : "CPL_MEM_WRITE", Depth );
|
||||
fprintf( pFile, "%s (", "ABC_DFFRSE" );
|
||||
Wlc_ObjForEachFanin( pObj, iFanin, k )
|
||||
fprintf( pFile, " .%s(%s)", k==0 ? "mem_data_in" : (k==1 ? "addr_in": "data_in"), Wlc_ObjName(p, iFanin) );
|
||||
fprintf( pFile, " .%s(%s) );\n", "data_out", Wlc_ObjName(p, i) );
|
||||
fprintf( pFile, " .%s(%s)", pInNames[k], Wlc_ObjName(p, iFanin) );
|
||||
fprintf( pFile, " .%s(%s) ) ;\n", "q", Wlc_ObjName(p, i) );
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
|
@ -426,22 +450,35 @@ void Wlc_WriteVerInt( FILE * pFile, Wlc_Ntk_t * p, int fNoFlops )
|
|||
if ( pObj->Type == WLC_OBJ_PI )
|
||||
continue;
|
||||
fprintf( pFile, " " );
|
||||
fprintf( pFile, "CPL_FF" );
|
||||
if ( Wlc_ObjRange(pObj) > 1 )
|
||||
fprintf( pFile, "#%d%*s", Wlc_ObjRange(pObj), 4 - Abc_Base10Log(Wlc_ObjRange(pObj)+1), "" );
|
||||
if ( p->fEasyFfs )
|
||||
{
|
||||
fprintf( pFile, "ABC_DFF" );
|
||||
fprintf( pFile, " reg%d (", i );
|
||||
fprintf( pFile, " .q(%s),", Wlc_ObjName(p, Wlc_ObjId(p, pObj)) );
|
||||
fprintf( pFile, " .d(%s),", Wlc_ObjName(p, Wlc_ObjId(p, Wlc_ObjFo2Fi(p, pObj))) );
|
||||
if ( p->vInits )
|
||||
fprintf( pFile, " .init(%s_init)", Wlc_ObjName(p, Wlc_ObjId(p, pObj)) );
|
||||
fprintf( pFile, " ) ;\n" );
|
||||
}
|
||||
else
|
||||
fprintf( pFile, " " );
|
||||
fprintf( pFile, " reg%d (", i );
|
||||
fprintf( pFile, " .q( %s ),", Wlc_ObjName(p, Wlc_ObjId(p, pObj)) );
|
||||
fprintf( pFile, " .qbar()," );
|
||||
fprintf( pFile, " .d( %s ),", Wlc_ObjName(p, Wlc_ObjId(p, Wlc_ObjFo2Fi(p, pObj))) );
|
||||
fprintf( pFile, " .clk( %s ),", "1\'b0" );
|
||||
fprintf( pFile, " .arst( %s ),", "1\'b0" );
|
||||
if ( p->vInits )
|
||||
fprintf( pFile, " .arstval( %s_init )", Wlc_ObjName(p, Wlc_ObjId(p, pObj)) );
|
||||
else
|
||||
fprintf( pFile, " .arstval( %s )", "1\'b0" );
|
||||
fprintf( pFile, " ) ;\n" );
|
||||
{
|
||||
fprintf( pFile, "CPL_FF" );
|
||||
if ( Wlc_ObjRange(pObj) > 1 )
|
||||
fprintf( pFile, "#%d%*s", Wlc_ObjRange(pObj), 4 - Abc_Base10Log(Wlc_ObjRange(pObj)+1), "" );
|
||||
else
|
||||
fprintf( pFile, " " );
|
||||
fprintf( pFile, " reg%d (", i );
|
||||
fprintf( pFile, " .q(%s),", Wlc_ObjName(p, Wlc_ObjId(p, pObj)) );
|
||||
fprintf( pFile, " .qbar()," );
|
||||
fprintf( pFile, " .d(%s),", Wlc_ObjName(p, Wlc_ObjId(p, Wlc_ObjFo2Fi(p, pObj))) );
|
||||
fprintf( pFile, " .clk(%s),", "1\'b0" );
|
||||
fprintf( pFile, " .arst(%s),", "1\'b0" );
|
||||
if ( p->vInits )
|
||||
fprintf( pFile, " .arstval(%s_init)", Wlc_ObjName(p, Wlc_ObjId(p, pObj)) );
|
||||
else
|
||||
fprintf( pFile, " .arstval(%s)", "1\'b0" );
|
||||
fprintf( pFile, " ) ;\n" );
|
||||
}
|
||||
}
|
||||
assert( !p->vInits || iFanin == (int)strlen(p->pInits) );
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue