2018-07-26 12:28:21 -05:00
/**
* Author : Jason Luu
* Date : May 2009
*
* Read a circuit netlist in XML format and populate the netlist data structures for VPR
*/
# include <stdio.h>
# include <string.h>
# include <assert.h>
# include "util.h"
# include "hash.h"
# include "vpr_types.h"
# include "vpr_utils.h"
# include "ReadLine.h"
# include "globals.h"
# include "ezxml.h"
# include "read_xml_util.h"
# include "read_netlist.h"
# include "pb_type_graph.h"
# include "cluster_legality.h"
# include "token.h"
# include "rr_graph.h"
static void processPorts ( INOUTP ezxml_t Parent , INOUTP t_pb * pb ,
INOUTP t_rr_node * rr_graph , INOUTP t_pb * * rr_node_to_pb_mapping , INP struct s_hash * * vpack_net_hash ) ;
static void processPb ( INOUTP ezxml_t Parent , INOUTP t_pb * pb ,
INOUTP t_rr_node * rr_graph , INOUTP t_pb * * rr_node_to_pb_mapping , INOUTP int * num_primitives ,
INP struct s_hash * * vpack_net_hash , INP struct s_hash * * logical_block_hash , INP int cb_index ) ;
static void processComplexBlock ( INOUTP ezxml_t Parent , INOUTP t_block * cb ,
INP int index , INOUTP int * num_primitives , INP const t_arch * arch , INP struct s_hash * * vpack_net_hash , INP struct s_hash * * logical_block_hash ) ;
static struct s_net * alloc_and_init_netlist_from_hash ( INP int ncount ,
INOUTP struct s_hash * * nhash ) ;
static int add_net_to_hash ( INOUTP struct s_hash * * nhash , INP char * net_name ,
INOUTP int * ncount ) ;
static void load_external_nets_and_cb ( INP int L_num_blocks ,
INP struct s_block block_list [ ] , INP int ncount ,
INP struct s_net nlist [ ] , OUTP int * ext_ncount ,
OUTP struct s_net * * ext_nets , INP char * * circuit_clocks ) ;
static void load_internal_cb_nets ( INOUTP t_pb * top_level ,
INP t_pb_graph_node * pb_graph_node , INOUTP t_rr_node * rr_graph ,
INOUTP int * curr_net ) ;
static void alloc_internal_cb_nets ( INOUTP t_pb * top_level ,
INP t_pb_graph_node * pb_graph_node , INOUTP t_rr_node * rr_graph ,
INP int pass ) ;
static void load_internal_cb_rr_graph_net_nums ( INP t_rr_node * cur_rr_node ,
INP t_rr_node * rr_graph , INOUTP struct s_net * nets ,
INOUTP int * curr_net , INOUTP int * curr_sink ) ;
static void mark_constant_generators ( INP int L_num_blocks ,
INP struct s_block block_list [ ] , INP int ncount ,
INOUTP struct s_net nlist [ ] ) ;
static void mark_constant_generators_rec ( INP t_pb * pb , INP t_rr_node * rr_graph ,
INOUTP struct s_net nlist [ ] ) ;
/**
* Initializes the block_list with info from a netlist
* net_file - Name of the netlist file to read
* num_blocks - number of CLBs in netlist
* block_list - array of blocks in netlist [ 0. . num_blocks - 1 ]
* num_nets - number of nets in netlist
* net_list - nets in netlist [ 0. . num_nets - 1 ]
*/
void read_netlist ( INP const char * net_file , INP const t_arch * arch ,
OUTP int * L_num_blocks , OUTP struct s_block * block_list [ ] ,
OUTP int * L_num_nets , OUTP struct s_net * net_list [ ] ) {
ezxml_t Cur , Prev , Top ;
int i ;
const char * Prop ;
int bcount ;
struct s_block * blist ;
int ext_ncount ;
struct s_net * ext_nlist ;
struct s_hash * * vpack_net_hash , * * logical_block_hash , * temp_hash ;
char * * circuit_inputs , * * circuit_outputs , * * circuit_clocks ;
int Count , Len ;
int num_primitives = 0 ;
/* Parse the file */
vpr_printf ( TIO_MESSAGE_INFO , " Begin parsing packed FPGA netlist file. \n " ) ;
Top = ezxml_parse_file ( net_file ) ;
if ( NULL = = Top ) {
vpr_printf ( TIO_MESSAGE_ERROR , " Unable to load netlist file '%s'. \n " , net_file ) ;
exit ( 1 ) ;
}
vpr_printf ( TIO_MESSAGE_INFO , " Finished parsing packed FPGA netlist file. \n " ) ;
/* Root node should be block */
CheckElement ( Top , " block " ) ;
/* Check top-level netlist attributes */
Prop = FindProperty ( Top , " name " , TRUE ) ;
vpr_printf ( TIO_MESSAGE_INFO , " Netlist generated from file '%s'. \n " , Prop ) ;
ezxml_set_attr ( Top , " name " , NULL ) ;
Prop = FindProperty ( Top , " instance " , TRUE ) ;
if ( strcmp ( Prop , " FPGA_packed_netlist[0] " ) ! = 0 ) {
vpr_printf ( TIO_MESSAGE_ERROR , " [Line %d] Expected instance to be \" FPGA_packed_netlist[0] \" , found %s. " ,
Top - > line , Prop ) ;
exit ( 1 ) ;
}
ezxml_set_attr ( Top , " instance " , NULL ) ;
/* Parse top-level netlist I/Os */
Cur = FindElement ( Top , " inputs " , TRUE ) ;
circuit_inputs = GetNodeTokens ( Cur ) ;
FreeNode ( Cur ) ;
Cur = FindElement ( Top , " outputs " , TRUE ) ;
circuit_outputs = GetNodeTokens ( Cur ) ;
FreeNode ( Cur ) ;
Cur = FindElement ( Top , " clocks " , TRUE ) ;
CountTokensInString ( Cur - > txt , & Count , & Len ) ;
if ( Count > 0 ) {
circuit_clocks = GetNodeTokens ( Cur ) ;
} else {
circuit_clocks = NULL ;
}
FreeNode ( Cur ) ;
/* Parse all CLB blocks and all nets*/
bcount = CountChildren ( Top , " block " , 1 ) ;
blist = ( struct s_block * ) my_calloc ( bcount , sizeof ( t_block ) ) ;
/* create quick hash look up for vpack_net and logical_block
Also reset logical block data structure for pb
*/
vpack_net_hash = alloc_hash_table ( ) ;
logical_block_hash = alloc_hash_table ( ) ;
for ( i = 0 ; i < num_logical_nets ; i + + ) {
temp_hash = insert_in_hash_table ( vpack_net_hash , vpack_net [ i ] . name , i ) ;
assert ( temp_hash - > count = = 1 ) ;
}
for ( i = 0 ; i < num_logical_blocks ; i + + ) {
temp_hash = insert_in_hash_table ( logical_block_hash , logical_block [ i ] . name , i ) ;
logical_block [ i ] . pb = NULL ;
assert ( temp_hash - > count = = 1 ) ;
}
/* Prcoess netlist */
Cur = Top - > child ;
i = 0 ;
while ( Cur ) {
if ( 0 = = strcmp ( Cur - > name , " block " ) ) {
CheckElement ( Cur , " block " ) ;
processComplexBlock ( Cur , blist , i , & num_primitives , arch , vpack_net_hash , logical_block_hash ) ;
Prev = Cur ;
Cur = Cur - > next ;
FreeNode ( Prev ) ;
i + + ;
} else {
Cur = Cur - > next ;
}
}
assert ( i = = bcount ) ;
assert ( num_primitives = = num_logical_blocks ) ;
/* Error check */
for ( i = 0 ; i < num_logical_blocks ; i + + ) {
if ( logical_block [ i ] . pb = = NULL ) {
vpr_printf ( TIO_MESSAGE_ERROR , " .blif file and .net file do not match, .net file missing atom %s. \n " ,
logical_block [ i ] . name ) ;
exit ( 1 ) ;
}
}
/* TODO: Add additional check to make sure net connections match */
mark_constant_generators ( bcount , blist , num_logical_nets , vpack_net ) ;
load_external_nets_and_cb ( bcount , blist , num_logical_nets , vpack_net , & ext_ncount ,
& ext_nlist , circuit_clocks ) ;
/* TODO: create this function later
check_top_IO_matches_IO_blocks ( circuit_inputs , circuit_outputs , circuit_clocks , blist , bcount ) ;
*/
FreeTokens ( & circuit_inputs ) ;
2019-06-19 17:15:30 -05:00
if ( circuit_outputs )
FreeTokens ( & circuit_outputs ) ;
2018-07-26 12:28:21 -05:00
if ( circuit_clocks )
FreeTokens ( & circuit_clocks ) ;
FreeNode ( Top ) ;
/* load mapping between external nets and all nets */
/* jluu TODO: Should use local variables here then assign to globals later, clean up later */
clb_to_vpack_net_mapping = ( int * ) my_malloc ( ext_ncount * sizeof ( int ) ) ;
vpack_to_clb_net_mapping = ( int * ) my_malloc ( num_logical_nets * sizeof ( int ) ) ;
for ( i = 0 ; i < num_logical_nets ; i + + ) {
vpack_to_clb_net_mapping [ i ] = OPEN ;
}
for ( i = 0 ; i < ext_ncount ; i + + ) {
temp_hash = get_hash_entry ( vpack_net_hash , ext_nlist [ i ] . name ) ;
assert ( temp_hash ! = NULL ) ;
clb_to_vpack_net_mapping [ i ] = temp_hash - > index ;
vpack_to_clb_net_mapping [ temp_hash - > index ] = i ;
}
/* Return blocks and nets */
* L_num_blocks = bcount ;
* block_list = blist ;
* L_num_nets = ext_ncount ;
* net_list = ext_nlist ;
free_hash_table ( logical_block_hash ) ;
free_hash_table ( vpack_net_hash ) ;
}
/**
* XML parser to populate CLB info and to update nets with the nets of this CLB
* Parent - XML tag for this CLB
* clb - Array of CLBs in the netlist
* index - index of the CLB to allocate and load information into
* vpack_net_hash - hashtable of all nets in blif netlist
* logical_block_hash - hashtable of all atoms in blif netlist
*/
static void processComplexBlock ( INOUTP ezxml_t Parent , INOUTP t_block * cb ,
INP int index , INOUTP int * num_primitives , INP const t_arch * arch , INP struct s_hash * * vpack_net_hash , INP struct s_hash * * logical_block_hash )
{
const char * Prop ;
boolean found ;
int num_tokens = 0 ;
t_token * tokens ;
int i ;
const t_pb_type * pb_type = NULL ;
/* parse cb attributes */
cb [ index ] . pb = ( t_pb * ) my_calloc ( 1 , sizeof ( t_pb ) ) ;
Prop = FindProperty ( Parent , " name " , TRUE ) ;
cb [ index ] . name = my_strdup ( Prop ) ;
cb [ index ] . pb - > name = my_strdup ( Prop ) ;
ezxml_set_attr ( Parent , " name " , NULL ) ;
Prop = FindProperty ( Parent , " instance " , TRUE ) ;
tokens = GetTokensFromString ( Prop , & num_tokens ) ;
ezxml_set_attr ( Parent , " instance " , NULL ) ;
if ( num_tokens ! = 4 | | tokens [ 0 ] . type ! = TOKEN_STRING
| | tokens [ 1 ] . type ! = TOKEN_OPEN_SQUARE_BRACKET
| | tokens [ 2 ] . type ! = TOKEN_INT
| | tokens [ 3 ] . type ! = TOKEN_CLOSE_SQUARE_BRACKET ) {
vpr_printf ( TIO_MESSAGE_ERROR , " [Line %d] Unknown syntax for instance %s in %s. Expected pb_type[instance_number]. \n " ,
Parent - > line , Prop , Parent - > name ) ;
exit ( 1 ) ;
}
assert ( my_atoi ( tokens [ 2 ] . data ) = = index ) ;
found = FALSE ;
for ( i = 0 ; i < num_types ; i + + ) {
if ( strcmp ( type_descriptors [ i ] . name , tokens [ 0 ] . data ) = = 0 ) {
cb [ index ] . type = & type_descriptors [ i ] ;
pb_type = cb [ index ] . type - > pb_type ;
found = TRUE ;
break ;
}
}
if ( ! found ) {
vpr_printf ( TIO_MESSAGE_ERROR , " [Line %d] Unknown cb type %s for cb %s #%d. \n " ,
Parent - > line , Prop , cb [ index ] . name , index ) ;
exit ( 1 ) ;
}
/* Parse all pbs and CB internal nets*/
cb [ index ] . pb - > logical_block = OPEN ;
cb [ index ] . pb - > pb_graph_node = cb [ index ] . type - > pb_graph_head ;
num_rr_nodes = cb [ index ] . pb - > pb_graph_node - > total_pb_pins ;
rr_node = ( t_rr_node * ) my_calloc ( ( num_rr_nodes * 2 ) + cb [ index ] . type - > pb_type - > num_input_pins
+ cb [ index ] . type - > pb_type - > num_output_pins + cb [ index ] . type - > pb_type - > num_clock_pins ,
sizeof ( t_rr_node ) ) ;
alloc_and_load_rr_graph_for_pb_graph_node ( cb [ index ] . pb - > pb_graph_node , arch ,
0 ) ;
cb [ index ] . pb - > rr_node_to_pb_mapping = ( t_pb * * ) my_calloc ( cb [ index ] . type - > pb_graph_head - > total_pb_pins , sizeof ( t_pb * ) ) ;
cb [ index ] . pb - > rr_graph = rr_node ;
Prop = FindProperty ( Parent , " mode " , TRUE ) ;
ezxml_set_attr ( Parent , " mode " , NULL ) ;
found = FALSE ;
for ( i = 0 ; i < pb_type - > num_modes ; i + + ) {
if ( strcmp ( Prop , pb_type - > modes [ i ] . name ) = = 0 ) {
cb [ index ] . pb - > mode = i ;
found = TRUE ;
}
}
if ( ! found ) {
vpr_printf ( TIO_MESSAGE_ERROR , " [Line %d] Unknown mode %s for cb %s #%d. \n " ,
Parent - > line , Prop , cb [ index ] . name , index ) ;
exit ( 1 ) ;
}
processPb ( Parent , cb [ index ] . pb , cb [ index ] . pb - > rr_graph , cb [ index ] . pb - > rr_node_to_pb_mapping , num_primitives , vpack_net_hash , logical_block_hash , index ) ;
cb [ index ] . nets = ( int * ) my_malloc ( cb [ index ] . type - > num_pins * sizeof ( int ) ) ;
for ( i = 0 ; i < cb [ index ] . type - > num_pins ; i + + ) {
cb [ index ] . nets [ i ] = OPEN ;
}
alloc_internal_cb_nets ( cb [ index ] . pb , cb [ index ] . pb - > pb_graph_node ,
cb [ index ] . pb - > rr_graph , 1 ) ;
alloc_internal_cb_nets ( cb [ index ] . pb , cb [ index ] . pb - > pb_graph_node ,
cb [ index ] . pb - > rr_graph , 2 ) ;
i = 0 ;
load_internal_cb_nets ( cb [ index ] . pb , cb [ index ] . pb - > pb_graph_node ,
cb [ index ] . pb - > rr_graph , & i ) ;
freeTokens ( tokens , num_tokens ) ;
#if 0
/* print local nets */
for ( i = 0 ; i < cb [ index ] . pb - > num_local_nets ; i + + ) {
vpr_printf ( TIO_MESSAGE_INFO , " local net %s: " , cb [ index ] . pb - > name ) ;
for ( j = 0 ; j < = cb [ index ] . pb - > local_nets [ i ] . num_sinks ; j + + ) {
vpr_printf ( TIO_MESSAGE_INFO , " %d " , cb [ index ] . pb - > local_nets [ i ] . node_block [ j ] ) ;
}
vpr_printf ( TIO_MESSAGE_INFO , " \n " ) ;
}
# endif
}
/**
* XML parser to populate pb info and to update internal nets of the parent CLB
* Parent - XML tag for this pb_type
* pb - physical block to use
* vpack_net_hash - hashtable of original blif net names and indices
* logical_block_hash - hashtable of original blif atom names and indices
*/
static void processPb ( INOUTP ezxml_t Parent , INOUTP t_pb * pb ,
INOUTP t_rr_node * rr_graph , INOUTP t_pb * * rr_node_to_pb_mapping , INOUTP int * num_primitives ,
INP struct s_hash * * vpack_net_hash , INP struct s_hash * * logical_block_hash , INP int cb_index ) {
ezxml_t Cur , Prev , lookahead ;
const char * Prop ;
const char * instance_type ;
int i , j , pb_index ;
boolean found ;
const t_pb_type * pb_type ;
t_token * tokens ;
int num_tokens ;
struct s_hash * temp_hash ;
Cur = FindElement ( Parent , " inputs " , TRUE ) ;
processPorts ( Cur , pb , rr_graph , rr_node_to_pb_mapping , vpack_net_hash ) ;
FreeNode ( Cur ) ;
Cur = FindElement ( Parent , " outputs " , TRUE ) ;
processPorts ( Cur , pb , rr_graph , rr_node_to_pb_mapping , vpack_net_hash ) ;
FreeNode ( Cur ) ;
Cur = FindElement ( Parent , " clocks " , TRUE ) ;
processPorts ( Cur , pb , rr_graph , rr_node_to_pb_mapping , vpack_net_hash ) ;
FreeNode ( Cur ) ;
pb_type = pb - > pb_graph_node - > pb_type ;
if ( pb_type - > num_modes = = 0 ) {
/* LUT specific optimizations */
if ( strcmp ( pb_type - > blif_model , " .names " ) = = 0 ) {
pb - > lut_pin_remap = ( int * ) my_malloc ( pb_type - > num_input_pins * sizeof ( int ) ) ;
for ( i = 0 ; i < pb_type - > num_input_pins ; i + + ) {
pb - > lut_pin_remap [ i ] = OPEN ;
}
} else {
pb - > lut_pin_remap = NULL ;
}
temp_hash = get_hash_entry ( logical_block_hash , pb - > name ) ;
if ( temp_hash = = NULL ) {
vpr_printf ( TIO_MESSAGE_ERROR , " .net file and .blif file do not match, encountered unknown primitive %s in .net file. \n " , pb - > name ) ;
exit ( 1 ) ;
}
pb - > logical_block = temp_hash - > index ;
assert ( logical_block [ temp_hash - > index ] . pb = = NULL ) ;
logical_block [ temp_hash - > index ] . pb = pb ;
logical_block [ temp_hash - > index ] . clb_index = cb_index ;
( * num_primitives ) + + ;
} else {
/* process children of child if exists */
pb - > child_pbs = ( t_pb * * ) my_calloc ( pb_type - > modes [ pb - > mode ] . num_pb_type_children ,
sizeof ( t_pb * ) ) ;
for ( i = 0 ; i < pb_type - > modes [ pb - > mode ] . num_pb_type_children ; i + + ) {
pb - > child_pbs [ i ] = ( t_pb * ) my_calloc (
pb_type - > modes [ pb - > mode ] . pb_type_children [ i ] . num_pb ,
sizeof ( t_pb ) ) ;
for ( j = 0 ; j < pb_type - > modes [ pb - > mode ] . pb_type_children [ i ] . num_pb ; j + + ) {
pb - > child_pbs [ i ] [ j ] . logical_block = OPEN ;
}
}
/* Populate info for each physical block */
Cur = Parent - > child ;
while ( Cur ) {
if ( 0 = = strcmp ( Cur - > name , " block " ) ) {
CheckElement ( Cur , " block " ) ;
instance_type = FindProperty ( Cur , " instance " , TRUE ) ;
tokens = GetTokensFromString ( instance_type , & num_tokens ) ;
ezxml_set_attr ( Cur , " instance " , NULL ) ;
if ( num_tokens ! = 4 | | tokens [ 0 ] . type ! = TOKEN_STRING
| | tokens [ 1 ] . type ! = TOKEN_OPEN_SQUARE_BRACKET
| | tokens [ 2 ] . type ! = TOKEN_INT
| | tokens [ 3 ] . type ! = TOKEN_CLOSE_SQUARE_BRACKET ) {
vpr_printf ( TIO_MESSAGE_ERROR , " [Line %d] Unknown syntax for instance %s in %s. Expected pb_type[instance_number]. \n " ,
Cur - > line , instance_type , Cur - > name ) ;
exit ( 1 ) ;
}
found = FALSE ;
pb_index = OPEN ;
for ( i = 0 ; i < pb_type - > modes [ pb - > mode ] . num_pb_type_children ;
i + + ) {
if ( strcmp (
pb_type - > modes [ pb - > mode ] . pb_type_children [ i ] . name ,
tokens [ 0 ] . data ) = = 0 ) {
if ( my_atoi ( tokens [ 2 ] . data )
> = pb_type - > modes [ pb - > mode ] . pb_type_children [ i ] . num_pb ) {
vpr_printf ( TIO_MESSAGE_ERROR , " [Line %d] Instance number exceeds # of pb available for instance %s in %s. \n " ,
Cur - > line , instance_type , Cur - > name ) ;
exit ( 1 ) ;
}
pb_index = my_atoi ( tokens [ 2 ] . data ) ;
if ( pb - > child_pbs [ i ] [ pb_index ] . pb_graph_node ! = NULL ) {
vpr_printf ( TIO_MESSAGE_ERROR , " [Line %d] node is used by two different blocks %s and %s. \n " ,
Cur - > line , instance_type ,
pb - > child_pbs [ i ] [ pb_index ] . name ) ;
exit ( 1 ) ;
}
pb - > child_pbs [ i ] [ pb_index ] . pb_graph_node =
& pb - > pb_graph_node - > child_pb_graph_nodes [ pb - > mode ] [ i ] [ pb_index ] ;
found = TRUE ;
break ;
}
}
if ( ! found ) {
vpr_printf ( TIO_MESSAGE_ERROR , " [Line %d] Unknown pb type %s. \n " ,
Cur - > line , instance_type ) ;
exit ( 1 ) ;
}
Prop = FindProperty ( Cur , " name " , TRUE ) ;
ezxml_set_attr ( Cur , " name " , NULL ) ;
if ( 0 ! = strcmp ( Prop , " open " ) ) {
pb - > child_pbs [ i ] [ pb_index ] . name = my_strdup ( Prop ) ;
/* Parse all pbs and CB internal nets*/
pb - > child_pbs [ i ] [ pb_index ] . logical_block = OPEN ;
Prop = FindProperty ( Cur , " mode " , FALSE ) ;
if ( Prop ) {
ezxml_set_attr ( Cur , " mode " , NULL ) ;
}
pb - > child_pbs [ i ] [ pb_index ] . mode = 0 ;
found = FALSE ;
for ( j = 0 ;
j
< pb - > child_pbs [ i ] [ pb_index ] . pb_graph_node - > pb_type - > num_modes ;
j + + ) {
if ( strcmp ( Prop ,
pb - > child_pbs [ i ] [ pb_index ] . pb_graph_node - > pb_type - > modes [ j ] . name )
= = 0 ) {
pb - > child_pbs [ i ] [ pb_index ] . mode = j ;
found = TRUE ;
}
}
if ( ! found
& & pb - > child_pbs [ i ] [ pb_index ] . pb_graph_node - > pb_type - > num_modes
! = 0 ) {
vpr_printf ( TIO_MESSAGE_ERROR , " [Line %d] Unknown mode %s for cb %s #%d. \n " ,
Cur - > line , Prop , pb - > child_pbs [ i ] [ pb_index ] . name , pb_index ) ;
exit ( 1 ) ;
}
pb - > child_pbs [ i ] [ pb_index ] . parent_pb = pb ;
pb - > child_pbs [ i ] [ pb_index ] . rr_graph = pb - > rr_graph ;
processPb ( Cur , & pb - > child_pbs [ i ] [ pb_index ] , rr_graph , rr_node_to_pb_mapping , num_primitives , vpack_net_hash , logical_block_hash , cb_index ) ;
} else {
/* physical block has no used primitives but it may have used routing */
pb - > child_pbs [ i ] [ pb_index ] . name = NULL ;
pb - > child_pbs [ i ] [ pb_index ] . logical_block = OPEN ;
lookahead = FindElement ( Cur , " outputs " , FALSE ) ;
if ( lookahead ! = NULL ) {
lookahead = FindFirstElement ( lookahead , " port " , TRUE ) ;
Prop = FindProperty ( Cur , " mode " , FALSE ) ;
if ( Prop ) {
ezxml_set_attr ( Cur , " mode " , NULL ) ;
}
pb - > child_pbs [ i ] [ pb_index ] . mode = 0 ;
found = FALSE ;
for ( j = 0 ;
j
< pb - > child_pbs [ i ] [ pb_index ] . pb_graph_node - > pb_type - > num_modes ;
j + + ) {
if ( strcmp ( Prop ,
pb - > child_pbs [ i ] [ pb_index ] . pb_graph_node - > pb_type - > modes [ j ] . name )
= = 0 ) {
pb - > child_pbs [ i ] [ pb_index ] . mode = j ;
found = TRUE ;
}
}
if ( ! found
& & pb - > child_pbs [ i ] [ pb_index ] . pb_graph_node - > pb_type - > num_modes
! = 0 ) {
vpr_printf ( TIO_MESSAGE_ERROR , " [Line %d] Unknown mode %s for cb %s #%d. \n " ,
Cur - > line , Prop , pb - > child_pbs [ i ] [ pb_index ] . name , pb_index ) ;
exit ( 1 ) ;
}
pb - > child_pbs [ i ] [ pb_index ] . parent_pb = pb ;
pb - > child_pbs [ i ] [ pb_index ] . rr_graph = pb - > rr_graph ;
processPb ( Cur , & pb - > child_pbs [ i ] [ pb_index ] , rr_graph , rr_node_to_pb_mapping , num_primitives , vpack_net_hash , logical_block_hash , cb_index ) ;
}
}
Prev = Cur ;
Cur = Cur - > next ;
FreeNode ( Prev ) ;
freeTokens ( tokens , num_tokens ) ;
} else {
Cur = Cur - > next ;
}
}
}
}
/**
* Allocates memory for nets and loads the name of the net so that it can be identified and loaded with
* more complete information later
* ncount - number of nets in the hashtable of nets
* nhash - hashtable of nets
* returns array of nets stored in hashtable
*/
static struct s_net * alloc_and_init_netlist_from_hash ( INP int ncount ,
INOUTP struct s_hash * * nhash ) {
struct s_net * nlist ;
struct s_hash_iterator hash_iter ;
struct s_hash * curr_net ;
int i ;
nlist = ( struct s_net * ) my_calloc ( ncount , sizeof ( struct s_net ) ) ;
hash_iter = start_hash_table_iterator ( ) ;
curr_net = get_next_hash ( nhash , & hash_iter ) ;
while ( curr_net ! = NULL ) {
assert ( nlist [ curr_net - > index ] . name = = NULL ) ;
nlist [ curr_net - > index ] . name = my_strdup ( curr_net - > name ) ;
nlist [ curr_net - > index ] . num_sinks = curr_net - > count - 1 ;
nlist [ curr_net - > index ] . node_block = ( int * ) my_malloc (
curr_net - > count * sizeof ( int ) ) ;
nlist [ curr_net - > index ] . node_block_pin = ( int * ) my_malloc (
curr_net - > count * sizeof ( int ) ) ;
nlist [ curr_net - > index ] . is_global = FALSE ;
for ( i = 0 ; i < curr_net - > count ; i + + ) {
nlist [ curr_net - > index ] . node_block [ i ] = OPEN ;
nlist [ curr_net - > index ] . node_block_pin [ i ] = OPEN ;
}
curr_net = get_next_hash ( nhash , & hash_iter ) ;
}
return nlist ;
}
/**
* Adds net to hashtable of nets . If the net is " open " , then this is a keyword so do not add it .
* If the net already exists , increase the count on that net
*/
static int add_net_to_hash ( INOUTP struct s_hash * * nhash , INP char * net_name ,
INOUTP int * ncount ) {
struct s_hash * hash_value ;
if ( strcmp ( net_name , " open " ) = = 0 ) {
return OPEN ;
}
hash_value = insert_in_hash_table ( nhash , net_name , * ncount ) ;
if ( hash_value - > count = = 1 ) {
assert ( * ncount = = hash_value - > index ) ;
( * ncount ) + + ;
}
return hash_value - > index ;
}
static void processPorts ( INOUTP ezxml_t Parent , INOUTP t_pb * pb ,
t_rr_node * rr_graph , INOUTP t_pb * * rr_node_to_pb_mapping , INP struct s_hash * * vpack_net_hash ) {
int i , j , in_port , out_port , clock_port , num_tokens ;
ezxml_t Cur , Prev ;
const char * Prop ;
char * * pins ;
char * port_name , * interconnect_name ;
int rr_node_index ;
t_pb_graph_pin * * * pin_node ;
int * num_ptrs , num_sets ;
struct s_hash * temp_hash ;
boolean found ;
Cur = Parent - > child ;
while ( Cur ) {
if ( 0 = = strcmp ( Cur - > name , " port " ) ) {
CheckElement ( Cur , " port " ) ;
Prop = FindProperty ( Cur , " name " , TRUE ) ;
ezxml_set_attr ( Cur , " name " , NULL ) ;
in_port = out_port = clock_port = 0 ;
found = FALSE ;
for ( i = 0 ; i < pb - > pb_graph_node - > pb_type - > num_ports ; i + + ) {
if ( 0
= = strcmp ( pb - > pb_graph_node - > pb_type - > ports [ i ] . name ,
Prop ) ) {
found = TRUE ;
break ;
}
if ( pb - > pb_graph_node - > pb_type - > ports [ i ] . is_clock
& & pb - > pb_graph_node - > pb_type - > ports [ i ] . type
= = IN_PORT ) {
clock_port + + ;
} else if ( ! pb - > pb_graph_node - > pb_type - > ports [ i ] . is_clock
& & pb - > pb_graph_node - > pb_type - > ports [ i ] . type
= = IN_PORT ) {
in_port + + ;
} else {
assert (
pb - > pb_graph_node - > pb_type - > ports [ i ] . type = = OUT_PORT ) ;
out_port + + ;
}
}
if ( ! found ) {
vpr_printf ( TIO_MESSAGE_ERROR , " [Line %d] Unknown port %s for pb %s[%d]. \n " ,
Cur - > line , Prop , pb - > pb_graph_node - > pb_type - > name ,
pb - > pb_graph_node - > placement_index ) ;
exit ( 1 ) ;
}
pins = GetNodeTokens ( Cur ) ;
num_tokens = CountTokens ( pins ) ;
if ( 0 = = strcmp ( Parent - > name , " inputs " ) ) {
if ( num_tokens ! = pb - > pb_graph_node - > num_input_pins [ in_port ] ) {
vpr_printf ( TIO_MESSAGE_ERROR , " [Line %d] Incorrect # pins %d found for port %s for pb %s[%d]. \n " ,
Cur - > line , num_tokens , Prop ,
pb - > pb_graph_node - > pb_type - > name ,
pb - > pb_graph_node - > placement_index ) ;
exit ( 1 ) ;
}
} else if ( 0 = = strcmp ( Parent - > name , " outputs " ) ) {
if ( num_tokens
! = pb - > pb_graph_node - > num_output_pins [ out_port ] ) {
vpr_printf ( TIO_MESSAGE_ERROR , " [Line %d] Incorrect # pins %d found for port %s for pb %s[%d]. \n " ,
Cur - > line , num_tokens , Prop ,
pb - > pb_graph_node - > pb_type - > name ,
pb - > pb_graph_node - > placement_index ) ;
exit ( 1 ) ;
}
} else {
if ( num_tokens
! = pb - > pb_graph_node - > num_clock_pins [ clock_port ] ) {
vpr_printf ( TIO_MESSAGE_ERROR , " [Line %d] Incorrect # pins %d found for port %s for pb %s[%d]. \n " ,
Cur - > line , num_tokens , Prop ,
pb - > pb_graph_node - > pb_type - > name ,
pb - > pb_graph_node - > placement_index ) ;
exit ( 1 ) ;
}
}
if ( 0 = = strcmp ( Parent - > name , " inputs " )
| | 0 = = strcmp ( Parent - > name , " clocks " ) ) {
if ( pb - > parent_pb = = NULL ) {
/* top-level, connections are nets to route */
for ( i = 0 ; i < num_tokens ; i + + ) {
if ( 0 = = strcmp ( Parent - > name , " inputs " ) )
rr_node_index =
pb - > pb_graph_node - > input_pins [ in_port ] [ i ] . pin_count_in_cluster ;
else
rr_node_index =
pb - > pb_graph_node - > clock_pins [ clock_port ] [ i ] . pin_count_in_cluster ;
if ( strcmp ( pins [ i ] , " open " ) ! = 0 ) {
temp_hash = get_hash_entry ( vpack_net_hash , pins [ i ] ) ;
if ( temp_hash = = NULL ) {
vpr_printf ( TIO_MESSAGE_ERROR , " .blif and .net do not match, unknown net %s found in .net file. \n . " , pins [ i ] ) ;
}
rr_graph [ rr_node_index ] . net_num = temp_hash - > index ;
}
rr_node_to_pb_mapping [ rr_node_index ] = pb ;
}
} else {
for ( i = 0 ; i < num_tokens ; i + + ) {
if ( 0 = = strcmp ( pins [ i ] , " open " ) ) {
continue ;
}
interconnect_name = strstr ( pins [ i ] , " -> " ) ;
* interconnect_name = ' \0 ' ;
interconnect_name + = 2 ;
port_name = pins [ i ] ;
pin_node =
alloc_and_load_port_pin_ptrs_from_string (
pb - > pb_graph_node - > pb_type - > parent_mode - > interconnect [ 0 ] . line_num ,
pb - > pb_graph_node - > parent_pb_graph_node ,
pb - > pb_graph_node - > parent_pb_graph_node - > child_pb_graph_nodes [ pb - > parent_pb - > mode ] ,
port_name , & num_ptrs , & num_sets , TRUE ,
TRUE ) ;
assert ( num_sets = = 1 & & num_ptrs [ 0 ] = = 1 ) ;
if ( 0 = = strcmp ( Parent - > name , " inputs " ) )
rr_node_index =
pb - > pb_graph_node - > input_pins [ in_port ] [ i ] . pin_count_in_cluster ;
else
rr_node_index =
pb - > pb_graph_node - > clock_pins [ clock_port ] [ i ] . pin_count_in_cluster ;
rr_graph [ rr_node_index ] . prev_node =
pin_node [ 0 ] [ 0 ] - > pin_count_in_cluster ;
rr_node_to_pb_mapping [ rr_node_index ] = pb ;
found = FALSE ;
for ( j = 0 ; j < pin_node [ 0 ] [ 0 ] - > num_output_edges ; j + + ) {
if ( 0
= = strcmp ( interconnect_name ,
pin_node [ 0 ] [ 0 ] - > output_edges [ j ] - > interconnect - > name ) ) {
found = TRUE ;
break ;
}
}
for ( j = 0 ; j < num_sets ; j + + ) {
free ( pin_node [ j ] ) ;
}
free ( pin_node ) ;
free ( num_ptrs ) ;
if ( ! found ) {
vpr_printf ( TIO_MESSAGE_ERROR , " [Line %d] Unknown interconnect %s connecting to pin %s. \n " ,
Cur - > line , interconnect_name , port_name ) ;
exit ( 1 ) ;
}
}
}
}
if ( 0 = = strcmp ( Parent - > name , " outputs " ) ) {
if ( pb - > pb_graph_node - > pb_type - > num_modes = = 0 ) {
/* primitives are drivers of nets */
for ( i = 0 ; i < num_tokens ; i + + ) {
rr_node_index =
pb - > pb_graph_node - > output_pins [ out_port ] [ i ] . pin_count_in_cluster ;
if ( strcmp ( pins [ i ] , " open " ) ! = 0 ) {
temp_hash = get_hash_entry ( vpack_net_hash , pins [ i ] ) ;
if ( temp_hash = = NULL ) {
vpr_printf ( TIO_MESSAGE_ERROR , " .blif and .net do not match, unknown net %s found in .net file. \n " , pins [ i ] ) ;
}
rr_graph [ rr_node_index ] . net_num = temp_hash - > index ;
}
rr_node_to_pb_mapping [ rr_node_index ] = pb ;
}
} else {
for ( i = 0 ; i < num_tokens ; i + + ) {
if ( 0 = = strcmp ( pins [ i ] , " open " ) ) {
continue ;
}
interconnect_name = strstr ( pins [ i ] , " -> " ) ;
* interconnect_name = ' \0 ' ;
interconnect_name + = 2 ;
port_name = pins [ i ] ;
pin_node =
alloc_and_load_port_pin_ptrs_from_string (
pb - > pb_graph_node - > pb_type - > modes [ pb - > mode ] . interconnect - > line_num ,
pb - > pb_graph_node ,
pb - > pb_graph_node - > child_pb_graph_nodes [ pb - > mode ] ,
port_name , & num_ptrs , & num_sets , TRUE ,
TRUE ) ;
assert ( num_sets = = 1 & & num_ptrs [ 0 ] = = 1 ) ;
rr_node_index =
pb - > pb_graph_node - > output_pins [ out_port ] [ i ] . pin_count_in_cluster ;
rr_graph [ rr_node_index ] . prev_node =
pin_node [ 0 ] [ 0 ] - > pin_count_in_cluster ;
rr_node_to_pb_mapping [ rr_node_index ] = pb ;
found = FALSE ;
for ( j = 0 ; j < pin_node [ 0 ] [ 0 ] - > num_output_edges ; j + + ) {
if ( 0
= = strcmp ( interconnect_name ,
pin_node [ 0 ] [ 0 ] - > output_edges [ j ] - > interconnect - > name ) ) {
found = TRUE ;
break ;
}
}
for ( j = 0 ; j < num_sets ; j + + ) {
free ( pin_node [ j ] ) ;
}
free ( pin_node ) ;
free ( num_ptrs ) ;
if ( ! found ) {
vpr_printf ( TIO_MESSAGE_ERROR , " [Line %d] Unknown interconnect %s connecting to pin %s. \n " ,
Cur - > line , interconnect_name , port_name ) ;
exit ( 1 ) ;
}
interconnect_name - = 2 ;
* interconnect_name = ' - ' ;
}
}
}
FreeTokens ( & pins ) ;
Prev = Cur ;
Cur = Cur - > next ;
FreeNode ( Prev ) ;
} else {
Cur = Cur - > next ;
}
}
}
/**
* This function updates the nets list and the connections between that list and the complex block
*/
static void load_external_nets_and_cb ( INP int L_num_blocks ,
INP struct s_block block_list [ ] , INP int ncount ,
INP struct s_net nlist [ ] , OUTP int * ext_ncount ,
OUTP struct s_net * * ext_nets , INP char * * circuit_clocks ) {
int i , j , k , ipin ;
struct s_hash * * ext_nhash ;
t_rr_node * rr_graph ;
t_pb_graph_pin * pb_graph_pin ;
int * count ;
int netnum , num_tokens ;
* ext_ncount = 0 ;
ext_nhash = alloc_hash_table ( ) ;
/* Assumes that complex block pins are ordered inputs, outputs, globals */
/* Determine the external nets of complex block */
for ( i = 0 ; i < L_num_blocks ; i + + ) {
ipin = 0 ;
if ( block_list [ i ] . type - > pb_type - > num_input_pins
+ block_list [ i ] . type - > pb_type - > num_output_pins
+ block_list [ i ] . type - > pb_type - > num_clock_pins
! = block_list [ i ] . type - > num_pins
/ block_list [ i ] . type - > capacity ) {
assert ( 0 ) ;
}
/* First determine nets external to complex blocks */
assert (
block_list [ i ] . type - > pb_type - > num_input_pins + block_list [ i ] . type - > pb_type - > num_output_pins + block_list [ i ] . type - > pb_type - > num_clock_pins = = block_list [ i ] . type - > num_pins / block_list [ i ] . type - > capacity ) ;
rr_graph = block_list [ i ] . pb - > rr_graph ;
for ( j = 0 ; j < block_list [ i ] . pb - > pb_graph_node - > num_input_ports ; j + + ) {
for ( k = 0 ; k < block_list [ i ] . pb - > pb_graph_node - > num_input_pins [ j ] ;
k + + ) {
pb_graph_pin =
& block_list [ i ] . pb - > pb_graph_node - > input_pins [ j ] [ k ] ;
assert ( pb_graph_pin - > pin_count_in_cluster = = ipin ) ;
if ( rr_graph [ pb_graph_pin - > pin_count_in_cluster ] . net_num
! = OPEN ) {
block_list [ i ] . nets [ ipin ] =
add_net_to_hash ( ext_nhash ,
nlist [ rr_graph [ pb_graph_pin - > pin_count_in_cluster ] . net_num ] . name ,
ext_ncount ) ;
} else {
block_list [ i ] . nets [ ipin ] = OPEN ;
}
ipin + + ;
}
}
for ( j = 0 ; j < block_list [ i ] . pb - > pb_graph_node - > num_output_ports ;
j + + ) {
for ( k = 0 ; k < block_list [ i ] . pb - > pb_graph_node - > num_output_pins [ j ] ;
k + + ) {
pb_graph_pin =
& block_list [ i ] . pb - > pb_graph_node - > output_pins [ j ] [ k ] ;
assert ( pb_graph_pin - > pin_count_in_cluster = = ipin ) ;
if ( rr_graph [ pb_graph_pin - > pin_count_in_cluster ] . net_num
! = OPEN ) {
block_list [ i ] . nets [ ipin ] =
add_net_to_hash ( ext_nhash ,
nlist [ rr_graph [ pb_graph_pin - > pin_count_in_cluster ] . net_num ] . name ,
ext_ncount ) ;
} else {
block_list [ i ] . nets [ ipin ] = OPEN ;
}
ipin + + ;
}
}
for ( j = 0 ; j < block_list [ i ] . pb - > pb_graph_node - > num_clock_ports ; j + + ) {
for ( k = 0 ; k < block_list [ i ] . pb - > pb_graph_node - > num_clock_pins [ j ] ;
k + + ) {
pb_graph_pin =
& block_list [ i ] . pb - > pb_graph_node - > clock_pins [ j ] [ k ] ;
assert ( pb_graph_pin - > pin_count_in_cluster = = ipin ) ;
if ( rr_graph [ pb_graph_pin - > pin_count_in_cluster ] . net_num
! = OPEN ) {
block_list [ i ] . nets [ ipin ] =
add_net_to_hash ( ext_nhash ,
nlist [ rr_graph [ pb_graph_pin - > pin_count_in_cluster ] . net_num ] . name ,
ext_ncount ) ;
} else {
block_list [ i ] . nets [ ipin ] = OPEN ;
}
ipin + + ;
}
}
for ( j = ipin ; j < block_list [ i ] . type - > num_pins ; j + + ) {
block_list [ i ] . nets [ ipin ] = OPEN ;
}
}
/* alloc and partially load the list of external nets */
( * ext_nets ) = alloc_and_init_netlist_from_hash ( * ext_ncount , ext_nhash ) ;
/* Load global nets */
num_tokens = CountTokens ( circuit_clocks ) ;
count = ( int * ) my_calloc ( * ext_ncount , sizeof ( int ) ) ;
/* complete load of external nets so that each net points back to the blocks */
for ( i = 0 ; i < L_num_blocks ; i + + ) {
ipin = 0 ;
rr_graph = block_list [ i ] . pb - > rr_graph ;
for ( j = 0 ; j < block_list [ i ] . type - > num_pins ; j + + ) {
netnum = block_list [ i ] . nets [ j ] ;
if ( netnum ! = OPEN ) {
if ( RECEIVER
= = block_list [ i ] . type - > class_inf [ block_list [ i ] . type - > pin_class [ j ] ] . type ) {
count [ netnum ] + + ;
if ( count [ netnum ] > ( * ext_nets ) [ netnum ] . num_sinks ) {
vpr_printf ( TIO_MESSAGE_ERROR , " net %s #%d inconsistency, expected %d terminals but encountered %d terminals, it is likely net terminal is disconnected in netlist file. \n " ,
( * ext_nets ) [ netnum ] . name , netnum , count [ netnum ] , ( * ext_nets ) [ netnum ] . num_sinks ) ;
exit ( 1 ) ;
}
( * ext_nets ) [ netnum ] . node_block [ count [ netnum ] ] = i ;
( * ext_nets ) [ netnum ] . node_block_pin [ count [ netnum ] ] = j ;
( * ext_nets ) [ netnum ] . is_global = block_list [ i ] . type - > is_global_pin [ j ] ; /* Error check performed later to ensure no mixing of global and non-global signals */
} else {
assert (
DRIVER = = block_list [ i ] . type - > class_inf [ block_list [ i ] . type - > pin_class [ j ] ] . type ) ;
assert ( ( * ext_nets ) [ netnum ] . node_block [ 0 ] = = OPEN ) ;
( * ext_nets ) [ netnum ] . node_block [ 0 ] = i ;
( * ext_nets ) [ netnum ] . node_block_pin [ 0 ] = j ;
}
}
}
}
/* Error check global and non global signals */
for ( i = 0 ; i < * ext_ncount ; i + + ) {
for ( j = 1 ; j < = ( * ext_nets ) [ i ] . num_sinks ; j + + ) {
if ( block_list [ ( * ext_nets ) [ i ] . node_block [ j ] ] . type - > is_global_pin [ ( * ext_nets ) [ i ] . node_block_pin [ j ] ] ! = ( * ext_nets ) [ i ] . is_global ) {
vpr_printf ( TIO_MESSAGE_ERROR , " Netlist attempts to connect net %s to both global and non-global pins. \n " ,
( * ext_nets ) [ i ] . name ) ;
exit ( 1 ) ;
}
}
for ( j = 0 ; j < num_tokens ; j + + ) {
if ( strcmp ( circuit_clocks [ j ] , ( * ext_nets ) [ i ] . name ) = = 0 ) {
assert ( ( * ext_nets ) [ i ] . is_global = = TRUE ) ; /* above code should have caught this case, if not, then bug in code */
}
}
}
free ( count ) ;
free_hash_table ( ext_nhash ) ;
}
/* Recursive function that fills rr_graph of cb with net numbers starting at the given rr_node */
static int count_sinks_internal_cb_rr_graph_net_nums (
INP t_rr_node * cur_rr_node , INP t_rr_node * rr_graph ) {
int i ;
int count = 0 ;
for ( i = 0 ; i < cur_rr_node - > num_edges ; i + + ) {
if ( & rr_graph [ rr_graph [ cur_rr_node - > edges [ i ] ] . prev_node ]
= = cur_rr_node ) {
2019-04-26 13:23:47 -05:00
if ( ! ( rr_graph [ cur_rr_node - > edges [ i ] ] . net_num = = OPEN | | rr_graph [ cur_rr_node - > edges [ i ] ] . net_num = = cur_rr_node - > net_num ) ) {
2018-07-26 12:28:21 -05:00
assert (
rr_graph [ cur_rr_node - > edges [ i ] ] . net_num = = OPEN | | rr_graph [ cur_rr_node - > edges [ i ] ] . net_num = = cur_rr_node - > net_num ) ;
2019-04-26 13:23:47 -05:00
}
2018-07-26 12:28:21 -05:00
count + = count_sinks_internal_cb_rr_graph_net_nums (
& rr_graph [ cur_rr_node - > edges [ i ] ] , rr_graph ) ;
}
}
if ( count = = 0 ) {
return 1 ; /* terminal node */
} else {
return count ;
}
}
/* Recursive function that fills rr_graph of cb with net numbers starting at the given rr_node */
static void load_internal_cb_rr_graph_net_nums ( INP t_rr_node * cur_rr_node ,
INP t_rr_node * rr_graph , INOUTP struct s_net * nets ,
INOUTP int * curr_net , INOUTP int * curr_sink ) {
int i ;
boolean terminal ;
terminal = TRUE ;
for ( i = 0 ; i < cur_rr_node - > num_edges ; i + + ) {
if ( & rr_graph [ rr_graph [ cur_rr_node - > edges [ i ] ] . prev_node ]
= = cur_rr_node ) {
/* TODO: If multiple edges to same node (should not happen in reasonable design) this always
selects the last edge , need to be smart about it in future ( ie . select fastest edge */
assert (
rr_graph [ cur_rr_node - > edges [ i ] ] . net_num = = OPEN | | rr_graph [ cur_rr_node - > edges [ i ] ] . net_num = = cur_rr_node - > net_num ) ;
rr_graph [ cur_rr_node - > edges [ i ] ] . net_num = cur_rr_node - > net_num ;
rr_graph [ cur_rr_node - > edges [ i ] ] . prev_edge = i ;
load_internal_cb_rr_graph_net_nums ( & rr_graph [ cur_rr_node - > edges [ i ] ] ,
rr_graph , nets , curr_net , curr_sink ) ;
terminal = FALSE ;
}
}
if ( terminal = = TRUE ) {
/* Since the routing node index is known, assign that instead of the more obscure node block */
nets [ * curr_net ] . node_block [ * curr_sink ] =
cur_rr_node - > pb_graph_pin - > pin_count_in_cluster ;
nets [ * curr_net ] . node_block_pin [ * curr_sink ] = OPEN ;
nets [ * curr_net ] . node_block_port [ * curr_sink ] = OPEN ;
( * curr_sink ) + + ;
}
}
/* Load internal cb nets and fill rr_graph of cb with net numbers */
static void load_internal_cb_nets ( INOUTP t_pb * top_level ,
INP t_pb_graph_node * pb_graph_node , INOUTP t_rr_node * rr_graph ,
INOUTP int * curr_net ) {
int i , j , k ;
const t_pb_type * pb_type ;
int temp , size ;
struct s_net * nets ;
pb_type = pb_graph_node - > pb_type ;
nets = top_level - > local_nets ;
temp = 0 ;
if ( pb_graph_node - > parent_pb_graph_node = = NULL ) { /* determine nets driven from inputs at top level */
* curr_net = 0 ;
for ( i = 0 ; i < pb_graph_node - > num_input_ports ; i + + ) {
for ( j = 0 ; j < pb_graph_node - > num_input_pins [ i ] ; j + + ) {
if ( rr_graph [ pb_graph_node - > input_pins [ i ] [ j ] . pin_count_in_cluster ] . net_num
! = OPEN ) {
load_internal_cb_rr_graph_net_nums (
& rr_graph [ pb_graph_node - > input_pins [ i ] [ j ] . pin_count_in_cluster ] ,
rr_graph , nets , curr_net , & temp ) ;
assert ( temp = = nets [ * curr_net ] . num_sinks ) ;
temp = 0 ;
size =
strlen ( pb_graph_node - > pb_type - > name )
+ pb_graph_node - > placement_index / 10
+ i / 10 + j / 10
+ pb_graph_node - > input_pins [ i ] [ j ] . pin_count_in_cluster
/ 10 + 26 ;
nets [ * curr_net ] . name = ( char * ) my_calloc ( size , sizeof ( char ) ) ;
sprintf ( nets [ * curr_net ] . name ,
" %s[%d].input[%d][%d].pin[%d] " ,
pb_graph_node - > pb_type - > name ,
pb_graph_node - > placement_index , i , j ,
pb_graph_node - > input_pins [ i ] [ j ] . pin_count_in_cluster ) ;
( * curr_net ) + + ;
}
}
}
for ( i = 0 ; i < pb_graph_node - > num_clock_ports ; i + + ) {
for ( j = 0 ; j < pb_graph_node - > num_clock_pins [ i ] ; j + + ) {
if ( rr_graph [ pb_graph_node - > clock_pins [ i ] [ j ] . pin_count_in_cluster ] . net_num
! = OPEN ) {
load_internal_cb_rr_graph_net_nums (
& rr_graph [ pb_graph_node - > clock_pins [ i ] [ j ] . pin_count_in_cluster ] ,
rr_graph , nets , curr_net , & temp ) ;
assert ( temp = = nets [ * curr_net ] . num_sinks ) ;
temp = 0 ;
nets [ * curr_net ] . is_global = TRUE ;
size =
strlen ( pb_graph_node - > pb_type - > name )
+ pb_graph_node - > placement_index / 10
+ i / 10 + j / 10
+ pb_graph_node - > clock_pins [ i ] [ j ] . pin_count_in_cluster
/ 10 + 26 ;
nets [ * curr_net ] . name = ( char * ) my_calloc ( size , sizeof ( char ) ) ;
sprintf ( nets [ * curr_net ] . name ,
" %s[%d].clock[%d][%d].pin[%d] " ,
pb_graph_node - > pb_type - > name ,
pb_graph_node - > placement_index , i , j ,
pb_graph_node - > clock_pins [ i ] [ j ] . pin_count_in_cluster ) ;
( * curr_net ) + + ;
}
}
}
}
if ( pb_type - > blif_model ! = NULL ) {
/* This is a terminal node so it might drive nets, find and map the rr_graph path for those nets */
for ( i = 0 ; i < pb_graph_node - > num_output_ports ; i + + ) {
for ( j = 0 ; j < pb_graph_node - > num_output_pins [ i ] ; j + + ) {
if ( rr_graph [ pb_graph_node - > output_pins [ i ] [ j ] . pin_count_in_cluster ] . net_num
! = OPEN ) {
load_internal_cb_rr_graph_net_nums (
& rr_graph [ pb_graph_node - > output_pins [ i ] [ j ] . pin_count_in_cluster ] ,
rr_graph , nets , curr_net , & temp ) ;
assert ( temp = = nets [ * curr_net ] . num_sinks ) ;
temp = 0 ;
size =
strlen ( pb_graph_node - > pb_type - > name )
+ pb_graph_node - > placement_index / 10
+ i / 10 + j / 10
+ pb_graph_node - > output_pins [ i ] [ j ] . pin_count_in_cluster
/ 10 + 26 ;
nets [ * curr_net ] . name = ( char * ) my_calloc ( size , sizeof ( char ) ) ;
sprintf ( nets [ * curr_net ] . name ,
" %s[%d].output[%d][%d].pin[%d] " ,
pb_graph_node - > pb_type - > name ,
pb_graph_node - > placement_index , i , j ,
pb_graph_node - > output_pins [ i ] [ j ] . pin_count_in_cluster ) ;
( * curr_net ) + + ;
}
}
}
} else {
/* Recurse down to primitives */
for ( i = 0 ; i < pb_type - > num_modes ; i + + ) {
for ( j = 0 ; j < pb_type - > modes [ i ] . num_pb_type_children ; j + + ) {
for ( k = 0 ; k < pb_type - > modes [ i ] . pb_type_children [ j ] . num_pb ;
k + + ) {
load_internal_cb_nets ( top_level ,
& pb_graph_node - > child_pb_graph_nodes [ i ] [ j ] [ k ] ,
rr_graph , curr_net ) ;
}
}
}
}
if ( pb_graph_node - > parent_pb_graph_node = = NULL ) { /* at top level */
assert ( * curr_net = = top_level - > num_local_nets ) ;
}
}
/* allocate space to store nets internal to cb
two pass algorithm , pass 1 count and allocate # nets , pass 2 determine # sinks
*/
static void alloc_internal_cb_nets ( INOUTP t_pb * top_level ,
INP t_pb_graph_node * pb_graph_node , INOUTP t_rr_node * rr_graph ,
INP int pass ) {
int i , j , k ;
const t_pb_type * pb_type ;
int num_sinks ;
pb_type = pb_graph_node - > pb_type ;
if ( pb_graph_node - > parent_pb_graph_node = = NULL ) { /* determine nets driven from inputs at top level */
top_level - > num_local_nets = 0 ;
if ( pass = = 1 )
top_level - > local_nets = NULL ;
for ( i = 0 ; i < pb_graph_node - > num_input_ports ; i + + ) {
for ( j = 0 ; j < pb_graph_node - > num_input_pins [ i ] ; j + + ) {
if ( rr_graph [ pb_graph_node - > input_pins [ i ] [ j ] . pin_count_in_cluster ] . net_num
! = OPEN ) {
if ( pass = = 2 ) {
num_sinks =
count_sinks_internal_cb_rr_graph_net_nums (
& rr_graph [ pb_graph_node - > input_pins [ i ] [ j ] . pin_count_in_cluster ] ,
rr_graph ) ;
top_level - > local_nets [ top_level - > num_local_nets ] . num_sinks =
num_sinks ;
top_level - > local_nets [ top_level - > num_local_nets ] . node_block = ( int * )
my_calloc ( num_sinks , sizeof ( int ) ) ;
top_level - > local_nets [ top_level - > num_local_nets ] . node_block_port = ( int * )
my_calloc ( num_sinks , sizeof ( int ) ) ;
top_level - > local_nets [ top_level - > num_local_nets ] . node_block_pin = ( int * )
my_calloc ( num_sinks , sizeof ( int ) ) ;
}
top_level - > num_local_nets + + ;
}
}
}
for ( i = 0 ; i < pb_graph_node - > num_clock_ports ; i + + ) {
for ( j = 0 ; j < pb_graph_node - > num_clock_pins [ i ] ; j + + ) {
if ( rr_graph [ pb_graph_node - > clock_pins [ i ] [ j ] . pin_count_in_cluster ] . net_num
! = OPEN ) {
if ( pass = = 2 ) {
num_sinks =
count_sinks_internal_cb_rr_graph_net_nums (
& rr_graph [ pb_graph_node - > clock_pins [ i ] [ j ] . pin_count_in_cluster ] ,
rr_graph ) ;
top_level - > local_nets [ top_level - > num_local_nets ] . num_sinks =
num_sinks ;
top_level - > local_nets [ top_level - > num_local_nets ] . node_block = ( int * )
my_calloc ( num_sinks , sizeof ( int ) ) ;
top_level - > local_nets [ top_level - > num_local_nets ] . node_block_port = ( int * )
my_calloc ( num_sinks , sizeof ( int ) ) ;
top_level - > local_nets [ top_level - > num_local_nets ] . node_block_pin = ( int * )
my_calloc ( num_sinks , sizeof ( int ) ) ;
}
top_level - > num_local_nets + + ;
}
}
}
}
if ( pb_type - > blif_model ! = NULL ) {
/* This is a terminal node so it might drive nets, find and map the rr_graph path for those nets */
for ( i = 0 ; i < pb_graph_node - > num_output_ports ; i + + ) {
for ( j = 0 ; j < pb_graph_node - > num_output_pins [ i ] ; j + + ) {
if ( rr_graph [ pb_graph_node - > output_pins [ i ] [ j ] . pin_count_in_cluster ] . net_num
! = OPEN ) {
if ( pass = = 2 ) {
num_sinks =
count_sinks_internal_cb_rr_graph_net_nums (
& rr_graph [ pb_graph_node - > output_pins [ i ] [ j ] . pin_count_in_cluster ] ,
rr_graph ) ;
top_level - > local_nets [ top_level - > num_local_nets ] . num_sinks =
num_sinks ;
top_level - > local_nets [ top_level - > num_local_nets ] . node_block = ( int * )
my_calloc ( num_sinks , sizeof ( int ) ) ;
top_level - > local_nets [ top_level - > num_local_nets ] . node_block_port = ( int * )
my_calloc ( num_sinks , sizeof ( int ) ) ;
top_level - > local_nets [ top_level - > num_local_nets ] . node_block_pin = ( int * )
my_calloc ( num_sinks , sizeof ( int ) ) ;
}
top_level - > num_local_nets + + ;
}
}
}
} else {
/* Recurse down to primitives */
for ( i = 0 ; i < pb_type - > num_modes ; i + + ) {
for ( j = 0 ; j < pb_type - > modes [ i ] . num_pb_type_children ; j + + ) {
for ( k = 0 ; k < pb_type - > modes [ i ] . pb_type_children [ j ] . num_pb ;
k + + ) {
alloc_internal_cb_nets ( top_level ,
& pb_graph_node - > child_pb_graph_nodes [ i ] [ j ] [ k ] ,
rr_graph , pass ) ;
}
}
}
}
if ( pb_graph_node - > parent_pb_graph_node = = NULL ) { /* at top level */
if ( pass = = 1 ) {
top_level - > local_nets = ( struct s_net * ) my_calloc ( top_level - > num_local_nets ,
sizeof ( struct s_net ) ) ;
}
}
}
static void mark_constant_generators ( INP int L_num_blocks ,
INP struct s_block block_list [ ] , INP int ncount ,
INOUTP struct s_net nlist [ ] ) {
int i ;
for ( i = 0 ; i < L_num_blocks ; i + + ) {
mark_constant_generators_rec ( block_list [ i ] . pb ,
block_list [ i ] . pb - > rr_graph , nlist ) ;
}
}
static void mark_constant_generators_rec ( INP t_pb * pb , INP t_rr_node * rr_graph ,
INOUTP struct s_net nlist [ ] ) {
int i , j ;
t_pb_type * pb_type ;
boolean const_gen ;
if ( pb - > pb_graph_node - > pb_type - > blif_model = = NULL ) {
for ( i = 0 ;
i
< pb - > pb_graph_node - > pb_type - > modes [ pb - > mode ] . num_pb_type_children ;
i + + ) {
pb_type =
& ( pb - > pb_graph_node - > pb_type - > modes [ pb - > mode ] . pb_type_children [ i ] ) ;
for ( j = 0 ; j < pb_type - > num_pb ; j + + ) {
if ( pb - > child_pbs [ i ] [ j ] . name ! = NULL ) {
mark_constant_generators_rec ( & ( pb - > child_pbs [ i ] [ j ] ) ,
rr_graph , nlist ) ;
}
}
}
} else if ( strcmp ( pb - > pb_graph_node - > pb_type - > name , " inpad " ) ! = 0 ) {
const_gen = TRUE ;
for ( i = 0 ; i < pb - > pb_graph_node - > num_input_ports & & const_gen = = TRUE ;
i + + ) {
for ( j = 0 ;
j < pb - > pb_graph_node - > num_input_pins [ i ]
& & const_gen = = TRUE ; j + + ) {
if ( rr_graph [ pb - > pb_graph_node - > input_pins [ i ] [ j ] . pin_count_in_cluster ] . net_num
! = OPEN ) {
const_gen = FALSE ;
}
}
}
for ( i = 0 ; i < pb - > pb_graph_node - > num_clock_ports & & const_gen = = TRUE ;
i + + ) {
for ( j = 0 ;
j < pb - > pb_graph_node - > num_clock_pins [ i ]
& & const_gen = = TRUE ; j + + ) {
if ( rr_graph [ pb - > pb_graph_node - > clock_pins [ i ] [ j ] . pin_count_in_cluster ] . net_num
! = OPEN ) {
const_gen = FALSE ;
}
}
}
if ( const_gen = = TRUE ) {
vpr_printf ( TIO_MESSAGE_INFO , " %s is a constant generator. \n " , pb - > name ) ;
for ( i = 0 ; i < pb - > pb_graph_node - > num_output_ports ; i + + ) {
for ( j = 0 ; j < pb - > pb_graph_node - > num_output_pins [ i ] ; j + + ) {
if ( rr_graph [ pb - > pb_graph_node - > output_pins [ i ] [ j ] . pin_count_in_cluster ] . net_num
! = OPEN ) {
nlist [ rr_graph [ pb - > pb_graph_node - > output_pins [ i ] [ j ] . pin_count_in_cluster ] . net_num ] . is_const_gen =
TRUE ;
}
}
}
}
}
}
/* Free logical blocks of netlist */
void free_logical_blocks ( void ) {
int iblk , i ;
t_model_ports * port ;
struct s_linked_vptr * tvptr , * next ;
for ( iblk = 0 ; iblk < num_logical_blocks ; iblk + + ) {
port = logical_block [ iblk ] . model - > inputs ;
i = 0 ;
while ( port ) {
if ( ! port - > is_clock ) {
free ( logical_block [ iblk ] . input_nets [ i ] ) ;
if ( logical_block [ iblk ] . input_net_tnodes ) {
if ( logical_block [ iblk ] . input_net_tnodes [ i ] )
free ( logical_block [ iblk ] . input_net_tnodes [ i ] ) ;
}
i + + ;
}
port = port - > next ;
}
if ( logical_block [ iblk ] . input_net_tnodes )
free ( logical_block [ iblk ] . input_net_tnodes ) ;
tvptr = logical_block [ iblk ] . packed_molecules ;
while ( tvptr ! = NULL ) {
next = tvptr - > next ;
free ( tvptr ) ;
tvptr = next ;
}
free ( logical_block [ iblk ] . input_nets ) ;
port = logical_block [ iblk ] . model - > outputs ;
i = 0 ;
while ( port ) {
free ( logical_block [ iblk ] . output_nets [ i ] ) ;
if ( logical_block [ iblk ] . output_net_tnodes ) {
if ( logical_block [ iblk ] . output_net_tnodes [ i ] )
free ( logical_block [ iblk ] . output_net_tnodes [ i ] ) ;
}
i + + ;
port = port - > next ;
}
if ( logical_block [ iblk ] . output_net_tnodes ) {
free ( logical_block [ iblk ] . output_net_tnodes ) ;
}
free ( logical_block [ iblk ] . output_nets ) ;
free ( logical_block [ iblk ] . name ) ;
tvptr = logical_block [ iblk ] . truth_table ;
while ( tvptr ! = NULL ) {
if ( tvptr - > data_vptr )
free ( tvptr - > data_vptr ) ;
next = tvptr - > next ;
free ( tvptr ) ;
tvptr = next ;
}
}
free ( logical_block ) ;
logical_block = NULL ;
}
/* Free logical blocks of netlist */
void free_logical_nets ( void ) {
int inet ;
for ( inet = 0 ; inet < num_logical_nets ; inet + + ) {
free ( vpack_net [ inet ] . name ) ;
free ( vpack_net [ inet ] . node_block ) ;
free ( vpack_net [ inet ] . node_block_port ) ;
free ( vpack_net [ inet ] . node_block_pin ) ;
}
free ( vpack_net ) ;
vpack_net = NULL ;
}