2018-07-26 12:28:21 -05:00
/***********************************/
/* SPICE Modeling for VPR */
/* Xifan TANG, EPFL/LSI */
/***********************************/
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <math.h>
# include <time.h>
# include <assert.h>
# include <errno.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <unistd.h>
/* Include vpr structs*/
# include "util.h"
# include "physical_types.h"
# include "vpr_types.h"
# include "globals.h"
# include "rr_graph_util.h"
# include "rr_graph.h"
# include "rr_graph2.h"
# include "vpr_utils.h"
/* Include SPICE support headers*/
# include "quicksort.h"
# include "linkedlist.h"
# include "fpga_spice_globals.h"
# include "spice_globals.h"
# include "fpga_spice_utils.h"
enum e_dir_err {
E_DIR_NOT_EXIST ,
E_EXIST_BUT_NOT_DIR ,
E_DIR_EXIST
} ;
/***** Subroutines *****/
char * my_gettime ( ) {
time_t current_time ;
char * c_time_string ;
/* Obtain current time as seconds elapsed since the Epoch*/
current_time = time ( NULL ) ;
if ( current_time = = ( ( time_t ) - 1 ) ) {
vpr_printf ( TIO_MESSAGE_ERROR , " Failure to compute the current time. \n " ) ;
exit ( 1 ) ;
}
/* Convert to local time format*/
c_time_string = ctime ( & current_time ) ;
if ( NULL = = c_time_string ) {
vpr_printf ( TIO_MESSAGE_ERROR , " Failure to convert the current time. \n " ) ;
exit ( 1 ) ;
}
/* Return it*/
return c_time_string ;
}
char * format_dir_path ( char * dir_path ) {
int len = strlen ( dir_path ) ; /* String length without the last "\0"*/
int i ;
char * ret = ( char * ) my_malloc ( sizeof ( char ) * ( len + 2 ) ) ;
strcpy ( ret , dir_path ) ;
/* Replace all the "\" to "/"*/
for ( i = 0 ; i < len ; i + + ) {
if ( ret [ i ] = = ' \\ ' ) {
ret [ i ] = ' / ' ; /* !!! Should not use "" */
}
}
/* If the path does not end up with "/" we should complete it*/
if ( ret [ len - 1 ] ! = ' / ' ) {
strcat ( ret , " / " ) ;
}
return ret ;
}
int try_access_file ( char * file_path ) {
/* F_OK checks existence and also R_OK, W_OK, X_OK,
* for readable , writable , excutable
*/
int ret = access ( file_path , F_OK ) ;
if ( 0 = = ret ) {
vpr_printf ( TIO_MESSAGE_WARNING , " Try access File(%s): exists! \n " , file_path ) ;
}
return ret ;
}
void my_remove_file ( char * file_path ) {
if ( NULL = = file_path ) {
return ;
}
if ( 0 ! = remove ( file_path ) ) {
vpr_printf ( TIO_MESSAGE_WARNING , " Fail to remove file(%s)! \n " , file_path ) ;
}
return ;
}
enum e_dir_err try_access_dir ( char * dir_path ) {
struct stat s ;
int err = stat ( dir_path , & s ) ;
if ( - 1 = = err ) {
if ( ENOENT = = errno ) {
return E_DIR_NOT_EXIST ;
} else {
perror ( " stat " ) ;
exit ( 1 ) ;
}
} else {
if ( S_ISDIR ( s . st_mode ) ) {
/* It is a dir*/
return E_DIR_EXIST ;
} else {
/* Exists but is no dir*/
return E_EXIST_BUT_NOT_DIR ;
}
}
}
int create_dir_path ( char * dir_path ) {
int ret ;
/* Check this path does not exist*/
/* Check the input legal*/
if ( NULL = = dir_path ) {
vpr_printf ( TIO_MESSAGE_INFO , " dir_path is empty and nothing is created. \n " ) ;
return 0 ;
}
ret = mkdir ( dir_path , S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH ) ;
switch ( ret ) {
case 0 :
vpr_printf ( TIO_MESSAGE_INFO , " Create directory(%s)...successfully. \n " , dir_path ) ;
return 1 ;
case - 1 :
if ( EEXIST = = errno ) {
vpr_printf ( TIO_MESSAGE_WARNING , " Directory(%s) already exists. Will overwrite SPICE netlists \n " , dir_path ) ;
return 1 ;
}
default :
vpr_printf ( TIO_MESSAGE_ERROR , " Create directory(%s)...Failed! \n " , dir_path ) ;
exit ( 1 ) ;
return 0 ;
}
}
/* Cat string2 to the end of string1 */
char * my_strcat ( char * str1 ,
char * str2 ) {
int len1 = strlen ( str1 ) ;
int len2 = strlen ( str2 ) ;
char * ret = ( char * ) my_malloc ( sizeof ( char ) * ( len1 + len2 + 1 ) ) ;
strcpy ( ret , str1 ) ;
strcat ( ret , str2 ) ;
return ret ;
}
/* Split the path and program name*/
int split_path_prog_name ( char * prog_path ,
char split_token ,
char * * ret_path ,
char * * ret_prog_name ) {
int i ;
int split_pos = - 1 ;
char * local_copy = my_strdup ( prog_path ) ;
int len = strlen ( local_copy ) ;
char * path = NULL ;
char * prog_name = NULL ;
/* Spot the split token*/
for ( i = len ; i > - 1 ; i - - ) {
if ( split_token = = local_copy [ i ] ) {
split_pos = i ;
break ;
}
}
/* Get the path and prog_name*/
if ( - 1 = = split_pos ) {
/* In this case, the prog_path actually contains only the program name*/
path = NULL ;
prog_name = local_copy ;
} else if ( len = = split_pos ) {
/* In this case the progrom name is NULL... actually the prog_path is a directory*/
path = local_copy ;
prog_name = NULL ;
} else {
/* We have to split it!*/
local_copy [ split_pos ] = ' \0 ' ;
path = my_strdup ( local_copy ) ;
prog_name = my_strdup ( local_copy + split_pos + 1 ) ;
}
/*Copy it to the return*/
( * ret_path ) = my_strdup ( path ) ;
( * ret_prog_name ) = my_strdup ( prog_name ) ;
/* Free useless resources */
my_free ( local_copy ) ;
my_free ( path ) ;
my_free ( prog_name ) ;
return 1 ;
}
char * chomp_file_name_postfix ( char * file_name ) {
char * ret = NULL ;
char * postfix = NULL ;
split_path_prog_name ( file_name , ' . ' , & ret , & postfix ) ;
my_free ( postfix ) ;
return ret ;
}
2018-08-10 14:46:00 -05:00
2018-07-26 12:28:21 -05:00
/* Print SRAM bits, typically in a comment line */
void fprint_commented_sram_bits ( FILE * fp ,
int num_sram_bits , int * sram_bits ) {
int i ;
if ( NULL = = fp ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (FILE:%s, LINE[%d]) FileHandle is NULL! \n " , __FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
for ( i = 0 ; i < num_sram_bits ; i + + ) {
fprintf ( fp , " %d " , sram_bits [ i ] ) ;
}
return ;
}
/* With a given spice_model_name, find the spice model and return its pointer
* If we find nothing , return NULL
*/
t_spice_model * find_name_matched_spice_model ( char * spice_model_name ,
int num_spice_model ,
t_spice_model * spice_models ) {
t_spice_model * ret = NULL ;
int imodel ;
int num_found = 0 ;
for ( imodel = 0 ; imodel < num_spice_model ; imodel + + ) {
if ( 0 = = strcmp ( spice_model_name , spice_models [ imodel ] . name ) ) {
ret = & ( spice_models [ imodel ] ) ;
num_found + + ;
}
}
if ( 0 = = num_found ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (FILE:%s, LINE[%d])Fail to find a spice model match name: %s ! \n " ,
__FILE__ , __LINE__ , spice_model_name ) ;
exit ( 1 ) ;
}
assert ( 1 = = num_found ) ;
return ret ;
}
/* Get the default spice_model*/
t_spice_model * get_default_spice_model ( enum e_spice_model_type default_spice_model_type ,
int num_spice_model ,
t_spice_model * spice_models ) {
t_spice_model * ret = NULL ;
int i ;
for ( i = 0 ; i < num_spice_model ; i + + ) {
/* Find a MUX and it is set as default*/
if ( ( default_spice_model_type = = spice_models [ i ] . type ) & & ( 1 = = spice_models [ i ] . is_default ) ) {
/* Check if we have multiple default*/
if ( NULL ! = ret ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,LINE[%d])Both SPICE model(%s and %s) are set as default! \n " ,
__FILE__ , __LINE__ , ret - > name , spice_models [ i ] . name ) ;
exit ( 1 ) ;
} else {
ret = & ( spice_models [ i ] ) ;
}
}
}
return ret ;
}
/* Tasks:
* 1. Search the inv_spice_model_name of each ports of a spice_model
* 2. Copy the information from inverter spice model to higher level spice_models
*/
void config_spice_model_port_inv_spice_model ( int num_spice_models ,
t_spice_model * spice_model ) {
int i , iport ;
t_spice_model * inv_spice_model = NULL ;
for ( i = 0 ; i < num_spice_models ; i + + ) {
/* By pass inverters and buffers */
if ( SPICE_MODEL_INVBUF = = spice_model [ i ] . type ) {
continue ;
}
for ( iport = 0 ; iport < spice_model [ i ] . num_port ; iport + + ) {
/* Now we bypass non BL/WL ports */
if ( ( SPICE_MODEL_PORT_BL ! = spice_model [ i ] . ports [ iport ] . type )
& & ( SPICE_MODEL_PORT_BLB ! = spice_model [ i ] . ports [ iport ] . type )
& & ( SPICE_MODEL_PORT_WL ! = spice_model [ i ] . ports [ iport ] . type )
& & ( SPICE_MODEL_PORT_WLB ! = spice_model [ i ] . ports [ iport ] . type ) ) {
continue ;
}
if ( NULL = = spice_model [ i ] . ports [ iport ] . inv_spice_model_name ) {
inv_spice_model = get_default_spice_model ( SPICE_MODEL_INVBUF ,
num_spice_models , spice_model ) ;
} else {
inv_spice_model = find_name_matched_spice_model ( spice_model [ i ] . ports [ iport ] . inv_spice_model_name ,
num_spice_models , spice_model ) ;
/* We should find a buffer spice_model*/
if ( NULL = = inv_spice_model ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Fail to find inv_spice_model to the port(name=%s) of spice_model(name=%s)! \n " ,
__FILE__ , __LINE__ , spice_model [ i ] . ports [ iport ] . prefix , spice_model [ i ] . name ) ;
exit ( 1 ) ;
}
}
/* Config */
spice_model [ i ] . ports [ iport ] . inv_spice_model = inv_spice_model ;
}
}
return ;
}
/* Tasks:
* 1. Search the spice_model_name of input and output buffer and link to the spice_model
* 2. Copy the information from input / output buffer spice model to higher level spice_models
*/
void config_spice_model_input_output_buffers_pass_gate ( int num_spice_models ,
t_spice_model * spice_model ) {
int i ;
t_spice_model * buf_spice_model = NULL ;
t_spice_model * pgl_spice_model = NULL ;
for ( i = 0 ; i < num_spice_models ; i + + ) {
/* By pass inverters and buffers */
if ( SPICE_MODEL_INVBUF = = spice_model [ i ] . type ) {
continue ;
}
/* Check if this spice model has input buffers */
if ( 1 = = spice_model [ i ] . input_buffer - > exist ) {
buf_spice_model = find_name_matched_spice_model ( spice_model [ i ] . input_buffer - > spice_model_name ,
num_spice_models , spice_model ) ;
/* We should find a buffer spice_model*/
if ( NULL = = buf_spice_model ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Fail to find inv/buffer spice_model to the input buffer of spice_model(name=%s)! \n " ,
__FILE__ , __LINE__ , spice_model [ i ] . name ) ;
exit ( 1 ) ;
}
/* Copy the information from found spice model to current spice model*/
memcpy ( spice_model [ i ] . input_buffer , buf_spice_model - > design_tech_info . buffer_info , sizeof ( t_spice_model_buffer ) ) ;
/* Recover the spice_model_name and exist */
spice_model [ i ] . input_buffer - > exist = 1 ;
spice_model [ i ] . input_buffer - > spice_model_name = my_strdup ( buf_spice_model - > name ) ;
spice_model [ i ] . input_buffer - > spice_model = buf_spice_model ;
}
/* Check if this spice model has output buffers */
if ( 1 = = spice_model [ i ] . output_buffer - > exist ) {
buf_spice_model = find_name_matched_spice_model ( spice_model [ i ] . output_buffer - > spice_model_name ,
num_spice_models , spice_model ) ;
/* We should find a buffer spice_model*/
if ( NULL = = buf_spice_model ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Fail to find inv/buffer spice_model to the output buffer of spice_model(name=%s)! \n " ,
__FILE__ , __LINE__ , spice_model [ i ] . name ) ;
exit ( 1 ) ;
}
/* Copy the information from found spice model to current spice model*/
memcpy ( spice_model [ i ] . output_buffer , buf_spice_model - > design_tech_info . buffer_info , sizeof ( t_spice_model_buffer ) ) ;
/* Recover the spice_model_name and exist */
spice_model [ i ] . output_buffer - > exist = 1 ;
spice_model [ i ] . output_buffer - > spice_model_name = my_strdup ( buf_spice_model - > name ) ;
spice_model [ i ] . output_buffer - > spice_model = buf_spice_model ;
}
/* If this spice_model is a LUT, check the lut_input_buffer */
if ( SPICE_MODEL_LUT = = spice_model [ i ] . type ) {
assert ( 1 = = spice_model [ i ] . lut_input_buffer - > exist ) ;
buf_spice_model = find_name_matched_spice_model ( spice_model [ i ] . lut_input_buffer - > spice_model_name ,
num_spice_models , spice_model ) ;
/* We should find a buffer spice_model*/
if ( NULL = = buf_spice_model ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Fail to find inv/buffer spice_model to the lut_input buffer of spice_model(name=%s)! \n " ,
__FILE__ , __LINE__ , spice_model [ i ] . name ) ;
exit ( 1 ) ;
}
/* Copy the information from found spice model to current spice model*/
memcpy ( spice_model [ i ] . lut_input_buffer , buf_spice_model - > design_tech_info . buffer_info , sizeof ( t_spice_model_buffer ) ) ;
/* Recover the spice_model_name and exist */
spice_model [ i ] . lut_input_buffer - > exist = 1 ;
spice_model [ i ] . lut_input_buffer - > spice_model_name = my_strdup ( buf_spice_model - > name ) ;
spice_model [ i ] . lut_input_buffer - > spice_model = buf_spice_model ;
}
/* Check pass_gate logic only for LUT and MUX */
if ( ( SPICE_MODEL_LUT = = spice_model [ i ] . type )
| | ( SPICE_MODEL_MUX = = spice_model [ i ] . type ) ) {
pgl_spice_model = find_name_matched_spice_model ( spice_model [ i ] . pass_gate_logic - > spice_model_name ,
num_spice_models , spice_model ) ;
/* We should find a buffer spice_model*/
if ( NULL = = pgl_spice_model ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Fail to find pass_gate spice_model to the pass_gate_logic of spice_model(name=%s)! \n " ,
__FILE__ , __LINE__ , spice_model [ i ] . name ) ;
exit ( 1 ) ;
}
/* Copy the information from found spice model to current spice model*/
memcpy ( spice_model [ i ] . pass_gate_logic , pgl_spice_model - > design_tech_info . pass_gate_info , sizeof ( t_spice_model_pass_gate_logic ) ) ;
/* Recover the spice_model_name */
spice_model [ i ] . pass_gate_logic - > spice_model_name = my_strdup ( pgl_spice_model - > name ) ;
spice_model [ i ] . pass_gate_logic - > spice_model = pgl_spice_model ;
}
}
return ;
}
/* Return the SPICE model ports wanted
* ATTENTION : we use the pointer of spice model here although we don ' t modify anything of spice_model
* but we have return input ports , whose pointer will be lost if the input is not the pointor of spice_model
* BECAUSE spice_model will be a local copy if it is not a pointer . And it will be set free when this function
* finishes . So the return pointers become invalid !
*/
t_spice_model_port * * find_spice_model_ports ( t_spice_model * spice_model ,
enum e_spice_model_port_type port_type ,
int * port_num , boolean ignore_global_port ) {
int iport , cur ;
t_spice_model_port * * ret = NULL ;
/* Check codes*/
assert ( NULL ! = port_num ) ;
assert ( NULL ! = spice_model ) ;
/* Count the number of ports that match*/
( * port_num ) = 0 ;
for ( iport = 0 ; iport < spice_model - > num_port ; iport + + ) {
/* ignore global port if user specified */
if ( ( TRUE = = ignore_global_port )
& & ( TRUE = = spice_model - > ports [ iport ] . is_global ) ) {
continue ;
}
if ( port_type = = spice_model - > ports [ iport ] . type ) {
( * port_num ) + + ;
}
}
/* Initial the return pointers*/
ret = ( t_spice_model_port * * ) my_malloc ( sizeof ( t_spice_model_port * ) * ( * port_num ) ) ;
memset ( ret , 0 , sizeof ( t_spice_model_port * ) * ( * port_num ) ) ;
/* Fill the return pointers*/
cur = 0 ;
for ( iport = 0 ; iport < spice_model - > num_port ; iport + + ) {
/* ignore global port if user specified */
if ( ( TRUE = = ignore_global_port )
& & ( TRUE = = spice_model - > ports [ iport ] . is_global ) ) {
continue ;
}
if ( port_type = = spice_model - > ports [ iport ] . type ) {
ret [ cur ] = & ( spice_model - > ports [ iport ] ) ;
cur + + ;
}
}
/* Check correctness*/
assert ( cur = = ( * port_num ) ) ;
return ret ;
}
/* Find the configure done ports */
t_spice_model_port * * find_spice_model_config_done_ports ( t_spice_model * spice_model ,
enum e_spice_model_port_type port_type ,
int * port_num , boolean ignore_global_port ) {
int iport , cur ;
t_spice_model_port * * ret = NULL ;
/* Check codes*/
assert ( NULL ! = port_num ) ;
assert ( NULL ! = spice_model ) ;
/* Count the number of ports that match*/
( * port_num ) = 0 ;
for ( iport = 0 ; iport < spice_model - > num_port ; iport + + ) {
/* ignore global port if user specified */
if ( ( TRUE = = ignore_global_port )
& & ( TRUE = = spice_model - > ports [ iport ] . is_global ) ) {
continue ;
}
if ( ( port_type = = spice_model - > ports [ iport ] . type )
& & ( TRUE = = spice_model - > ports [ iport ] . is_config_enable ) ) {
( * port_num ) + + ;
}
}
/* Initial the return pointers*/
ret = ( t_spice_model_port * * ) my_malloc ( sizeof ( t_spice_model_port * ) * ( * port_num ) ) ;
memset ( ret , 0 , sizeof ( t_spice_model_port * ) * ( * port_num ) ) ;
/* Fill the return pointers*/
cur = 0 ;
for ( iport = 0 ; iport < spice_model - > num_port ; iport + + ) {
/* ignore global port if user specified */
if ( ( TRUE = = ignore_global_port )
& & ( TRUE = = spice_model - > ports [ iport ] . is_global ) ) {
continue ;
}
if ( ( port_type = = spice_model - > ports [ iport ] . type )
& & ( TRUE = = spice_model - > ports [ iport ] . is_config_enable ) ) {
ret [ cur ] = & ( spice_model - > ports [ iport ] ) ;
cur + + ;
}
}
/* Check correctness*/
assert ( cur = = ( * port_num ) ) ;
return ret ;
}
/* Find the transistor in the tech lib*/
t_spice_transistor_type * find_mosfet_tech_lib ( t_spice_tech_lib tech_lib ,
e_spice_trans_type trans_type ) {
/* If we did not find return NULL*/
t_spice_transistor_type * ret = NULL ;
int i ;
for ( i = 0 ; i < tech_lib . num_transistor_type ; i + + ) {
if ( trans_type = = tech_lib . transistor_types [ i ] . type ) {
ret = & ( tech_lib . transistor_types [ i ] ) ;
break ;
}
}
return ret ;
}
/* Convert a integer to a string*/
char * my_itoa ( int input ) {
char * ret = NULL ;
int sign = 0 ;
int len = 0 ;
int temp = input ;
int cur ;
char end_of_str ;
/* Identify input number is positive or negative*/
if ( input < 0 ) {
sign = 1 ; /* sign will be '-'*/
len = 1 ;
temp = 0 - input ;
} else if ( 0 = = input ) {
sign = 0 ;
len = 2 ;
/* Alloc*/
ret = ( char * ) my_malloc ( sizeof ( char ) * len ) ;
/* Lets get the end_of_str, the char is dependent on OS*/
sprintf ( ret , " %s " , " 0 " ) ;
return ret ;
}
/* Identify the length of string*/
while ( temp > 0 ) {
len + + ;
temp = temp / 10 ;
}
/* Total length of string should include '\0' at the end*/
len = len + 1 ;
/* Alloc*/
ret = ( char * ) my_malloc ( sizeof ( char ) * len ) ;
/*Fill it*/
temp = input ;
/* Lets get the end_of_str, the char is dependent on OS*/
sprintf ( ret , " %s " , " - " ) ;
end_of_str = ret [ 1 ] ;
ret [ len - 1 ] = end_of_str ;
cur = len - 2 ;
/* Print the number reversely*/
while ( temp > 0 ) {
ret [ cur ] = temp % 10 + ' 0 ' ; /* ASIC II base is '0'*/
cur - - ;
temp = temp / 10 ;
}
/* Print the sign*/
if ( 1 = = sign ) {
assert ( 0 = = cur ) ;
ret [ cur ] = ' - ' ;
temp = 0 - input ;
} else {
assert ( - 1 = = cur ) ;
}
return ret ;
}
2018-08-10 14:46:00 -05:00
/* Generate a filename (string) for a grid subckt SPICE netlist,
* with given x and y coordinates
*/
char * fpga_spice_create_one_subckt_filename ( char * file_name_prefix ,
int subckt_x , int subckt_y ,
char * file_name_postfix ) {
char * fname = NULL ;
fname = ( char * ) my_malloc ( sizeof ( char ) * ( strlen ( file_name_prefix )
+ strlen ( my_itoa ( subckt_x ) ) + strlen ( my_itoa ( subckt_y ) )
+ strlen ( file_name_postfix ) + 1 ) ) ;
sprintf ( fname , " %s%d_%d%s " ,
file_name_prefix , subckt_x , subckt_y , file_name_postfix ) ;
return fname ;
}
2018-07-26 12:28:21 -05:00
/* With given spice_model_port, find the pb_type port with same name and type*/
t_port * find_pb_type_port_match_spice_model_port ( t_pb_type * pb_type ,
t_spice_model_port * spice_model_port ) {
int iport ;
t_port * ret = NULL ;
/* Search ports */
for ( iport = 0 ; iport < pb_type - > num_ports ; iport + + ) {
/* Match the name and port size*/
if ( ( 0 = = strcmp ( pb_type - > ports [ iport ] . name , spice_model_port - > prefix ) )
& & ( pb_type - > ports [ iport ] . num_pins = = spice_model_port - > size ) ) {
/* Match the type*/
switch ( spice_model_port - > type ) {
case SPICE_MODEL_PORT_INPUT :
if ( ( IN_PORT = = pb_type - > ports [ iport ] . type )
& & ( 0 = = pb_type - > ports [ iport ] . is_clock ) ) {
if ( NULL ! = ret ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s, [LINE%d])More than 1 pb_type(%s) port match spice_model_port(%s)! \n " ,
__FILE__ , __LINE__ , pb_type - > name , spice_model_port - > prefix ) ;
exit ( 1 ) ;
}
ret = & ( pb_type - > ports [ iport ] ) ;
}
break ;
case SPICE_MODEL_PORT_OUTPUT :
if ( OUT_PORT = = pb_type - > ports [ iport ] . type ) {
if ( NULL ! = ret ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s, [LINE%d])More than 1 pb_type(%s) port match spice_model_port(%s)! \n " ,
__FILE__ , __LINE__ , pb_type - > name , spice_model_port - > prefix ) ;
exit ( 1 ) ;
}
ret = & ( pb_type - > ports [ iport ] ) ;
}
break ;
case SPICE_MODEL_PORT_CLOCK :
if ( ( IN_PORT = = pb_type - > ports [ iport ] . type ) & & ( 1 = = pb_type - > ports [ iport ] . is_clock ) ) {
if ( NULL ! = ret ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s, [LINE%d])More than 1 pb_type(%s) port match spice_model_port(%s)! \n " ,
__FILE__ , __LINE__ , pb_type - > name , spice_model_port - > prefix ) ;
exit ( 1 ) ;
}
ret = & ( pb_type - > ports [ iport ] ) ;
}
break ;
case SPICE_MODEL_PORT_INOUT :
if ( ( INOUT_PORT = = pb_type - > ports [ iport ] . type ) & & ( 0 = = pb_type - > ports [ iport ] . is_clock ) ) {
if ( NULL ! = ret ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s, [LINE%d])More than 1 pb_type(%s) port match spice_model_port(%s)! \n " ,
__FILE__ , __LINE__ , pb_type - > name , spice_model_port - > prefix ) ;
exit ( 1 ) ;
}
ret = & ( pb_type - > ports [ iport ] ) ;
}
break ;
case SPICE_MODEL_PORT_SRAM :
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s, [LINE%d])Invalid type for spice_model_port(%s)! \n " ,
__FILE__ , __LINE__ , spice_model_port - > prefix ) ;
exit ( 1 ) ;
}
}
}
return ret ;
}
char * chomp_spice_node_prefix ( char * spice_node_prefix ) {
int len = 0 ;
char * ret = NULL ;
if ( NULL = = spice_node_prefix ) {
return NULL ;
}
len = strlen ( spice_node_prefix ) ; /* String length without the last "\0"*/
ret = ( char * ) my_malloc ( sizeof ( char ) * ( len + 2 ) ) ;
/* Don't do anything when input is NULL*/
if ( NULL = = spice_node_prefix ) {
my_free ( ret ) ;
return NULL ;
}
strcpy ( ret , spice_node_prefix ) ;
/* If the path end up with "_" we should remove it*/
if ( ' _ ' = = ret [ len - 1 ] ) {
ret [ len - 1 ] = ret [ len ] ;
}
return ret ;
}
char * format_spice_node_prefix ( char * spice_node_prefix ) {
int len = strlen ( spice_node_prefix ) ; /* String length without the last "\0"*/
char * ret = ( char * ) my_malloc ( sizeof ( char ) * ( len + 2 ) ) ;
/* Don't do anything when input is NULL*/
if ( NULL = = spice_node_prefix ) {
my_free ( ret ) ;
return NULL ;
}
strcpy ( ret , spice_node_prefix ) ;
/* If the path does not end up with "_" we should complete it*/
if ( ret [ len - 1 ] ! = ' _ ' ) {
strcat ( ret , " _ " ) ;
}
return ret ;
}
t_port * * find_pb_type_ports_match_spice_model_port_type ( t_pb_type * pb_type ,
enum e_spice_model_port_type port_type ,
int * port_num ) {
int iport , cur ;
t_port * * ret = NULL ;
/* Check codes*/
assert ( NULL ! = port_num ) ;
assert ( NULL ! = pb_type ) ;
/* Count the number of ports that match*/
( * port_num ) = 0 ;
for ( iport = 0 ; iport < pb_type - > num_ports ; iport + + ) {
switch ( port_type ) {
case SPICE_MODEL_PORT_INPUT : /* TODO: support is_non_clock_global*/
if ( ( IN_PORT = = pb_type - > ports [ iport ] . type )
& & ( 0 = = pb_type - > ports [ iport ] . is_clock ) ) {
( * port_num ) + + ;
}
break ;
case SPICE_MODEL_PORT_OUTPUT :
if ( ( OUT_PORT = = pb_type - > ports [ iport ] . type )
& & ( 0 = = pb_type - > ports [ iport ] . is_clock ) ) {
( * port_num ) + + ;
}
break ;
case SPICE_MODEL_PORT_INOUT :
if ( ( INOUT_PORT = = pb_type - > ports [ iport ] . type )
& & ( 0 = = pb_type - > ports [ iport ] . is_clock ) ) {
( * port_num ) + + ;
}
break ;
case SPICE_MODEL_PORT_CLOCK :
if ( ( IN_PORT = = pb_type - > ports [ iport ] . type )
& & ( 1 = = pb_type - > ports [ iport ] . is_clock ) ) {
( * port_num ) + + ;
}
break ;
case SPICE_MODEL_PORT_SRAM :
/* Original VPR don't support this*/
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s, [LINE%d])Invalid type for port! \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
}
/* Initial the return pointers*/
ret = ( t_port * * ) my_malloc ( sizeof ( t_port * ) * ( * port_num ) ) ;
memset ( ret , 0 , sizeof ( t_port * ) * ( * port_num ) ) ;
/* Fill the return pointers*/
cur = 0 ;
for ( iport = 0 ; iport < pb_type - > num_ports ; iport + + ) {
switch ( port_type ) {
case SPICE_MODEL_PORT_INPUT : /* TODO: support is_non_clock_global*/
if ( ( IN_PORT = = pb_type - > ports [ iport ] . type )
& & ( 0 = = pb_type - > ports [ iport ] . is_clock ) ) {
ret [ cur ] = & ( pb_type - > ports [ iport ] ) ;
cur + + ;
}
break ;
case SPICE_MODEL_PORT_OUTPUT :
if ( ( OUT_PORT = = pb_type - > ports [ iport ] . type )
& & ( 0 = = pb_type - > ports [ iport ] . is_clock ) ) {
ret [ cur ] = & ( pb_type - > ports [ iport ] ) ;
cur + + ;
}
break ;
case SPICE_MODEL_PORT_INOUT :
if ( ( INOUT_PORT = = pb_type - > ports [ iport ] . type )
& & ( 0 = = pb_type - > ports [ iport ] . is_clock ) ) {
ret [ cur ] = & ( pb_type - > ports [ iport ] ) ;
cur + + ;
}
break ;
case SPICE_MODEL_PORT_CLOCK :
if ( ( IN_PORT = = pb_type - > ports [ iport ] . type )
& & ( 1 = = pb_type - > ports [ iport ] . is_clock ) ) {
ret [ cur ] = & ( pb_type - > ports [ iport ] ) ;
cur + + ;
}
break ;
case SPICE_MODEL_PORT_SRAM :
/* Original VPR don't support this*/
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s, [LINE%d])Invalid type for port! \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
}
/* Check correctness*/
assert ( cur = = ( * port_num ) ) ;
return ret ;
}
/* Given the co-ordinators of grid,
* Find if there is a block mapped into this grid
*/
t_block * search_mapped_block ( int x , int y , int z ) {
t_block * ret = NULL ;
int iblk = 0 ;
/*Valid pointors*/
assert ( NULL ! = grid ) ;
assert ( ( 0 < x ) | | ( 0 = = x ) ) ;
assert ( ( x < ( nx + 1 ) ) | | ( x = = ( nx + 1 ) ) ) ;
assert ( ( 0 < y ) | | ( 0 = = y ) ) ;
assert ( ( x < ( ny + 1 ) ) | | ( x = = ( ny + 1 ) ) ) ;
/* Search all blocks*/
for ( iblk = 0 ; iblk < num_blocks ; iblk + + ) {
if ( ( x = = block [ iblk ] . x ) & & ( y = = block [ iblk ] . y ) & & ( z = = block [ iblk ] . z ) ) {
/* Matched cordinators*/
ret = & ( block [ iblk ] ) ;
/* Check */
assert ( block [ iblk ] . type = = grid [ x ] [ y ] . type ) ;
assert ( z < grid [ x ] [ y ] . type - > capacity ) ;
assert ( 0 < grid [ x ] [ y ] . usage ) ;
}
}
return ret ;
}
/* Change the decimal number to binary
* and return a array of integer */
int * my_decimal2binary ( int decimal ,
int * binary_len ) {
int * ret = NULL ;
int i = 0 ;
int code = decimal ;
( * binary_len ) = 0 ;
while ( 0 < code ) {
( * binary_len ) + + ;
code = code / 2 ;
}
i = ( * binary_len ) - 1 ;
while ( 0 < code ) {
ret [ i ] = code % 2 ;
i - - ;
code = code / 2 ;
}
return ret ;
}
/* Determine the number of SRAM bit for a basis subckt of a multiplexer
* In general , the number of SRAM bits should be same as the number of inputs per level
* with one exception :
* When multiplexing structure is tree - like , there should be only 1 SRAM bit
*/
int determine_num_sram_bits_mux_basis_subckt ( t_spice_model * mux_spice_model ,
int mux_size ,
int num_input_per_level ,
boolean special_basis ) {
int num_sram_bits ;
/* General cases */
switch ( mux_spice_model - > design_tech_info . structure ) {
case SPICE_MODEL_STRUCTURE_TREE :
num_sram_bits = 1 ;
break ;
case SPICE_MODEL_STRUCTURE_ONELEVEL :
case SPICE_MODEL_STRUCTURE_MULTILEVEL :
num_sram_bits = num_input_per_level ;
if ( ( 2 = = num_sram_bits ) & & ( 2 = = mux_size ) ) {
num_sram_bits = 1 ;
}
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid structure for spice model (%s)! \n " ,
__FILE__ , __LINE__ , mux_spice_model - > name ) ;
exit ( 1 ) ;
}
/* For special cases: overide the results */
if ( TRUE = = special_basis ) {
num_sram_bits = num_input_per_level ;
}
return num_sram_bits ;
}
/* Determine the level of multiplexer
*/
int determine_tree_mux_level ( int mux_size ) {
int level = 0 ;
/* Do log2(mux_size), have a basic number*/
level = ( int ) ( log ( ( double ) mux_size ) / log ( 2. ) ) ;
/* Fix the error, i.e. mux_size=5, level = 2, we have to complete */
while ( mux_size > pow ( 2. , ( double ) level ) ) {
level + + ;
}
return level ;
}
int determine_num_input_basis_multilevel_mux ( int mux_size ,
int mux_level ) {
int num_input_per_unit = 2 ;
/* Special Case: mux_size = 2 */
if ( 2 = = mux_size ) {
return mux_size ;
}
if ( 1 = = mux_level ) {
return mux_size ;
}
if ( 2 = = mux_level ) {
num_input_per_unit = ( int ) sqrt ( mux_size ) ;
while ( num_input_per_unit * num_input_per_unit < mux_size ) {
num_input_per_unit + + ;
}
return num_input_per_unit ;
}
assert ( 2 < mux_level ) ;
while ( pow ( ( double ) num_input_per_unit , ( double ) mux_level ) < mux_size ) {
num_input_per_unit + + ;
}
if ( num_input_per_unit < 2 ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Number of inputs of each basis should be at least 2! \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
return num_input_per_unit ;
}
/*Determine the number inputs required at the last level*/
int tree_mux_last_level_input_num ( int num_level ,
int mux_size ) {
int ret = 0 ;
ret = ( int ) ( pow ( 2. , ( double ) num_level ) ) - mux_size ;
if ( 0 < ret ) {
ret = ( int ) ( 2. * ( mux_size - pow ( 2. , ( double ) ( num_level - 1 ) ) ) ) ;
} else if ( 0 > ret ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])num_level(%d) is wrong with mux_size(%d)! \n " ,
__FILE__ , __LINE__ , num_level , mux_size ) ;
exit ( 1 ) ;
} else {
ret = mux_size ;
}
return ret ;
}
int multilevel_mux_last_level_input_num ( int num_level , int num_input_per_unit ,
int mux_size ) {
int ret = 0 ;
int num_basis_last_level = ( int ) ( mux_size / num_input_per_unit ) ;
int num_potential_special_inputs = 0 ;
int num_special_basis = 0 ;
int num_input_special_basis = 0 ;
ret = mux_size - num_basis_last_level * num_input_per_unit ;
assert ( ( 0 = = ret ) | | ( 0 < ret ) ) ;
/* Special Case: mux_size = 2 */
if ( 2 = = mux_size ) {
return mux_size ;
}
if ( 0 < ret ) {
/* Check if we need a special basis at last level,
* differ : the number of input of the last - 2 level will be used
*/
num_potential_special_inputs = ( num_basis_last_level + ret ) - pow ( ( double ) ( num_input_per_unit ) , ( double ) ( num_level - 1 ) ) ;
/* should be smaller than the num_input_per_unit */
assert ( ( ! ( 0 > num_potential_special_inputs ) ) & & ( num_potential_special_inputs < num_input_per_unit ) ) ;
/* We need a speical basis */
num_special_basis = pow ( ( double ) ( num_input_per_unit ) , ( double ) ( num_level - 1 ) ) - num_basis_last_level ;
if ( ret = = num_special_basis ) {
num_input_special_basis = 0 ;
} else if ( 1 = = num_special_basis ) {
num_input_special_basis = ret ;
} else {
assert ( 1 < num_special_basis ) ;
num_input_special_basis = ret - 1 ;
}
ret = num_input_special_basis + num_basis_last_level * num_input_per_unit ;
} else {
ret = mux_size ;
}
return ret ;
}
int determine_lut_path_id ( int lut_size ,
int * lut_inputs ) {
int path_id = 0 ;
int i ;
for ( i = 0 ; i < lut_size ; i + + ) {
switch ( lut_inputs [ i ] ) {
case 0 :
path_id + = ( int ) pow ( 2. , ( double ) ( i ) ) ;
break ;
case 1 :
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid sram_bits[%d]! \n " ,
__FILE__ , __LINE__ , i ) ;
exit ( 1 ) ;
}
}
return path_id ;
}
/* Decoding a one-level MUX:
* SPICE / Verilog model declare the sram port sequence as follows :
* sel0 , sel1 , . . . , selN ,
* which control the pass - gate logic connected to
* in0 , in1 , . . . , inN
* When decode the SRAM bits , we initialize every bits to zero
* And then set the sel signal corresponding to the input to be 1.
* TODO : previously the decoding is not correct , need to check any bug in SPICE part
*/
int * decode_onelevel_mux_sram_bits ( int fan_in ,
int mux_level ,
int path_id ) {
int * ret = ( int * ) my_malloc ( sizeof ( int ) * fan_in ) ;
int i ;
/* Check */
assert ( ( ! ( 0 > path_id ) ) & & ( path_id < fan_in ) ) ;
for ( i = 0 ; i < fan_in ; i + + ) {
ret [ i ] = 0 ;
}
ret [ path_id ] = 1 ;
/* ret[fan_in - 1 - path_id] = 1; */
return ret ;
}
int * decode_multilevel_mux_sram_bits ( int fan_in ,
int mux_level ,
int path_id ) {
int * ret = NULL ;
int i , j , path_differ , temp ;
int num_last_level_input , active_mux_level , active_path_id , num_input_basis ;
/* Check */
assert ( ( 0 = = path_id ) | | ( 0 < path_id ) ) ;
assert ( path_id < fan_in ) ;
/* TODO: determine the number of input of basis */
switch ( mux_level ) {
case 1 :
/* Special: 1-level should be have special care !!! */
return decode_onelevel_mux_sram_bits ( fan_in , mux_level , path_id ) ;
default :
assert ( 1 < mux_level ) ;
num_input_basis = determine_num_input_basis_multilevel_mux ( fan_in , mux_level ) ;
break ;
}
ret = ( int * ) my_malloc ( sizeof ( int ) * ( num_input_basis * mux_level ) ) ;
/* Determine last level input */
num_last_level_input = multilevel_mux_last_level_input_num ( mux_level , num_input_basis , fan_in ) ;
/* Initialize */
for ( i = 0 ; i < ( num_input_basis * mux_level ) ; i + + ) {
ret [ i ] = 0 ;
}
/* When last level input number is less than the 2**mux_level,
* There are some input at the level : ( mux_level - 1 )
*/
active_mux_level = mux_level ;
active_path_id = path_id ;
if ( num_last_level_input < fan_in ) {
if ( path_id > num_last_level_input ) {
active_mux_level = mux_level - 1 ;
active_path_id = ( int ) pow ( ( double ) num_input_basis , ( double ) ( active_mux_level ) ) - ( fan_in - path_id ) ;
}
} else {
assert ( num_last_level_input = = fan_in ) ;
}
temp = active_path_id ;
for ( i = mux_level - 1 ; i > ( mux_level - active_mux_level - 1 ) ; i - - ) {
for ( j = 0 ; j < num_input_basis ; j + + ) {
path_differ = ( j + 1 ) * ( int ) pow ( ( double ) num_input_basis , ( double ) ( i + active_mux_level - mux_level ) ) ;
if ( temp < path_differ ) {
/* This is orignal one for SPICE, but not work for VerilogGen
* I comment it here
ret [ i * num_input_basis + j ] = 1 ;
*/
ret [ ( mux_level - 1 - i ) * num_input_basis + j ] = 1 ;
/* Reduce the min. start index of this basis */
temp - = j * ( int ) pow ( ( double ) num_input_basis , ( double ) ( i + active_mux_level - mux_level ) ) ;
break ; /* Touch the boundry, stop and move onto the next level */
}
}
}
/* Check */
assert ( 0 = = temp ) ;
return ret ;
}
/* Decode the configuration to sram_bits
* A path_id is in the range of [ 0. . fan_in - 1 ]
* sram
* input0 - - - - - |
* | - - - - - output
* input1 - - - - - |
* Here , we assume ( fix ) the mux2to1 pass input0 when sram = 1 ( vdd ) , and pass input1 when sram = 0 ( gnd )
* To generate the sram bits , we can determine the in each level of MUX ,
* the path id is on the upper path ( sram = 1 ) or the lower path ( sram = 0 ) , by path_id > 2 * * mux_level
*/
int * decode_tree_mux_sram_bits ( int fan_in ,
int mux_level ,
int path_id ) {
int * ret = ( int * ) my_malloc ( sizeof ( int ) * mux_level ) ;
int i = 0 ;
int path_differ = 0 ;
int temp = 0 ;
int num_last_level_input = 0 ;
int active_mux_level = 0 ;
int active_path_id = 0 ;
/* Check */
assert ( ( 0 = = path_id ) | | ( 0 < path_id ) ) ;
assert ( path_id < fan_in ) ;
/* Determine last level input */
num_last_level_input = tree_mux_last_level_input_num ( mux_level , fan_in ) ;
/* Initialize */
for ( i = 0 ; i < mux_level ; i + + ) {
ret [ i ] = 0 ;
}
/* When last level input number is less than the 2**mux_level,
* There are some input at the level : ( mux_level - 1 )
*/
active_mux_level = mux_level ;
active_path_id = path_id ;
if ( num_last_level_input < fan_in ) {
if ( path_id > num_last_level_input ) {
active_mux_level = mux_level - 1 ;
active_path_id = ( int ) pow ( 2. , ( double ) ( active_mux_level ) ) - ( fan_in - path_id ) ;
}
} else {
assert ( num_last_level_input = = fan_in ) ;
}
temp = active_path_id ;
for ( i = mux_level - 1 ; i > ( mux_level - active_mux_level - 1 ) ; i - - ) {
path_differ = ( int ) pow ( 2. , ( double ) ( i + active_mux_level - mux_level ) ) ;
if ( temp < path_differ ) {
ret [ i ] = 1 ;
} else {
temp = temp - path_differ ;
ret [ i ] = 0 ;
}
}
/* Check */
assert ( 0 = = temp ) ;
return ret ;
}
void decode_cmos_mux_sram_bits ( t_spice_model * mux_spice_model ,
int mux_size , int path_id ,
int * bit_len , int * * conf_bits , int * mux_level ) {
/* Check */
assert ( NULL ! = mux_level ) ;
assert ( NULL ! = bit_len ) ;
assert ( NULL ! = conf_bits ) ;
assert ( ( - 1 < path_id ) & & ( path_id < mux_size ) ) ;
assert ( SPICE_MODEL_MUX = = mux_spice_model - > type ) ;
assert ( SPICE_MODEL_DESIGN_CMOS = = mux_spice_model - > design_tech ) ;
/* Initialization */
( * bit_len ) = 0 ;
( * conf_bits ) = NULL ;
/* Special for MUX-2: whatever structure it is, it has always one-level and one configuration bit */
if ( 2 = = mux_size ) {
( * bit_len ) = 1 ;
( * mux_level ) = 1 ;
( * conf_bits ) = decode_tree_mux_sram_bits ( mux_size , ( * mux_level ) , path_id ) ;
return ;
}
/* Other general cases */
switch ( mux_spice_model - > design_tech_info . structure ) {
case SPICE_MODEL_STRUCTURE_TREE :
( * mux_level ) = determine_tree_mux_level ( mux_size ) ;
( * bit_len ) = ( * mux_level ) ;
( * conf_bits ) = decode_tree_mux_sram_bits ( mux_size , ( * mux_level ) , path_id ) ;
break ;
case SPICE_MODEL_STRUCTURE_ONELEVEL :
( * mux_level ) = 1 ;
( * bit_len ) = mux_size ;
( * conf_bits ) = decode_onelevel_mux_sram_bits ( mux_size , ( * mux_level ) , path_id ) ;
break ;
case SPICE_MODEL_STRUCTURE_MULTILEVEL :
( * mux_level ) = mux_spice_model - > design_tech_info . mux_num_level ;
( * bit_len ) = determine_num_input_basis_multilevel_mux ( mux_size , ( * mux_level ) ) * ( * mux_level ) ;
( * conf_bits ) = decode_multilevel_mux_sram_bits ( mux_size , ( * mux_level ) , path_id ) ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid structure for mux_spice_model (%s)! \n " ,
__FILE__ , __LINE__ , mux_spice_model - > name ) ;
exit ( 1 ) ;
}
return ;
}
/**
* Split a string with strtok
* Store each token in a char array
* tokens ( char * * ) :
* tokens [ i ] ( char * ) : pointer to a string split by delims
*/
char * * my_strtok ( char * str ,
char * delims ,
int * len )
{
char * * ret ;
char * result ;
int cnt = 0 ;
int * lens ;
char * tmp ;
if ( NULL = = str )
{
printf ( " Warning: NULL string found in my_strtok! \n " ) ;
return NULL ;
}
tmp = my_strdup ( str ) ;
result = strtok ( tmp , delims ) ;
/*First scan to determine the size*/
while ( result ! = NULL )
{
cnt + + ;
/* strtok split until its buffer is NULL*/
result = strtok ( NULL , delims ) ;
}
//printf("1st scan cnt=%d\n",cnt);
/* Allocate memory*/
ret = ( char * * ) my_malloc ( cnt * sizeof ( char * ) ) ;
lens = ( int * ) my_malloc ( cnt * sizeof ( int ) ) ;
/*Second to determine the size of each char*/
cnt = 0 ;
memcpy ( tmp , str , strlen ( str ) + 1 ) ;
result = strtok ( tmp , delims ) ;
while ( result ! = NULL )
{
lens [ cnt ] = strlen ( result ) + 1 ;
//printf("lens[%d]=%d .",cnt,lens[cnt]);
cnt + + ;
/* strtok split until its buffer is NULL*/
result = strtok ( NULL , delims ) ;
}
//printf("\n");
/*Third to allocate and copy each char*/
cnt = 0 ;
memcpy ( tmp , str , strlen ( str ) + 1 ) ;
result = strtok ( tmp , delims ) ;
while ( result ! = NULL )
{
//printf("results[%d] = %s ",cnt,result);
ret [ cnt ] = my_strdup ( result ) ;
cnt + + ;
/* strtok split until its buffer is NULL*/
result = strtok ( NULL , delims ) ;
}
//printf("\n");
( * len ) = cnt ;
free ( tmp ) ;
return ret ;
}
2018-08-01 15:04:28 -05:00
int get_opposite_side ( int side ) {
switch ( side ) {
case 0 :
return 2 ;
case 1 :
return 3 ;
case 2 :
return 0 ;
case 3 :
return 1 ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s, [LINE%d])Invalid side index. Should be [0,3]. \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
}
2018-07-26 12:28:21 -05:00
char * convert_side_index_to_string ( int side ) {
switch ( side ) {
case 0 :
return " top " ;
case 1 :
return " right " ;
case 2 :
return " bottom " ;
case 3 :
return " left " ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s, [LINE%d])Invalid side index. Should be [0,3]. \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
}
char * convert_chan_type_to_string ( t_rr_type chan_type ) {
switch ( chan_type ) {
case CHANX :
return " chanx " ;
break ;
case CHANY :
return " chany " ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s, [LINE%d])Invalid type of channel! \n " , __FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
}
char * convert_chan_rr_node_direction_to_string ( enum PORTS chan_rr_node_direction ) {
switch ( chan_rr_node_direction ) {
case IN_PORT :
return " in " ;
break ;
case OUT_PORT :
return " out " ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s, [LINE%d])Invalid type of port! \n " , __FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
}
void init_spice_net_info ( t_spice_net_info * spice_net_info ) {
if ( NULL = = spice_net_info ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s, [LINE%d])Invalid spice_net_info! \n " , __FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
spice_net_info - > density = 0. ;
spice_net_info - > freq = 0. ;
assert ( ( 1 = = default_signal_init_value ) | | ( 0 = = default_signal_init_value ) ) ;
spice_net_info - > init_val = default_signal_init_value ;
spice_net_info - > probability = ( float ) default_signal_init_value ;
spice_net_info - > pwl = 0. ;
spice_net_info - > pwh = 0. ;
spice_net_info - > slew_rise = 0. ;
return ;
}
t_spice_model * find_iopad_spice_model ( int num_spice_model ,
t_spice_model * spice_models ) {
t_spice_model * ret = NULL ;
int imodel ;
int num_found = 0 ;
for ( imodel = 0 ; imodel < num_spice_model ; imodel + + ) {
if ( SPICE_MODEL_IOPAD = = spice_models [ imodel ] . type ) {
ret = & ( spice_models [ imodel ] ) ;
num_found + + ;
}
}
assert ( 1 = = num_found ) ;
return ret ;
}
2018-08-09 12:27:16 -05:00
/* Check if the grid coorindate given is in the range */
boolean is_grid_coordinate_in_range ( int x_min ,
int x_max ,
int grid_x ) {
/* See if x is in the range */
if ( ( x_min > grid_x )
| | ( x_max < grid_x ) ) {
return FALSE ;
}
/* Reach here, means all in the range */
return TRUE ;
}
2018-07-26 12:28:21 -05:00
char * generate_string_spice_model_type ( enum e_spice_model_type spice_model_type ) {
char * ret = NULL ;
switch ( spice_model_type ) {
case SPICE_MODEL_WIRE :
ret = " wire " ;
break ;
case SPICE_MODEL_MUX :
ret = " Multiplexer " ;
break ;
case SPICE_MODEL_LUT :
ret = " Look-Up Table " ;
break ;
case SPICE_MODEL_FF :
ret = " Flip-flop " ;
break ;
case SPICE_MODEL_SRAM :
ret = " SRAM " ;
break ;
case SPICE_MODEL_HARDLOGIC :
ret = " hard_logic " ;
break ;
case SPICE_MODEL_IOPAD :
ret = " iopad " ;
break ;
case SPICE_MODEL_SCFF :
ret = " Scan-chain Flip-flop " ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s, [LINE%d])Invalid spice_model_type! \n " , __FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
return ret ;
}
/* Deteremine the side of a io grid */
int determine_io_grid_side ( int x ,
int y ) {
/* TOP side IO of FPGA */
if ( ( ny + 1 ) = = y ) {
/* Make sure a valid x, y */
assert ( ( ! ( 0 > x ) ) & & ( x < ( nx + 1 ) ) ) ;
return BOTTOM ; /* Such I/O has only Bottom side pins */
} else if ( ( nx + 1 ) = = x ) { /* RIGHT side IO of FPGA */
/* Make sure a valid x, y */
assert ( ( ! ( 0 > y ) ) & & ( y < ( ny + 1 ) ) ) ;
return LEFT ; /* Such I/O has only Left side pins */
} else if ( 0 = = y ) { /* BOTTOM side IO of FPGA */
/* Make sure a valid x, y */
assert ( ( ! ( 0 > x ) ) & & ( x < ( nx + 1 ) ) ) ;
return TOP ; /* Such I/O has only Top side pins */
} else if ( 0 = = x ) { /* LEFT side IO of FPGA */
/* Make sure a valid x, y */
assert ( ( ! ( 0 > y ) ) & & ( y < ( ny + 1 ) ) ) ;
return RIGHT ; /* Such I/O has only Right side pins */
} else {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s, [LINE%d])I/O Grid is in the center part of FPGA! Currently unsupported! \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
}
void find_prev_rr_nodes_with_src ( t_rr_node * src_rr_node ,
int * num_drive_rr_nodes ,
t_rr_node * * * drive_rr_nodes ,
int * * switch_indices ) {
int inode , iedge , next_node ;
int cur_index , switch_index ;
assert ( NULL ! = src_rr_node ) ;
assert ( NULL ! = num_drive_rr_nodes ) ;
assert ( NULL ! = switch_indices ) ;
( * num_drive_rr_nodes ) = 0 ;
( * drive_rr_nodes ) = NULL ;
( * switch_indices ) = NULL ;
switch_index = - 1 ;
/* Determine num_drive_rr_node */
for ( inode = 0 ; inode < num_rr_nodes ; inode + + ) {
for ( iedge = 0 ; iedge < rr_node [ inode ] . num_edges ; iedge + + ) {
next_node = rr_node [ inode ] . edges [ iedge ] ;
if ( src_rr_node = = & ( rr_node [ next_node ] ) ) {
/* Get the spice_model */
if ( - 1 = = switch_index ) {
switch_index = rr_node [ inode ] . switches [ iedge ] ;
} else { /* Make sure the switches are the same*/
assert ( switch_index = = rr_node [ inode ] . switches [ iedge ] ) ;
}
( * num_drive_rr_nodes ) + + ;
}
}
}
/* Malloc */
( * drive_rr_nodes ) = ( t_rr_node * * ) my_malloc ( sizeof ( t_rr_node * ) * ( * num_drive_rr_nodes ) ) ;
( * switch_indices ) = ( int * ) my_malloc ( sizeof ( int ) * ( * num_drive_rr_nodes ) ) ;
/* Find all the rr_nodes that drive current_rr_node*/
cur_index = 0 ;
for ( inode = 0 ; inode < num_rr_nodes ; inode + + ) {
for ( iedge = 0 ; iedge < rr_node [ inode ] . num_edges ; iedge + + ) {
next_node = rr_node [ inode ] . edges [ iedge ] ;
if ( src_rr_node = = & ( rr_node [ next_node ] ) ) {
/* Update drive_rr_nodes list */
( * drive_rr_nodes ) [ cur_index ] = & ( rr_node [ inode ] ) ;
( * switch_indices ) [ cur_index ] = rr_node [ inode ] . switches [ iedge ] ;
cur_index + + ;
}
}
}
assert ( cur_index = = ( * num_drive_rr_nodes ) ) ;
return ;
}
int find_path_id_prev_rr_node ( int num_drive_rr_nodes ,
t_rr_node * * drive_rr_nodes ,
t_rr_node * src_rr_node ) {
int path_id , inode ;
/* Configuration bits for this MUX*/
path_id = - 1 ;
for ( inode = 0 ; inode < num_drive_rr_nodes ; inode + + ) {
if ( drive_rr_nodes [ inode ] = = & ( rr_node [ src_rr_node - > prev_node ] ) ) {
path_id = inode ;
break ;
}
}
assert ( ( - 1 ! = path_id ) & & ( path_id < src_rr_node - > fan_in ) ) ;
return path_id ;
}
int pb_pin_net_num ( t_rr_node * pb_rr_graph ,
t_pb_graph_pin * pin ) {
int net_num = OPEN ;
if ( NULL = = pb_rr_graph ) {
/* Try the temp_net_num in pb_graph_pin */
net_num = pin - > temp_net_num ;
} else {
net_num = pb_rr_graph [ pin - > pin_count_in_cluster ] . net_num ;
}
return net_num ;
}
float pb_pin_density ( t_rr_node * pb_rr_graph ,
t_pb_graph_pin * pin ) {
float density = 0. ;
int net_num ;
if ( NULL = = pb_rr_graph ) {
/* Try the temp_net_num in pb_graph_pin */
net_num = pin - > temp_net_num ;
if ( OPEN ! = net_num ) {
density = vpack_net [ net_num ] . spice_net_info - > density ;
}
return density ;
}
net_num = pb_rr_graph [ pin - > pin_count_in_cluster ] . net_num ;
if ( OPEN ! = net_num ) {
density = vpack_net [ net_num ] . spice_net_info - > density ;
}
return density ;
}
float pb_pin_probability ( t_rr_node * pb_rr_graph ,
t_pb_graph_pin * pin ) {
float probability = ( float ) ( default_signal_init_value ) ;
int net_num ;
if ( NULL = = pb_rr_graph ) {
/* Try the temp_net_num in pb_graph_pin */
net_num = pin - > temp_net_num ;
if ( OPEN ! = net_num ) {
probability = vpack_net [ net_num ] . spice_net_info - > probability ;
}
return probability ;
}
net_num = pb_rr_graph [ pin - > pin_count_in_cluster ] . net_num ;
if ( OPEN ! = net_num ) {
probability = vpack_net [ net_num ] . spice_net_info - > probability ;
}
return probability ;
}
int pb_pin_init_value ( t_rr_node * pb_rr_graph ,
t_pb_graph_pin * pin ) {
float init_val = ( float ) ( default_signal_init_value ) ;
int net_num ;
if ( NULL = = pb_rr_graph ) {
/* TODO: we know initialize to vdd could reduce the leakage power od multiplexers!
* But I can this as an option !
*/
/* Try the temp_net_num in pb_graph_pin */
net_num = pin - > temp_net_num ;
if ( OPEN ! = net_num ) {
init_val = vpack_net [ net_num ] . spice_net_info - > init_val ;
}
return init_val ;
}
net_num = pb_rr_graph [ pin - > pin_count_in_cluster ] . net_num ;
if ( OPEN ! = net_num ) {
init_val = vpack_net [ net_num ] . spice_net_info - > init_val ;
}
return init_val ;
}
float get_rr_node_net_density ( t_rr_node node ) {
/* If we found this net is OPEN, we assume it zero-density */
if ( OPEN = = node . vpack_net_num ) {
return 0. ;
} else {
return vpack_net [ node . vpack_net_num ] . spice_net_info - > density ;
}
}
float get_rr_node_net_probability ( t_rr_node node ) {
/* If we found this net is OPEN, we assume it zero-probability */
if ( OPEN = = node . vpack_net_num ) {
/* TODO: we know initialize to vdd could reduce the leakage power od multiplexers!
* But I can this as an option !
*/
return ( float ) ( default_signal_init_value ) ;
} else {
return vpack_net [ node . vpack_net_num ] . spice_net_info - > probability ;
}
}
int get_rr_node_net_init_value ( t_rr_node node ) {
/* If we found this net is OPEN, we assume it zero-probability */
if ( OPEN = = node . vpack_net_num ) {
/* TODO: we know initialize to vdd could reduce the leakage power od multiplexers!
* But I can this as an option !
*/
return ( float ) ( default_signal_init_value ) ;
} else {
return vpack_net [ node . vpack_net_num ] . spice_net_info - > init_val ;
}
}
int find_parent_pb_type_child_index ( t_pb_type * parent_pb_type ,
int mode_index ,
t_pb_type * child_pb_type ) {
int i ;
assert ( NULL ! = parent_pb_type ) ;
assert ( NULL ! = child_pb_type ) ;
assert ( ( ! ( 0 > mode_index ) ) & & ( mode_index < parent_pb_type - > num_modes ) ) ;
for ( i = 0 ; i < parent_pb_type - > modes [ mode_index ] . num_pb_type_children ; i + + ) {
if ( child_pb_type = = & ( parent_pb_type - > modes [ mode_index ] . pb_type_children [ i ] ) ) {
assert ( 0 = = strcmp ( child_pb_type - > name , parent_pb_type - > modes [ mode_index ] . pb_type_children [ i ] . name ) ) ;
return i ;
}
}
return - 1 ;
}
/* Rule in generating a unique name:
* name of current pb = < parent_pb_name_tag > _ < cur_pb_graph_node > [ index ]
*/
void gen_spice_name_tag_pb_rec ( t_pb * cur_pb ,
char * prefix ) {
char * prefix_rec = NULL ;
int ipb , jpb , mode_index ;
mode_index = cur_pb - > mode ;
/* Free previous name_tag if there is */
/* my_free(cur_pb->spice_name_tag); */
/* Generate the name_tag */
if ( ( 0 < cur_pb - > pb_graph_node - > pb_type - > num_modes )
& & ( NULL = = cur_pb - > pb_graph_node - > pb_type - > spice_model_name ) ) {
prefix_rec = ( char * ) my_malloc ( sizeof ( char ) * ( strlen ( prefix ) + 1 + strlen ( cur_pb - > pb_graph_node - > pb_type - > name ) + 1
+ strlen ( my_itoa ( cur_pb - > pb_graph_node - > placement_index ) ) + 7 + strlen ( cur_pb - > pb_graph_node - > pb_type - > modes [ mode_index ] . name ) + 2 ) ) ;
sprintf ( prefix_rec , " %s_%s[%d]_mode[%s] " ,
prefix , cur_pb - > pb_graph_node - > pb_type - > name , cur_pb - > pb_graph_node - > placement_index , cur_pb - > pb_graph_node - > pb_type - > modes [ mode_index ] . name ) ;
cur_pb - > spice_name_tag = my_strdup ( prefix_rec ) ;
} else {
assert ( ( 0 = = cur_pb - > pb_graph_node - > pb_type - > num_modes )
| | ( NULL ! = cur_pb - > pb_graph_node - > pb_type - > spice_model_name ) ) ;
prefix_rec = ( char * ) my_malloc ( sizeof ( char ) * ( strlen ( prefix ) + 1 + strlen ( cur_pb - > pb_graph_node - > pb_type - > name ) + 1
+ strlen ( my_itoa ( cur_pb - > pb_graph_node - > placement_index ) ) + 2 ) ) ;
sprintf ( prefix_rec , " %s_%s[%d] " ,
prefix , cur_pb - > pb_graph_node - > pb_type - > name , cur_pb - > pb_graph_node - > placement_index ) ;
cur_pb - > spice_name_tag = my_strdup ( prefix_rec ) ;
}
/* When reach the leaf, we directly return */
/* Recursive until reach the leaf */
if ( ( 0 = = cur_pb - > pb_graph_node - > pb_type - > num_modes )
| | ( NULL = = cur_pb - > child_pbs ) ) {
return ;
}
for ( ipb = 0 ; ipb < cur_pb - > pb_graph_node - > pb_type - > modes [ mode_index ] . num_pb_type_children ; ipb + + ) {
for ( jpb = 0 ; jpb < cur_pb - > pb_graph_node - > pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . num_pb ; jpb + + ) {
/* Refer to pack/output_clustering.c [LINE 392] */
//if ((NULL != cur_pb->child_pbs[ipb])&&(NULL != cur_pb->child_pbs[ipb][jpb].name)) {
/* Try to simplify the name tag... to avoid exceeding the length of SPICE name (up to 1024 chars) */
/* gen_spice_name_tag_pb_rec(&(cur_pb->child_pbs[ipb][jpb]),prefix); */
gen_spice_name_tag_pb_rec ( & ( cur_pb - > child_pbs [ ipb ] [ jpb ] ) , prefix_rec ) ;
//}
}
}
my_free ( prefix_rec ) ;
return ;
}
/* Generate a unique name tag for each pb,
* to identify it in both SPICE netlist and Power Modeling .
*/
void gen_spice_name_tags_all_pbs ( ) {
int iblk ;
char * prefix = NULL ;
for ( iblk = 0 ; iblk < num_blocks ; iblk + + ) {
prefix = ( char * ) my_malloc ( sizeof ( char ) * ( 5 + strlen ( my_itoa ( block [ iblk ] . x ) ) + 2 + strlen ( my_itoa ( block [ iblk ] . y ) ) + 2 ) ) ;
sprintf ( prefix , " grid[%d][%d] " , block [ iblk ] . x , block [ iblk ] . y ) ;
gen_spice_name_tag_pb_rec ( block [ iblk ] . pb , prefix ) ;
my_free ( prefix ) ;
}
return ;
}
/* Make sure the edge has only one input pin and output pin*/
void check_pb_graph_edge ( t_pb_graph_edge pb_graph_edge ) {
assert ( 1 = = pb_graph_edge . num_input_pins ) ;
assert ( 1 = = pb_graph_edge . num_output_pins ) ;
return ;
}
/* Check all the edges for a given pb_graph_pin*/
void check_pb_graph_pin_edges ( t_pb_graph_pin pb_graph_pin ) {
int iedge ;
for ( iedge = 0 ; iedge < pb_graph_pin . num_input_edges ; iedge + + ) {
check_pb_graph_edge ( * ( pb_graph_pin . input_edges [ iedge ] ) ) ;
}
for ( iedge = 0 ; iedge < pb_graph_pin . num_output_edges ; iedge + + ) {
check_pb_graph_edge ( * ( pb_graph_pin . output_edges [ iedge ] ) ) ;
}
return ;
}
int find_pb_mapped_logical_block_rec ( t_pb * cur_pb ,
t_spice_model * pb_spice_model ,
char * pb_spice_name_tag ) {
int logical_block_index = OPEN ;
int mode_index , ipb , jpb ;
assert ( NULL ! = cur_pb ) ;
if ( ( pb_spice_model = = cur_pb - > pb_graph_node - > pb_type - > spice_model )
& & ( 0 = = strcmp ( cur_pb - > spice_name_tag , pb_spice_name_tag ) ) ) {
2018-08-01 15:04:28 -05:00
/* Return the logic block we may find */
switch ( pb_spice_model - > type ) {
case SPICE_MODEL_LUT :
/* Special for LUT... They have sub modes!!!*/
2018-07-26 12:28:21 -05:00
assert ( NULL ! = cur_pb - > child_pbs ) ;
return cur_pb - > child_pbs [ 0 ] [ 0 ] . logical_block ;
2018-08-01 15:04:28 -05:00
case SPICE_MODEL_FF :
assert ( pb_spice_model = = logical_block [ cur_pb - > logical_block ] . mapped_spice_model ) ;
return cur_pb - > logical_block ;
case SPICE_MODEL_HARDLOGIC :
if ( NULL ! = cur_pb - > child_pbs ) {
return cur_pb - > child_pbs [ 0 ] [ 0 ] . logical_block ;
} else {
assert ( pb_spice_model = = logical_block [ cur_pb - > logical_block ] . mapped_spice_model ) ;
return cur_pb - > logical_block ;
}
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid spice model type! \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
2018-07-26 12:28:21 -05:00
}
}
/* Go recursively ... */
mode_index = cur_pb - > mode ;
if ( 0 = = cur_pb - > pb_graph_node - > pb_type - > num_modes ) {
return logical_block_index ;
}
for ( ipb = 0 ; ipb < cur_pb - > pb_graph_node - > pb_type - > modes [ mode_index ] . num_pb_type_children ; ipb + + ) {
for ( jpb = 0 ; jpb < cur_pb - > pb_graph_node - > pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . num_pb ; jpb + + ) {
/* Refer to pack/output_clustering.c [LINE 392] */
if ( ( NULL ! = cur_pb - > child_pbs [ ipb ] ) & & ( NULL ! = cur_pb - > child_pbs [ ipb ] [ jpb ] . name ) ) {
logical_block_index =
find_pb_mapped_logical_block_rec ( & ( cur_pb - > child_pbs [ ipb ] [ jpb ] ) , pb_spice_model , pb_spice_name_tag ) ;
if ( OPEN ! = logical_block_index ) {
return logical_block_index ;
}
}
}
}
return logical_block_index ;
}
int find_grid_mapped_logical_block ( int x , int y ,
t_spice_model * pb_spice_model ,
char * pb_spice_name_tag ) {
int logical_block_index = OPEN ;
int iblk ;
/* Find the grid usage */
if ( 0 = = grid [ x ] [ y ] . usage ) {
return logical_block_index ;
} else {
assert ( 0 < grid [ x ] [ y ] . usage ) ;
/* search each block */
for ( iblk = 0 ; iblk < grid [ x ] [ y ] . usage ; iblk + + ) {
/* Get the pb */
logical_block_index = find_pb_mapped_logical_block_rec ( block [ grid [ x ] [ y ] . blocks [ iblk ] ] . pb ,
pb_spice_model , pb_spice_name_tag ) ;
if ( OPEN ! = logical_block_index ) {
return logical_block_index ;
}
}
}
return logical_block_index ;
}
void stats_pb_graph_node_port_pin_numbers ( t_pb_graph_node * cur_pb_graph_node ,
int * num_inputs ,
int * num_outputs ,
int * num_clock_pins ) {
int iport ;
assert ( NULL ! = cur_pb_graph_node ) ;
( * num_inputs ) = 0 ;
for ( iport = 0 ; iport < cur_pb_graph_node - > num_input_ports ; iport + + ) {
( * num_inputs ) + = cur_pb_graph_node - > num_input_pins [ iport ] ;
}
( * num_outputs ) = 0 ;
for ( iport = 0 ; iport < cur_pb_graph_node - > num_output_ports ; iport + + ) {
( * num_outputs ) + = cur_pb_graph_node - > num_output_pins [ iport ] ;
}
( * num_clock_pins ) = 0 ;
for ( iport = 0 ; iport < cur_pb_graph_node - > num_clock_ports ; iport + + ) {
( * num_clock_pins ) + = cur_pb_graph_node - > num_clock_pins [ iport ] ;
}
return ;
}
int recommend_num_sim_clock_cycle ( float sim_window_size ) {
float avg_density = 0. ;
float median_density = 0. ;
int recmd_num_sim_clock_cycle = 0 ;
int inet , jnet ;
int net_cnt = 0 ;
float * density_value = NULL ;
int * sort_index = NULL ;
int * net_to_sort_index_mapping = NULL ;
float weighted_avg_density = 0. ;
float net_weight = 0. ;
int weighted_net_cnt = 0 ;
/* get the average density of all the nets */
for ( inet = 0 ; inet < num_logical_nets ; inet + + ) {
assert ( NULL ! = vpack_net [ inet ] . spice_net_info ) ;
if ( ( FALSE = = vpack_net [ inet ] . is_global )
& & ( FALSE = = vpack_net [ inet ] . is_const_gen )
& & ( 0. ! = vpack_net [ inet ] . spice_net_info - > density ) ) {
avg_density + = vpack_net [ inet ] . spice_net_info - > density ;
net_cnt + + ;
/* Consider the weight of fan-out */
if ( 0 = = vpack_net [ inet ] . num_sinks ) {
net_weight = 1 ;
} else {
assert ( 0 < vpack_net [ inet ] . num_sinks ) ;
net_weight = vpack_net [ inet ] . num_sinks ;
}
weighted_avg_density + = vpack_net [ inet ] . spice_net_info - > density * net_weight ;
weighted_net_cnt + = net_weight ;
}
}
avg_density = avg_density / net_cnt ;
weighted_avg_density = weighted_avg_density / weighted_net_cnt ;
/* Fill the array to be sorted */
density_value = ( float * ) my_malloc ( sizeof ( float ) * net_cnt ) ;
sort_index = ( int * ) my_malloc ( sizeof ( int ) * net_cnt ) ;
net_to_sort_index_mapping = ( int * ) my_malloc ( sizeof ( int ) * net_cnt ) ;
jnet = 0 ;
for ( inet = 0 ; inet < num_logical_nets ; inet + + ) {
assert ( NULL ! = vpack_net [ inet ] . spice_net_info ) ;
if ( ( FALSE = = vpack_net [ inet ] . is_global )
& & ( FALSE = = vpack_net [ inet ] . is_const_gen )
& & ( 0. ! = vpack_net [ inet ] . spice_net_info - > density ) ) {
sort_index [ jnet ] = jnet ;
net_to_sort_index_mapping [ jnet ] = inet ;
density_value [ jnet ] = vpack_net [ inet ] . spice_net_info - > density ;
jnet + + ;
}
}
assert ( jnet = = net_cnt ) ;
/* Sort the density */
quicksort_float_index ( net_cnt , sort_index , density_value ) ;
/* Get the median */
median_density = vpack_net [ sort_index [ ( int ) ( 0.5 * net_cnt ) ] ] . spice_net_info - > density ;
/* It may be more reasonable to use median
* But , if median density is 0 , we use average density
*/
2018-08-10 14:46:00 -05:00
if ( ( 0. = = median_density ) & & ( 0. = = avg_density ) ) {
2018-07-26 12:28:21 -05:00
recmd_num_sim_clock_cycle = 1 ;
vpr_printf ( TIO_MESSAGE_WARNING ,
" All the signal density is zero! No. of clock cycles in simulations are set to be %d! " ,
recmd_num_sim_clock_cycle ) ;
2018-08-10 14:46:00 -05:00
} else if ( 0. = = avg_density ) {
recmd_num_sim_clock_cycle = ( int ) round ( 1 / median_density ) ;
} else if ( 0. = = median_density ) {
recmd_num_sim_clock_cycle = ( int ) round ( 1 / avg_density ) ;
2018-07-26 12:28:21 -05:00
} else {
/* add a sim window size to balance the weight of average density and median density
* In practice , we find that there could be huge difference between avereage and median values
* For a reasonable number of simulation clock cycles , we do this window size .
*/
recmd_num_sim_clock_cycle = ( int ) round ( 1 / ( sim_window_size * avg_density + ( 1 - sim_window_size ) * median_density ) ) ;
}
assert ( 0 < recmd_num_sim_clock_cycle ) ;
vpr_printf ( TIO_MESSAGE_INFO , " Average net density: %.2f \n " , avg_density ) ;
vpr_printf ( TIO_MESSAGE_INFO , " Median net density: %.2f \n " , median_density ) ;
vpr_printf ( TIO_MESSAGE_INFO , " Average net densityi after weighting: %.2f \n " , weighted_avg_density ) ;
vpr_printf ( TIO_MESSAGE_INFO , " Window size set for Simulation: %.2f \n " , sim_window_size ) ;
vpr_printf ( TIO_MESSAGE_INFO , " Net density after Window size : %.2f \n " ,
( sim_window_size * avg_density + ( 1 - sim_window_size ) * median_density ) ) ;
vpr_printf ( TIO_MESSAGE_INFO , " Recommend no. of clock cycles: %d \n " , recmd_num_sim_clock_cycle ) ;
/* Free */
my_free ( sort_index ) ;
my_free ( density_value ) ;
my_free ( net_to_sort_index_mapping ) ;
return recmd_num_sim_clock_cycle ;
}
void auto_select_num_sim_clock_cycle ( t_spice * spice ,
float sim_window_size ) {
int recmd_num_sim_clock_cycle = recommend_num_sim_clock_cycle ( sim_window_size ) ;
/* Auto select number of simulation clock cycles*/
if ( - 1 = = spice - > spice_params . meas_params . sim_num_clock_cycle ) {
vpr_printf ( TIO_MESSAGE_INFO , " Auto select the no. of clock cycles in simulation: %d \n " , recmd_num_sim_clock_cycle ) ;
spice - > spice_params . meas_params . sim_num_clock_cycle = recmd_num_sim_clock_cycle ;
} else {
vpr_printf ( TIO_MESSAGE_INFO , " No. of clock cycles in simulation is forced to be: %d \n " ,
spice - > spice_params . meas_params . sim_num_clock_cycle ) ;
}
return ;
}
/* Malloc grid_index_low and grid_index_high for a spice_model */
void alloc_spice_model_grid_index_low_high ( t_spice_model * cur_spice_model ) {
int ix , iy ;
/* grid_index_low */
/* x - direction*/
cur_spice_model - > grid_index_low = ( int * * ) my_malloc ( sizeof ( int * ) * ( nx + 2 ) ) ;
/* y - direction*/
for ( ix = 0 ; ix < ( nx + 2 ) ; ix + + ) {
cur_spice_model - > grid_index_low [ ix ] = ( int * ) my_malloc ( sizeof ( int ) * ( ny + 2 ) ) ;
}
/* Initialize */
for ( ix = 0 ; ix < ( nx + 2 ) ; ix + + ) {
for ( iy = 0 ; iy < ( ny + 2 ) ; iy + + ) {
cur_spice_model - > grid_index_low [ ix ] [ iy ] = 0 ;
}
}
/* grid_index_high */
/* x - direction*/
cur_spice_model - > grid_index_high = ( int * * ) my_malloc ( sizeof ( int * ) * ( nx + 2 ) ) ;
/* y - direction*/
for ( ix = 0 ; ix < ( nx + 2 ) ; ix + + ) {
cur_spice_model - > grid_index_high [ ix ] = ( int * ) my_malloc ( sizeof ( int ) * ( ny + 2 ) ) ;
}
/* Initialize */
for ( ix = 0 ; ix < ( nx + 2 ) ; ix + + ) {
for ( iy = 0 ; iy < ( ny + 2 ) ; iy + + ) {
cur_spice_model - > grid_index_high [ ix ] [ iy ] = 0 ;
}
}
return ;
}
void free_one_spice_model_grid_index_low_high ( t_spice_model * cur_spice_model ) {
int ix ;
for ( ix = 0 ; ix < ( nx + 2 ) ; ix + + ) {
my_free ( cur_spice_model - > grid_index_high [ ix ] ) ;
my_free ( cur_spice_model - > grid_index_low [ ix ] ) ;
}
my_free ( cur_spice_model - > grid_index_high ) ;
my_free ( cur_spice_model - > grid_index_low ) ;
return ;
}
void free_spice_model_grid_index_low_high ( int num_spice_models ,
t_spice_model * spice_model ) {
int i ;
for ( i = 0 ; i < num_spice_models ; i + + ) {
free_one_spice_model_grid_index_low_high ( & ( spice_model [ i ] ) ) ;
}
return ;
}
void update_one_spice_model_grid_index_low ( int x , int y ,
t_spice_model * cur_spice_model ) {
/* Check */
assert ( ( ! ( 0 > x ) ) & & ( ! ( x > ( nx + 1 ) ) ) ) ;
assert ( ( ! ( 0 > y ) ) & & ( ! ( y > ( ny + 1 ) ) ) ) ;
assert ( NULL ! = cur_spice_model ) ;
assert ( NULL ! = cur_spice_model - > grid_index_low ) ;
assert ( NULL ! = cur_spice_model - > grid_index_low [ x ] ) ;
/* Assigne the low */
cur_spice_model - > grid_index_low [ x ] [ y ] = cur_spice_model - > cnt ;
return ;
}
void update_spice_models_grid_index_low ( int x , int y ,
int num_spice_models ,
t_spice_model * spice_model ) {
int i ;
for ( i = 0 ; i < num_spice_models ; i + + ) {
update_one_spice_model_grid_index_low ( x , y , & ( spice_model [ i ] ) ) ;
}
return ;
}
void update_one_spice_model_grid_index_high ( int x , int y ,
t_spice_model * cur_spice_model ) {
/* Check */
assert ( ( ! ( 0 > x ) ) & & ( ! ( x > ( nx + 1 ) ) ) ) ;
assert ( ( ! ( 0 > y ) ) & & ( ! ( y > ( ny + 1 ) ) ) ) ;
assert ( NULL ! = cur_spice_model ) ;
assert ( NULL ! = cur_spice_model - > grid_index_high ) ;
assert ( NULL ! = cur_spice_model - > grid_index_high [ x ] ) ;
/* Assigne the low */
cur_spice_model - > grid_index_high [ x ] [ y ] = cur_spice_model - > cnt ;
return ;
}
void update_spice_models_grid_index_high ( int x , int y ,
int num_spice_models ,
t_spice_model * spice_model ) {
int i ;
for ( i = 0 ; i < num_spice_models ; i + + ) {
update_one_spice_model_grid_index_high ( x , y , & ( spice_model [ i ] ) ) ;
}
return ;
}
void zero_one_spice_model_grid_index_low_high ( t_spice_model * cur_spice_model ) {
int ix , iy ;
/* Initialize */
for ( ix = 0 ; ix < ( nx + 2 ) ; ix + + ) {
for ( iy = 0 ; iy < ( ny + 2 ) ; iy + + ) {
cur_spice_model - > grid_index_high [ ix ] [ iy ] = 0 ;
cur_spice_model - > grid_index_low [ ix ] [ iy ] = 0 ;
}
}
return ;
}
void zero_spice_model_grid_index_low_high ( int num_spice_models ,
t_spice_model * spice_model ) {
int i ;
for ( i = 0 ; i < num_spice_models ; i + + ) {
zero_one_spice_model_grid_index_low_high ( & ( spice_model [ i ] ) ) ;
}
return ;
}
char * gen_str_spice_model_structure ( enum e_spice_model_structure spice_model_structure ) {
switch ( spice_model_structure ) {
case SPICE_MODEL_STRUCTURE_TREE :
return " tree-like " ;
case SPICE_MODEL_STRUCTURE_ONELEVEL :
return " one-level " ;
case SPICE_MODEL_STRUCTURE_MULTILEVEL :
return " multi-level " ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid spice model structure! \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
}
/* Check if the spice model structure is the same with the switch_inf structure */
boolean check_spice_model_structure_match_switch_inf ( t_switch_inf target_switch_inf ) {
assert ( NULL ! = target_switch_inf . spice_model ) ;
if ( target_switch_inf . structure ! = target_switch_inf . spice_model - > design_tech_info . structure ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Structure in spice_model(%s) is different from switch_inf[%s]! \n " ,
__FILE__ , __LINE__ , target_switch_inf . spice_model - > name , target_switch_inf . name ) ;
return FALSE ;
}
return TRUE ;
}
int find_pb_type_idle_mode_index ( t_pb_type cur_pb_type ) {
int idle_mode_index = 0 ;
int imode = 0 ;
int num_idle_mode = 0 ;
/* if we touch the leaf node */
if ( NULL ! = cur_pb_type . blif_model ) {
return 0 ;
}
if ( 0 = = cur_pb_type . num_modes ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Intend to find the idle mode while cur_pb_type has 0 modes! \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
/* Normal Condition: */
for ( imode = 0 ; imode < cur_pb_type . num_modes ; imode + + ) {
if ( 1 = = cur_pb_type . modes [ imode ] . define_idle_mode ) {
idle_mode_index = imode ;
num_idle_mode + + ;
}
}
2018-08-01 15:04:28 -05:00
2018-07-26 12:28:21 -05:00
assert ( 1 = = num_idle_mode ) ;
return idle_mode_index ;
}
/* Find the physical mode index */
int find_pb_type_physical_mode_index ( t_pb_type cur_pb_type ) {
int phy_mode_index = 0 ;
int imode = 0 ;
int num_phy_mode = 0 ;
/* if we touch the leaf node */
if ( NULL ! = cur_pb_type . blif_model ) {
return 0 ;
}
if ( 0 = = cur_pb_type . num_modes ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Intend to find the idle mode while cur_pb_type has 0 modes! \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
/* Normal Condition: */
for ( imode = 0 ; imode < cur_pb_type . num_modes ; imode + + ) {
if ( 1 = = cur_pb_type . modes [ imode ] . define_physical_mode ) {
phy_mode_index = imode ;
num_phy_mode + + ;
}
}
assert ( 1 = = num_phy_mode ) ;
return phy_mode_index ;
}
void mark_grid_type_pb_graph_node_pins_temp_net_num ( int x , int y ) {
int iport , ipin , type_pin_index , class_id , pin_global_rr_node_id ;
t_type_ptr type = NULL ;
t_pb_graph_node * top_pb_graph_node = NULL ;
int mode_index , ipb , jpb ;
/* Assert */
assert ( ( ! ( x < 0 ) ) & & ( x < ( nx + 2 ) ) ) ;
assert ( ( ! ( y < 0 ) ) & & ( y < ( ny + 2 ) ) ) ;
type = grid [ x ] [ y ] . type ;
if ( EMPTY_TYPE = = type ) {
return ; /* Bypass empty grid */
}
top_pb_graph_node = type - > pb_graph_head ;
/* Input ports */
for ( iport = 0 ; iport < top_pb_graph_node - > num_input_ports ; iport + + ) {
for ( ipin = 0 ; ipin < top_pb_graph_node - > num_input_pins [ iport ] ; ipin + + ) {
top_pb_graph_node - > input_pins [ iport ] [ ipin ] . temp_net_num = OPEN ;
type_pin_index = top_pb_graph_node - > input_pins [ iport ] [ ipin ] . pin_count_in_cluster ;
class_id = type - > pin_class [ type_pin_index ] ;
assert ( RECEIVER = = type - > class_inf [ class_id ] . type ) ;
/* Find the pb net_num and update OPIN net_num */
pin_global_rr_node_id = get_rr_node_index ( x , y , IPIN , type_pin_index , rr_node_indices ) ;
if ( OPEN = = rr_node [ pin_global_rr_node_id ] . net_num ) {
top_pb_graph_node - > input_pins [ iport ] [ ipin ] . temp_net_num = OPEN ;
continue ;
}
top_pb_graph_node - > input_pins [ iport ] [ ipin ] . temp_net_num = clb_to_vpack_net_mapping [ rr_node [ pin_global_rr_node_id ] . net_num ] ;
}
}
/* clock ports */
for ( iport = 0 ; iport < top_pb_graph_node - > num_clock_ports ; iport + + ) {
for ( ipin = 0 ; ipin < top_pb_graph_node - > num_clock_pins [ iport ] ; ipin + + ) {
top_pb_graph_node - > clock_pins [ iport ] [ ipin ] . temp_net_num = OPEN ;
type_pin_index = top_pb_graph_node - > clock_pins [ iport ] [ ipin ] . pin_count_in_cluster ;
class_id = type - > pin_class [ type_pin_index ] ;
assert ( RECEIVER = = type - > class_inf [ class_id ] . type ) ;
/* Find the pb net_num and update OPIN net_num */
pin_global_rr_node_id = get_rr_node_index ( x , y , IPIN , type_pin_index , rr_node_indices ) ;
if ( OPEN = = rr_node [ pin_global_rr_node_id ] . net_num ) {
top_pb_graph_node - > clock_pins [ iport ] [ ipin ] . temp_net_num = OPEN ;
continue ;
}
top_pb_graph_node - > clock_pins [ iport ] [ ipin ] . temp_net_num = clb_to_vpack_net_mapping [ rr_node [ pin_global_rr_node_id ] . net_num ] ;
}
}
/* Go recursively ... */
mode_index = find_pb_type_idle_mode_index ( * ( top_pb_graph_node - > pb_type ) ) ;
for ( ipb = 0 ; ipb < top_pb_graph_node - > pb_type - > modes [ mode_index ] . num_pb_type_children ; ipb + + ) {
for ( jpb = 0 ; jpb < top_pb_graph_node - > pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . num_pb ; jpb + + ) {
/* Mark pb_graph_node temp_net_num */
rec_mark_pb_graph_node_temp_net_num ( & ( top_pb_graph_node - > child_pb_graph_nodes [ mode_index ] [ ipb ] [ jpb ] ) ) ;
}
}
/* Output ports */
for ( iport = 0 ; iport < top_pb_graph_node - > num_output_ports ; iport + + ) {
for ( ipin = 0 ; ipin < top_pb_graph_node - > num_output_pins [ iport ] ; ipin + + ) {
top_pb_graph_node - > output_pins [ iport ] [ ipin ] . temp_net_num = OPEN ;
type_pin_index = top_pb_graph_node - > output_pins [ iport ] [ ipin ] . pin_count_in_cluster ;
class_id = type - > pin_class [ type_pin_index ] ;
assert ( DRIVER = = type - > class_inf [ class_id ] . type ) ;
/* Find the pb net_num and update OPIN net_num */
pin_global_rr_node_id = get_rr_node_index ( x , y , OPIN , type_pin_index , rr_node_indices ) ;
if ( OPEN = = rr_node [ pin_global_rr_node_id ] . net_num ) {
top_pb_graph_node - > output_pins [ iport ] [ ipin ] . temp_net_num = OPEN ;
continue ;
}
top_pb_graph_node - > output_pins [ iport ] [ ipin ] . temp_net_num = clb_to_vpack_net_mapping [ rr_node [ pin_global_rr_node_id ] . net_num ] ;
}
}
/* Run again to handle feedback loop */
/* Input ports */
for ( iport = 0 ; iport < top_pb_graph_node - > num_input_ports ; iport + + ) {
for ( ipin = 0 ; ipin < top_pb_graph_node - > num_input_pins [ iport ] ; ipin + + ) {
top_pb_graph_node - > input_pins [ iport ] [ ipin ] . temp_net_num = OPEN ;
type_pin_index = top_pb_graph_node - > input_pins [ iport ] [ ipin ] . pin_count_in_cluster ;
class_id = type - > pin_class [ type_pin_index ] ;
assert ( RECEIVER = = type - > class_inf [ class_id ] . type ) ;
/* Find the pb net_num and update OPIN net_num */
pin_global_rr_node_id = get_rr_node_index ( x , y , IPIN , type_pin_index , rr_node_indices ) ;
if ( OPEN = = rr_node [ pin_global_rr_node_id ] . net_num ) {
top_pb_graph_node - > input_pins [ iport ] [ ipin ] . temp_net_num = OPEN ;
continue ;
}
top_pb_graph_node - > input_pins [ iport ] [ ipin ] . temp_net_num = clb_to_vpack_net_mapping [ rr_node [ pin_global_rr_node_id ] . net_num ] ;
}
}
/* clock ports */
for ( iport = 0 ; iport < top_pb_graph_node - > num_clock_ports ; iport + + ) {
for ( ipin = 0 ; ipin < top_pb_graph_node - > num_clock_pins [ iport ] ; ipin + + ) {
top_pb_graph_node - > clock_pins [ iport ] [ ipin ] . temp_net_num = OPEN ;
type_pin_index = top_pb_graph_node - > clock_pins [ iport ] [ ipin ] . pin_count_in_cluster ;
class_id = type - > pin_class [ type_pin_index ] ;
assert ( RECEIVER = = type - > class_inf [ class_id ] . type ) ;
/* Find the pb net_num and update OPIN net_num */
pin_global_rr_node_id = get_rr_node_index ( x , y , IPIN , type_pin_index , rr_node_indices ) ;
if ( OPEN = = rr_node [ pin_global_rr_node_id ] . net_num ) {
top_pb_graph_node - > clock_pins [ iport ] [ ipin ] . temp_net_num = OPEN ;
continue ;
}
top_pb_graph_node - > clock_pins [ iport ] [ ipin ] . temp_net_num = clb_to_vpack_net_mapping [ rr_node [ pin_global_rr_node_id ] . net_num ] ;
}
}
return ;
}
/* Assign the temp_net_num by considering the first incoming edge that belongs to the correct operating mode */
void assign_pb_graph_node_pin_temp_net_num_by_mode_index ( t_pb_graph_pin * cur_pb_graph_pin ,
int mode_index ) {
int iedge ;
/* IMPORTANT: I assume by default the index of selected edge is 0
* Make sure this input edge comes from the default mode
*/
for ( iedge = 0 ; iedge < cur_pb_graph_pin - > num_input_edges ; iedge + + ) {
if ( mode_index ! = cur_pb_graph_pin - > input_edges [ iedge ] - > interconnect - > parent_mode_index ) {
continue ;
}
cur_pb_graph_pin - > temp_net_num = cur_pb_graph_pin - > input_edges [ iedge ] - > input_pins [ 0 ] - > temp_net_num ;
break ;
}
return ;
}
void mark_pb_graph_node_input_pins_temp_net_num ( t_pb_graph_node * cur_pb_graph_node ,
int mode_index ) {
int iport , ipin ;
assert ( NULL ! = cur_pb_graph_node ) ;
/* Input ports */
for ( iport = 0 ; iport < cur_pb_graph_node - > num_input_ports ; iport + + ) {
for ( ipin = 0 ; ipin < cur_pb_graph_node - > num_input_pins [ iport ] ; ipin + + ) {
cur_pb_graph_node - > input_pins [ iport ] [ ipin ] . temp_net_num = OPEN ;
/* IMPORTANT: I assume by default the index of selected edge is 0
* Make sure this input edge comes from the default mode
*/
assign_pb_graph_node_pin_temp_net_num_by_mode_index ( & ( cur_pb_graph_node - > input_pins [ iport ] [ ipin ] ) , mode_index ) ;
}
}
return ;
}
void mark_pb_graph_node_clock_pins_temp_net_num ( t_pb_graph_node * cur_pb_graph_node ,
int mode_index ) {
int iport , ipin ;
assert ( NULL ! = cur_pb_graph_node ) ;
/* Clock ports */
for ( iport = 0 ; iport < cur_pb_graph_node - > num_clock_ports ; iport + + ) {
for ( ipin = 0 ; ipin < cur_pb_graph_node - > num_clock_pins [ iport ] ; ipin + + ) {
cur_pb_graph_node - > clock_pins [ iport ] [ ipin ] . temp_net_num = OPEN ;
assign_pb_graph_node_pin_temp_net_num_by_mode_index ( & ( cur_pb_graph_node - > clock_pins [ iport ] [ ipin ] ) , mode_index ) ;
}
}
return ;
}
void mark_pb_graph_node_output_pins_temp_net_num ( t_pb_graph_node * cur_pb_graph_node ,
int mode_index ) {
int iport , ipin ;
assert ( NULL ! = cur_pb_graph_node ) ;
for ( iport = 0 ; iport < cur_pb_graph_node - > num_output_ports ; iport + + ) {
for ( ipin = 0 ; ipin < cur_pb_graph_node - > num_output_pins [ iport ] ; ipin + + ) {
cur_pb_graph_node - > output_pins [ iport ] [ ipin ] . temp_net_num = OPEN ;
/* IMPORTANT: I assume by default the index of selected edge is 0
* Make sure this input edge comes from the default mode
*/
assign_pb_graph_node_pin_temp_net_num_by_mode_index ( & ( cur_pb_graph_node - > output_pins [ iport ] [ ipin ] ) , mode_index ) ;
}
}
return ;
}
/* Mark temp_net_num in current pb_graph_node from the parent pb_graph_node */
void rec_mark_pb_graph_node_temp_net_num ( t_pb_graph_node * cur_pb_graph_node ) {
int mode_index , ipb , jpb ;
assert ( NULL ! = cur_pb_graph_node ) ;
/* Find the default mode */
mode_index = find_pb_type_idle_mode_index ( * ( cur_pb_graph_node - > pb_type ) ) ;
mark_pb_graph_node_input_pins_temp_net_num ( cur_pb_graph_node , mode_index ) ;
mark_pb_graph_node_clock_pins_temp_net_num ( cur_pb_graph_node , mode_index ) ;
if ( NULL ! = cur_pb_graph_node - > pb_type - > spice_model ) {
return ;
}
/* Go recursively ... */
mode_index = find_pb_type_idle_mode_index ( * ( cur_pb_graph_node - > pb_type ) ) ;
for ( ipb = 0 ; ipb < cur_pb_graph_node - > pb_type - > modes [ mode_index ] . num_pb_type_children ; ipb + + ) {
for ( jpb = 0 ; jpb < cur_pb_graph_node - > pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . num_pb ; jpb + + ) {
/* Mark pb_graph_node temp_net_num */
rec_mark_pb_graph_node_temp_net_num ( & ( cur_pb_graph_node - > child_pb_graph_nodes [ mode_index ] [ ipb ] [ jpb ] ) ) ;
}
}
/* IMPORTANT: update the temp_net of Output ports after recursion is done!
* the outputs of sub pb_graph_node should be updated first
*/
mark_pb_graph_node_output_pins_temp_net_num ( cur_pb_graph_node , mode_index ) ;
/* Do this again to handle feedback loops ! */
mark_pb_graph_node_input_pins_temp_net_num ( cur_pb_graph_node , mode_index ) ;
mark_pb_graph_node_clock_pins_temp_net_num ( cur_pb_graph_node , mode_index ) ;
return ;
}
void load_one_pb_graph_pin_temp_net_num_from_pb ( t_pb * cur_pb ,
t_pb_graph_pin * cur_pb_graph_pin ) {
int node_index ;
t_rr_node * pb_rr_nodes = NULL ;
assert ( NULL ! = cur_pb ) ;
assert ( NULL ! = cur_pb - > pb_graph_node ) ;
/* Get the selected edge of current pin*/
pb_rr_nodes = cur_pb - > rr_graph ;
node_index = cur_pb_graph_pin - > pin_count_in_cluster ;
cur_pb_graph_pin - > temp_net_num = pb_rr_nodes [ node_index ] . vpack_net_num ;
return ;
}
/* According to the vpack_net_num in cur_pb
* assign it to the corresponding pb_graph_pins
*/
void load_pb_graph_node_temp_net_num_from_pb ( t_pb * cur_pb ) {
int iport , ipin ;
assert ( NULL ! = cur_pb ) ;
assert ( NULL ! = cur_pb - > pb_graph_node ) ;
/* Input ports */
for ( iport = 0 ; iport < cur_pb - > pb_graph_node - > num_input_ports ; iport + + ) {
for ( ipin = 0 ; ipin < cur_pb - > pb_graph_node - > num_input_pins [ iport ] ; ipin + + ) {
load_one_pb_graph_pin_temp_net_num_from_pb ( cur_pb ,
& ( cur_pb - > pb_graph_node - > input_pins [ iport ] [ ipin ] ) ) ;
}
}
/* Clock ports */
for ( iport = 0 ; iport < cur_pb - > pb_graph_node - > num_clock_ports ; iport + + ) {
for ( ipin = 0 ; ipin < cur_pb - > pb_graph_node - > num_clock_pins [ iport ] ; ipin + + ) {
load_one_pb_graph_pin_temp_net_num_from_pb ( cur_pb ,
& ( cur_pb - > pb_graph_node - > clock_pins [ iport ] [ ipin ] ) ) ;
}
}
/* Output ports */
for ( iport = 0 ; iport < cur_pb - > pb_graph_node - > num_output_ports ; iport + + ) {
for ( ipin = 0 ; ipin < cur_pb - > pb_graph_node - > num_output_pins [ iport ] ; ipin + + ) {
load_one_pb_graph_pin_temp_net_num_from_pb ( cur_pb ,
& ( cur_pb - > pb_graph_node - > output_pins [ iport ] [ ipin ] ) ) ;
}
}
return ;
}
/* Recursively traverse the hierachy of a pb,
* store parasitic nets in the temp_net_num of the assoicated pb_graph_node
*/
void rec_mark_one_pb_unused_pb_graph_node_temp_net_num ( t_pb * cur_pb ) {
int ipb , jpb ;
int mode_index ;
/* Check */
assert ( NULL ! = cur_pb ) ;
if ( NULL ! = cur_pb - > pb_graph_node - > pb_type - > spice_model ) {
return ;
}
/* Go recursively ... */
mode_index = cur_pb - > mode ;
if ( ! ( 0 < cur_pb - > pb_graph_node - > pb_type - > num_modes ) ) {
return ;
}
for ( ipb = 0 ; ipb < cur_pb - > pb_graph_node - > pb_type - > modes [ mode_index ] . num_pb_type_children ; ipb + + ) {
for ( jpb = 0 ; jpb < cur_pb - > pb_graph_node - > pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . num_pb ; jpb + + ) {
/* Refer to pack/output_clustering.c [LINE 392] */
if ( ( NULL ! = cur_pb - > child_pbs [ ipb ] ) & & ( NULL ! = cur_pb - > child_pbs [ ipb ] [ jpb ] . name ) ) {
rec_mark_one_pb_unused_pb_graph_node_temp_net_num ( & ( cur_pb - > child_pbs [ ipb ] [ jpb ] ) ) ;
} else {
/* Print idle graph_node muxes */
load_pb_graph_node_temp_net_num_from_pb ( cur_pb ) ;
/* We should update the net_num */
rec_mark_pb_graph_node_temp_net_num ( cur_pb - > child_pbs [ ipb ] [ jpb ] . pb_graph_node ) ;
}
}
}
return ;
}
void update_pb_vpack_net_num_from_temp_net_num ( t_pb * cur_pb ,
t_pb_graph_pin * cur_pb_graph_pin ) {
int node_index ;
t_rr_node * pb_rr_nodes = NULL ;
assert ( NULL ! = cur_pb ) ;
assert ( NULL ! = cur_pb - > pb_graph_node ) ;
/* Get the selected edge of current pin*/
pb_rr_nodes = cur_pb - > rr_graph ;
node_index = cur_pb_graph_pin - > pin_count_in_cluster ;
/* Avoid mistakenly modification */
if ( OPEN ! = pb_rr_nodes [ node_index ] . vpack_net_num ) {
return ;
}
/* Only modify when original vpack_net_num is open!!! */
pb_rr_nodes [ node_index ] . vpack_net_num = cur_pb_graph_pin - > temp_net_num ;
return ;
}
void update_pb_graph_node_temp_net_num_to_pb ( t_pb_graph_node * cur_pb_graph_node ,
t_pb * cur_pb ) {
int iport , ipin ;
t_rr_node * pb_rr_nodes = NULL ;
assert ( NULL ! = cur_pb - > pb_graph_node ) ;
assert ( NULL ! = cur_pb ) ;
pb_rr_nodes = cur_pb - > rr_graph ;
/* Input ports */
for ( iport = 0 ; iport < cur_pb_graph_node - > num_input_ports ; iport + + ) {
for ( ipin = 0 ; ipin < cur_pb_graph_node - > num_input_pins [ iport ] ; ipin + + ) {
update_pb_vpack_net_num_from_temp_net_num ( cur_pb ,
& ( cur_pb_graph_node - > input_pins [ iport ] [ ipin ] ) ) ;
}
}
/* Clock ports */
for ( iport = 0 ; iport < cur_pb_graph_node - > num_clock_ports ; iport + + ) {
for ( ipin = 0 ; ipin < cur_pb_graph_node - > num_clock_pins [ iport ] ; ipin + + ) {
update_pb_vpack_net_num_from_temp_net_num ( cur_pb ,
& ( cur_pb_graph_node - > clock_pins [ iport ] [ ipin ] ) ) ;
}
}
/* Output ports */
for ( iport = 0 ; iport < cur_pb_graph_node - > num_output_ports ; iport + + ) {
for ( ipin = 0 ; ipin < cur_pb_graph_node - > num_output_pins [ iport ] ; ipin + + ) {
update_pb_vpack_net_num_from_temp_net_num ( cur_pb ,
& ( cur_pb_graph_node - > output_pins [ iport ] [ ipin ] ) ) ;
}
}
return ;
}
void rec_load_unused_pb_graph_node_temp_net_num_to_pb ( t_pb * cur_pb ) {
int ipb , jpb ;
int mode_index ;
/* Check */
assert ( NULL ! = cur_pb ) ;
if ( NULL ! = cur_pb - > pb_graph_node - > pb_type - > spice_model ) {
return ;
}
/* Go recursively ... */
mode_index = cur_pb - > mode ;
if ( ! ( 0 < cur_pb - > pb_graph_node - > pb_type - > num_modes ) ) {
return ;
}
for ( ipb = 0 ; ipb < cur_pb - > pb_graph_node - > pb_type - > modes [ mode_index ] . num_pb_type_children ; ipb + + ) {
for ( jpb = 0 ; jpb < cur_pb - > pb_graph_node - > pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . num_pb ; jpb + + ) {
/* Refer to pack/output_clustering.c [LINE 392] */
if ( ( NULL ! = cur_pb - > child_pbs [ ipb ] ) & & ( NULL ! = cur_pb - > child_pbs [ ipb ] [ jpb ] . name ) ) {
rec_load_unused_pb_graph_node_temp_net_num_to_pb ( & ( cur_pb - > child_pbs [ ipb ] [ jpb ] ) ) ;
} else {
update_pb_graph_node_temp_net_num_to_pb ( cur_pb - > child_pbs [ ipb ] [ jpb ] . pb_graph_node ,
cur_pb ) ;
}
}
}
return ;
}
void mark_one_pb_parasitic_nets ( t_pb * cur_pb ) {
/* By go recursively, parasitic net num are stored in the temp_net_num in pb_graph_node */
rec_mark_one_pb_unused_pb_graph_node_temp_net_num ( cur_pb ) ;
/* Load the temp_net_num to vpack_net_num in the current pb! */
rec_load_unused_pb_graph_node_temp_net_num_to_pb ( cur_pb ) ;
return ;
}
void init_rr_nodes_vpack_net_num_changed ( int LL_num_rr_nodes ,
t_rr_node * LL_rr_node ) {
int inode ;
for ( inode = 0 ; inode < LL_num_rr_nodes ; inode + + ) {
LL_rr_node [ inode ] . vpack_net_num_changed = FALSE ;
}
return ;
}
/* Check if this net is connected to a PI*/
boolean is_net_pi ( t_net * cur_net ) {
int src_blk_idx ;
assert ( NULL ! = cur_net ) ;
src_blk_idx = cur_net - > node_block [ 0 ] ;
if ( VPACK_INPAD = = logical_block [ src_blk_idx ] . type ) {
return TRUE ;
}
return FALSE ;
}
int check_consistency_logical_block_net_num ( t_logical_block * lgk_blk ,
int num_inputs , int * input_net_num ) {
int i , iport , ipin , net_eq ;
int consistency = 1 ;
int * input_net_num_mapped = ( int * ) my_calloc ( num_inputs , sizeof ( int ) ) ;
for ( iport = 0 ; iport < lgk_blk - > pb - > pb_graph_node - > num_input_ports ; iport + + ) {
for ( ipin = 0 ; ipin < lgk_blk - > pb - > pb_graph_node - > num_input_pins [ iport ] ; ipin + + ) {
if ( OPEN = = lgk_blk - > input_nets [ iport ] [ ipin ] ) {
continue ; /* bypass unused pins */
}
/* Initial net_eq */
net_eq = 0 ;
/* Check if this net can be found in the input net_num */
for ( i = 0 ; i < num_inputs ; i + + ) {
if ( 1 = = input_net_num_mapped [ i ] ) {
continue ;
}
if ( input_net_num [ i ] = = lgk_blk - > input_nets [ iport ] [ ipin ] ) {
net_eq = 1 ;
input_net_num_mapped [ i ] = 1 ;
break ;
}
}
if ( 0 = = net_eq ) {
consistency = 0 ;
break ;
}
}
if ( 0 = = consistency ) {
break ;
}
}
/* Free */
my_free ( input_net_num_mapped ) ;
return consistency ;
}
/* Determine if this rr_node is driving this switch box (x,y)
* For more than length - 1 wire , the fan - in of a des_rr_node in a switch box
* contain all the drivers in the switch boxes that it passes through .
* This function is to identify if the src_rr_node is the driver in this switch box
*/
int rr_node_drive_switch_box ( t_rr_node * src_rr_node ,
t_rr_node * des_rr_node ,
int switch_box_x ,
int switch_box_y ,
int chan_side ) {
/* Make sure a valid src_rr_node and des_rr_node */
assert ( NULL ! = src_rr_node ) ;
assert ( NULL ! = des_rr_node ) ;
/* The src_rr_node should be either CHANX or CHANY */
assert ( ( CHANX = = des_rr_node - > type ) | | ( CHANY = = des_rr_node - > type ) ) ;
/* Valid switch_box coordinator */
assert ( ( ! ( 0 > switch_box_x ) ) & & ( ! ( switch_box_x > ( nx + 1 ) ) ) ) ;
assert ( ( ! ( 0 > switch_box_y ) ) & & ( ! ( switch_box_y > ( ny + 1 ) ) ) ) ;
/* Valid des_rr_node coordinator */
2018-08-01 15:04:28 -05:00
assert ( ( ! ( switch_box_x < ( des_rr_node - > xlow - 1 ) ) ) & & ( ! ( switch_box_x > ( des_rr_node - > xhigh + 1 ) ) ) ) ;
assert ( ( ! ( switch_box_y < ( des_rr_node - > ylow - 1 ) ) ) & & ( ! ( switch_box_y > ( des_rr_node - > yhigh + 1 ) ) ) ) ;
2018-07-26 12:28:21 -05:00
/* Check the src_rr_node coordinator */
switch ( chan_side ) {
case TOP :
/* Following cases:
* |
* / | \
*/
/* The destination rr_node only have one condition!!! */
assert ( ( INC_DIRECTION = = des_rr_node - > direction ) & & ( CHANY = = des_rr_node - > type ) ) ;
/* depend on the type of src_rr_node */
switch ( src_rr_node - > type ) {
case OPIN :
if ( ( ( switch_box_y + 1 ) = = src_rr_node - > ylow )
& & ( ( switch_box_x = = src_rr_node - > xlow ) | | ( ( switch_box_x + 1 ) = = src_rr_node - > xlow ) ) ) {
return 1 ;
}
break ;
case CHANX :
assert ( src_rr_node - > ylow = = src_rr_node - > yhigh ) ;
if ( ( switch_box_y = = src_rr_node - > ylow )
2018-08-01 15:04:28 -05:00
& & ( ! ( switch_box_x < ( src_rr_node - > xlow - 1 ) ) )
& & ( ! ( switch_box_x > ( src_rr_node - > xhigh + 1 ) ) ) ) {
2018-07-26 12:28:21 -05:00
return 1 ;
}
break ;
case CHANY :
assert ( src_rr_node - > xlow = = src_rr_node - > xhigh ) ;
if ( ( switch_box_x = = src_rr_node - > xlow )
2018-08-01 15:04:28 -05:00
& & ( ! ( switch_box_y < src_rr_node - > ylow ) )
& & ( ! ( switch_box_y > src_rr_node - > yhigh ) ) ) {
2018-07-26 12:28:21 -05:00
return 1 ;
}
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s, [LINE%d])Invalid src_rr_node type! \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
break ;
case RIGHT :
/* Following cases:
* \
* - - - - - - -
* /
*/
/* The destination rr_node only have one condition!!! */
assert ( ( INC_DIRECTION = = des_rr_node - > direction ) & & ( CHANX = = des_rr_node - > type ) ) ;
/* depend on the type of src_rr_node */
switch ( src_rr_node - > type ) {
case OPIN :
if ( ( ( switch_box_x + 1 ) = = src_rr_node - > xlow )
& & ( ( switch_box_y = = src_rr_node - > ylow ) | | ( ( switch_box_y + 1 ) = = src_rr_node - > ylow ) ) ) {
return 1 ;
}
break ;
case CHANX :
assert ( src_rr_node - > ylow = = src_rr_node - > yhigh ) ;
if ( ( switch_box_y = = src_rr_node - > ylow )
& & ( ! ( switch_box_x < src_rr_node - > xlow ) ) & & ( ! ( switch_box_x > src_rr_node - > xhigh ) ) ) {
return 1 ;
}
break ;
case CHANY :
assert ( src_rr_node - > xlow = = src_rr_node - > xhigh ) ;
if ( ( switch_box_x = = src_rr_node - > xlow )
2018-08-01 15:04:28 -05:00
& & ( ! ( switch_box_y < ( src_rr_node - > ylow - 1 ) ) )
& & ( ! ( switch_box_y > ( src_rr_node - > yhigh + 1 ) ) ) ) {
2018-07-26 12:28:21 -05:00
return 1 ;
}
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s, [LINE%d])Invalid src_rr_node type! \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
break ;
case BOTTOM :
/* Following cases:
* |
2018-08-01 15:04:28 -05:00
* \ | /
2018-07-26 12:28:21 -05:00
* |
*/
/* The destination rr_node only have one condition!!! */
assert ( ( DEC_DIRECTION = = des_rr_node - > direction ) & & ( CHANY = = des_rr_node - > type ) ) ;
/* depend on the type of src_rr_node */
switch ( src_rr_node - > type ) {
case OPIN :
if ( ( switch_box_y = = src_rr_node - > ylow )
& & ( ( switch_box_x = = src_rr_node - > xlow ) | | ( ( switch_box_x + 1 ) = = src_rr_node - > xlow ) ) ) {
return 1 ;
}
break ;
case CHANX :
assert ( src_rr_node - > ylow = = src_rr_node - > yhigh ) ;
if ( ( switch_box_y = = src_rr_node - > ylow )
2018-08-01 15:04:28 -05:00
& & ( ! ( switch_box_x < ( src_rr_node - > xlow - 1 ) ) )
& & ( ! ( switch_box_x > ( src_rr_node - > xhigh + 1 ) ) ) ) {
2018-07-26 12:28:21 -05:00
return 1 ;
}
break ;
case CHANY :
assert ( src_rr_node - > xlow = = src_rr_node - > xhigh ) ;
if ( ( switch_box_x = = src_rr_node - > xlow )
2018-08-01 15:04:28 -05:00
& & ( ! ( ( switch_box_y + 1 ) < src_rr_node - > ylow ) )
& & ( ! ( ( switch_box_y + 1 ) > src_rr_node - > yhigh ) ) ) {
2018-07-26 12:28:21 -05:00
return 1 ;
}
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s, [LINE%d])Invalid src_rr_node type! \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
break ;
case LEFT :
/* Following cases:
* /
* - - - - - - -
* \
*/
/* The destination rr_node only have one condition!!! */
assert ( ( DEC_DIRECTION = = des_rr_node - > direction ) & & ( CHANX = = des_rr_node - > type ) ) ;
/* depend on the type of src_rr_node */
switch ( src_rr_node - > type ) {
case OPIN :
if ( ( switch_box_x = = src_rr_node - > xlow )
& & ( ( switch_box_y = = src_rr_node - > ylow ) | | ( ( switch_box_y + 1 ) = = src_rr_node - > ylow ) ) ) {
return 1 ;
}
break ;
case CHANX :
assert ( src_rr_node - > ylow = = src_rr_node - > yhigh ) ;
if ( ( switch_box_y = = src_rr_node - > ylow )
2018-08-01 15:04:28 -05:00
& & ( ! ( ( switch_box_x + 1 ) < src_rr_node - > xlow ) )
& & ( ! ( ( switch_box_x + 1 ) > src_rr_node - > xhigh ) ) ) {
2018-07-26 12:28:21 -05:00
return 1 ;
}
break ;
case CHANY :
assert ( src_rr_node - > xlow = = src_rr_node - > xhigh ) ;
if ( ( switch_box_x = = src_rr_node - > xlow )
2018-08-01 15:04:28 -05:00
& & ( ! ( switch_box_y < ( src_rr_node - > ylow - 1 ) ) )
& & ( ! ( switch_box_y > ( src_rr_node - > yhigh + 1 ) ) ) ) {
2018-07-26 12:28:21 -05:00
return 1 ;
}
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s, [LINE%d])Invalid src_rr_node type! \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s, [LINE%d])Invalid side! \n " , __FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
return 0 ;
}
void find_drive_rr_nodes_switch_box ( int switch_box_x ,
int switch_box_y ,
t_rr_node * src_rr_node ,
int chan_side ,
int return_num_only ,
int * num_drive_rr_nodes ,
t_rr_node * * * drive_rr_nodes ,
int * switch_index ) {
int cur_index = 0 ;
//int inode, iedge, next_node;
int inode ;
/* I decide to kill the codes that search all the edges, the running time is huge... */
/* Determine the num_drive_rr_nodes */
( * num_drive_rr_nodes ) = 0 ;
( * switch_index ) = - 1 ;
for ( inode = 0 ; inode < src_rr_node - > num_drive_rr_nodes ; inode + + ) {
if ( 1 = = rr_node_drive_switch_box ( src_rr_node - > drive_rr_nodes [ inode ] , src_rr_node ,
switch_box_x , switch_box_y , chan_side ) ) {
/* Get the spice_model */
if ( - 1 = = ( * switch_index ) ) {
( * switch_index ) = src_rr_node - > drive_switches [ inode ] ;
} else { /* Make sure the switches are the same*/
assert ( ( * switch_index ) = = src_rr_node - > drive_switches [ inode ] ) ;
}
( * num_drive_rr_nodes ) + + ;
}
}
//for (inode = 0; inode < num_rr_nodes; inode++) {
// for (iedge = 0; iedge < rr_node[inode].num_edges; iedge++) {
// next_node = rr_node[inode].edges[iedge];
// /* Make sure the coordinator is matched to this switch box*/
// if ((src_rr_node == &(rr_node[next_node]))
// &&(1 == rr_node_drive_switch_box(&(rr_node[inode]), src_rr_node, switch_box_x, switch_box_y, chan_side))) {
// /* Get the spice_model */
// if (-1 == (*switch_index)) {
// (*switch_index) = rr_node[inode].switches[iedge];
// } else { /* Make sure the switches are the same*/
// assert((*switch_index) == rr_node[inode].switches[iedge]);
// }
// (*num_drive_rr_nodes)++;
// }
// }
//}
/* Check and malloc*/
assert ( ( ! ( 0 > ( * num_drive_rr_nodes ) ) ) & & ( ! ( ( * num_drive_rr_nodes ) > src_rr_node - > fan_in ) ) ) ;
if ( 1 = = return_num_only ) {
return ;
}
( * drive_rr_nodes ) = NULL ;
if ( 0 = = ( * num_drive_rr_nodes ) ) {
return ;
}
( * drive_rr_nodes ) = ( t_rr_node * * ) my_malloc ( sizeof ( t_rr_node * ) * ( * num_drive_rr_nodes ) ) ;
/* Find all the rr_nodes that drive current_rr_node*/
cur_index = 0 ;
( * switch_index ) = - 1 ;
for ( inode = 0 ; inode < src_rr_node - > num_drive_rr_nodes ; inode + + ) {
if ( 1 = = rr_node_drive_switch_box ( src_rr_node - > drive_rr_nodes [ inode ] , src_rr_node ,
switch_box_x , switch_box_y , chan_side ) ) {
/* Update drive_rr_nodes list */
( * drive_rr_nodes ) [ cur_index ] = src_rr_node - > drive_rr_nodes [ inode ] ;
/* Get the spice_model */
if ( - 1 = = ( * switch_index ) ) {
( * switch_index ) = src_rr_node - > drive_switches [ inode ] ;
} else { /* Make sure the switches are the same*/
assert ( ( * switch_index ) = = src_rr_node - > drive_switches [ inode ] ) ;
}
cur_index + + ;
}
}
//for (inode = 0; inode < num_rr_nodes; inode++) {
// for (iedge = 0; iedge < rr_node[inode].num_edges; iedge++) {
// next_node = rr_node[inode].edges[iedge];
// /* Make sure the coordinator is matched to this switch box*/
// if ((src_rr_node == &(rr_node[next_node]))
// &&(1 == rr_node_drive_switch_box(&(rr_node[inode]), src_rr_node, switch_box_x, switch_box_y, chan_side))) {
// /* Update drive_rr_nodes list */
// (*drive_rr_nodes)[cur_index] = &(rr_node[inode]);
// /* Get the spice_model */
// if (-1 == (*switch_index)) {
// (*switch_index) = rr_node[inode].switches[iedge];
// } else { /* Make sure the switches are the same*/
// assert((*switch_index) == rr_node[inode].switches[iedge]);
// }
// cur_index++;
// }
// }
//}
/* Verification */
assert ( cur_index = = ( * num_drive_rr_nodes ) ) ;
return ;
}
/* Count the number of configuration bits of a spice model */
int count_num_sram_bits_one_spice_model ( t_spice_model * cur_spice_model ,
int mux_size ) {
int num_sram_bits = 0 ;
int iport ;
int lut_size ;
int num_input_port = 0 ;
t_spice_model_port * * input_ports = NULL ;
int num_output_port = 0 ;
t_spice_model_port * * output_ports = NULL ;
int num_sram_port = 0 ;
t_spice_model_port * * sram_ports = NULL ;
assert ( NULL ! = cur_spice_model ) ;
/* Only LUT and MUX requires configuration bits*/
switch ( cur_spice_model - > type ) {
case SPICE_MODEL_LUT :
/* Determine size of LUT*/
input_ports = find_spice_model_ports ( cur_spice_model , SPICE_MODEL_PORT_INPUT , & num_input_port , TRUE ) ;
output_ports = find_spice_model_ports ( cur_spice_model , SPICE_MODEL_PORT_OUTPUT , & num_output_port , TRUE ) ;
sram_ports = find_spice_model_ports ( cur_spice_model , SPICE_MODEL_PORT_SRAM , & num_sram_port , TRUE ) ;
assert ( 1 = = num_input_port ) ;
assert ( 1 = = num_output_port ) ;
assert ( 1 = = num_sram_port ) ;
lut_size = input_ports [ 0 ] - > size ;
num_sram_bits = ( int ) pow ( 2. , ( double ) ( lut_size ) ) ;
assert ( num_sram_bits = = sram_ports [ 0 ] - > size ) ;
assert ( 1 = = output_ports [ 0 ] - > size ) ;
/* TODO: could be more smart! Use mapped spice_model of SRAM ports!
* Support Non - volatile RRAM - based SRAM */
switch ( cur_spice_model - > design_tech ) {
case SPICE_MODEL_DESIGN_RRAM :
/* Non-volatile SRAM requires 2 BLs and 2 WLs for each 1 memory bit,
* Number of memory bits is still same as CMOS SRAM
*/
break ;
case SPICE_MODEL_DESIGN_CMOS :
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (FILE:%s,LINE[%d])Invalid design_technology of LUT(name: %s) \n " ,
__FILE__ , __LINE__ , cur_spice_model - > name ) ;
exit ( 1 ) ;
}
break ;
case SPICE_MODEL_MUX :
assert ( ( 2 = = mux_size ) | | ( 2 < mux_size ) ) ;
/* Number of configuration bits depends on the MUX structure */
switch ( cur_spice_model - > design_tech_info . structure ) {
case SPICE_MODEL_STRUCTURE_TREE :
num_sram_bits = determine_tree_mux_level ( mux_size ) ;
break ;
case SPICE_MODEL_STRUCTURE_ONELEVEL :
num_sram_bits = mux_size ;
break ;
case SPICE_MODEL_STRUCTURE_MULTILEVEL :
num_sram_bits = cur_spice_model - > design_tech_info . mux_num_level
* determine_num_input_basis_multilevel_mux ( mux_size ,
cur_spice_model - > design_tech_info . mux_num_level ) ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid structure for spice model (%s)! \n " ,
__FILE__ , __LINE__ , cur_spice_model - > name ) ;
exit ( 1 ) ;
}
/* For 2:1 MUX, whatever structure, there is only one level */
if ( 2 = = mux_size ) {
num_sram_bits = 1 ;
}
/* Also the number of configuration bits depends on the technology*/
switch ( cur_spice_model - > design_tech ) {
case SPICE_MODEL_DESIGN_RRAM :
/* 4T1R MUX requires more configuration bits */
if ( SPICE_MODEL_STRUCTURE_TREE = = cur_spice_model - > design_tech_info . structure ) {
/* For tree-structure: we need 3 times more config. bits */
num_sram_bits = 3 * num_sram_bits ;
} else if ( SPICE_MODEL_STRUCTURE_MULTILEVEL = = cur_spice_model - > design_tech_info . structure ) {
/* For multi-level structure: we need 1 more config. bits for each level */
num_sram_bits + = cur_spice_model - > design_tech_info . mux_num_level ;
} else {
num_sram_bits = ( num_sram_bits + 1 ) ;
}
/* For 2:1 MUX, whatever structure, there is only one level */
if ( 2 = = mux_size ) {
num_sram_bits = 3 ;
}
break ;
case SPICE_MODEL_DESIGN_CMOS :
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (FILE:%s,LINE[%d])Invalid design_technology of MUX(name: %s) \n " ,
__FILE__ , __LINE__ , cur_spice_model - > name ) ;
exit ( 1 ) ;
}
break ;
case SPICE_MODEL_WIRE :
case SPICE_MODEL_FF :
case SPICE_MODEL_SRAM :
case SPICE_MODEL_HARDLOGIC :
case SPICE_MODEL_SCFF :
case SPICE_MODEL_VDD :
case SPICE_MODEL_GND :
case SPICE_MODEL_IOPAD :
/* Other block, we just count the number SRAM ports defined by user */
num_sram_bits = 0 ;
sram_ports = find_spice_model_ports ( cur_spice_model , SPICE_MODEL_PORT_SRAM , & num_sram_port , TRUE ) ;
/* TODO: could be more smart!
* Support Non - volatile RRAM - based SRAM */
if ( 0 < num_sram_port ) {
assert ( NULL ! = sram_ports ) ;
for ( iport = 0 ; iport < num_sram_port ; iport + + ) {
assert ( NULL ! = sram_ports [ iport ] - > spice_model ) ;
num_sram_bits + = sram_ports [ iport ] - > size ;
/* TODO: could be more smart!
* Support Non - volatile RRAM - based SRAM */
switch ( cur_spice_model - > design_tech ) {
case SPICE_MODEL_DESIGN_RRAM :
/* Non-volatile SRAM requires 2 BLs and 2 WLs for each 1 memory bit,
* Number of memory bits is still same as CMOS SRAM
*/
case SPICE_MODEL_DESIGN_CMOS :
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (FILE:%s,LINE[%d])Invalid design_technology of LUT(name: %s) \n " ,
__FILE__ , __LINE__ , cur_spice_model - > name ) ;
exit ( 1 ) ;
}
}
}
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s, [LINE%d])Invalid spice_model_type! \n " , __FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
return num_sram_bits ;
}
/* For a multiplexer, determine its reserved configuration bits */
int count_num_reserved_conf_bits_one_lut_spice_model ( t_spice_model * cur_spice_model ,
enum e_sram_orgz cur_sram_orgz_type ) {
int num_reserved_conf_bits = 0 ;
int num_sram_port = 0 ;
t_spice_model_port * * sram_ports = NULL ;
/* Check */
assert ( SPICE_MODEL_LUT = = cur_spice_model - > type ) ;
/* Determine size of LUT*/
sram_ports = find_spice_model_ports ( cur_spice_model , SPICE_MODEL_PORT_SRAM , & num_sram_port , TRUE ) ;
assert ( 1 = = num_sram_port ) ;
/* TODO: could be more smart! Use mapped spice_model of SRAM ports!
* Support Non - volatile RRAM - based SRAM */
switch ( sram_ports [ 0 ] - > spice_model - > design_tech ) {
case SPICE_MODEL_DESIGN_RRAM :
/* Non-volatile SRAM requires 2 BLs and 2 WLs for each 1 memory bit,
* In memory bank , by intensively share the Bit / Word Lines ,
* we only need 1 additional BL and WL for each memory bit .
* Number of memory bits is still same as CMOS SRAM
*/
num_reserved_conf_bits =
count_num_reserved_conf_bits_one_rram_sram_spice_model ( sram_ports [ 0 ] - > spice_model ,
cur_sram_orgz_type ) ;
break ;
case SPICE_MODEL_DESIGN_CMOS :
num_reserved_conf_bits = 0 ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (FILE:%s,LINE[%d])Invalid design_technology of LUT(name: %s) \n " ,
__FILE__ , __LINE__ , cur_spice_model - > name ) ;
exit ( 1 ) ;
}
/* Free */
my_free ( sram_ports ) ;
return num_reserved_conf_bits ;
}
/* For a multiplexer, determine its reserved configuration bits */
int count_num_reserved_conf_bits_one_mux_spice_model ( t_spice_model * cur_spice_model ,
enum e_sram_orgz cur_sram_orgz_type ,
int mux_size ) {
int num_reserved_conf_bits = 0 ;
/* Check */
assert ( SPICE_MODEL_MUX = = cur_spice_model - > type ) ;
assert ( ( 2 = = mux_size ) | | ( 2 < mux_size ) ) ;
/* Number of configuration bits depends on the MUX structure */
switch ( cur_spice_model - > design_tech_info . structure ) {
case SPICE_MODEL_STRUCTURE_TREE :
num_reserved_conf_bits = 2 ;
break ;
case SPICE_MODEL_STRUCTURE_ONELEVEL :
num_reserved_conf_bits = mux_size ;
break ;
case SPICE_MODEL_STRUCTURE_MULTILEVEL :
num_reserved_conf_bits = cur_spice_model - > design_tech_info . mux_num_level *
determine_num_input_basis_multilevel_mux ( mux_size ,
cur_spice_model - > design_tech_info . mux_num_level ) ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid structure for spice model (%s)! \n " ,
__FILE__ , __LINE__ , cur_spice_model - > name ) ;
exit ( 1 ) ;
}
/* For 2:1 MUX, whatever structure, there is only one level */
if ( 2 = = mux_size ) {
num_reserved_conf_bits = 2 ;
}
/* Also the number of configuration bits depends on the technology*/
switch ( cur_spice_model - > design_tech ) {
case SPICE_MODEL_DESIGN_RRAM :
switch ( cur_sram_orgz_type ) {
case SPICE_SRAM_MEMORY_BANK :
/* In memory bank, by intensively share the Bit/Word Lines,
* we only need 1 additional BL and WL for each MUX level .
*/
/* For 2:1 MUX, whatever structure, there is only one level */
if ( 2 = = mux_size ) {
num_reserved_conf_bits = 2 ;
}
break ;
case SPICE_SRAM_SCAN_CHAIN :
case SPICE_SRAM_STANDALONE :
/* 4T1R MUX requires more configuration bits */
if ( SPICE_MODEL_STRUCTURE_TREE = = cur_spice_model - > design_tech_info . structure ) {
/* For tree-structure: we need 3 times more config. bits */
num_reserved_conf_bits = 0 ;
} else if ( SPICE_MODEL_STRUCTURE_MULTILEVEL = = cur_spice_model - > design_tech_info . structure ) {
/* For multi-level structure: we need 1 more config. bits for each level */
num_reserved_conf_bits = 0 ;
} else {
num_reserved_conf_bits = 0 ;
}
/* For 2:1 MUX, whatever structure, there is only one level */
if ( 2 = = mux_size ) {
num_reserved_conf_bits = 0 ;
}
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (FILE:%s,LINE[%d])Invalid type of SRAM organization! \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
break ;
case SPICE_MODEL_DESIGN_CMOS :
num_reserved_conf_bits = 0 ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (FILE:%s,LINE[%d])Invalid design_technology of MUX(name: %s) \n " ,
__FILE__ , __LINE__ , cur_spice_model - > name ) ;
exit ( 1 ) ;
}
return num_reserved_conf_bits ;
}
/* For a non-volatile SRAM, we determine its number of reserved conf. bits */
int count_num_reserved_conf_bits_one_rram_sram_spice_model ( t_spice_model * cur_spice_model ,
enum e_sram_orgz cur_sram_orgz_type ) {
int num_reserved_conf_bits = 0 ;
int num_bl_ports , num_wl_ports ;
t_spice_model_port * * bl_ports = NULL ;
t_spice_model_port * * wl_ports = NULL ;
/* Check */
assert ( SPICE_MODEL_SRAM = = cur_spice_model - > type ) ;
switch ( cur_sram_orgz_type ) {
case SPICE_SRAM_MEMORY_BANK :
find_bl_wl_ports_spice_model ( cur_spice_model ,
& num_bl_ports , & bl_ports ,
& num_wl_ports , & wl_ports ) ;
assert ( ( 1 = = num_bl_ports ) & & ( 1 = = num_wl_ports ) ) ;
assert ( bl_ports [ 0 ] - > size = = wl_ports [ 0 ] - > size ) ;
num_reserved_conf_bits = bl_ports [ 0 ] - > size - 1 ; /*TODO: to be more smart: num_bl-1 of SRAM model ?*/
break ;
case SPICE_SRAM_SCAN_CHAIN :
case SPICE_SRAM_STANDALONE :
num_reserved_conf_bits = 0 ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (FILE:%s,LINE[%d])Invalid type of SRAM organization! \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
/* Free */
my_free ( bl_ports ) ;
my_free ( wl_ports ) ;
return num_reserved_conf_bits ;
}
int count_num_reserved_conf_bits_one_spice_model ( t_spice_model * cur_spice_model ,
enum e_sram_orgz cur_sram_orgz_type ,
int mux_size ) {
int num_reserved_conf_bits = 0 ;
int temp_num_reserved_conf_bits = 0 ;
int iport ;
int num_sram_port = 0 ;
t_spice_model_port * * sram_ports = NULL ;
assert ( NULL ! = cur_spice_model ) ;
/* Only LUT and MUX requires configuration bits*/
switch ( cur_spice_model - > type ) {
case SPICE_MODEL_LUT :
num_reserved_conf_bits =
count_num_reserved_conf_bits_one_lut_spice_model ( cur_spice_model ,
cur_sram_orgz_type ) ;
break ;
case SPICE_MODEL_MUX :
num_reserved_conf_bits =
count_num_reserved_conf_bits_one_mux_spice_model ( cur_spice_model ,
cur_sram_orgz_type ,
mux_size ) ;
break ;
case SPICE_MODEL_WIRE :
case SPICE_MODEL_FF :
case SPICE_MODEL_SRAM :
case SPICE_MODEL_HARDLOGIC :
case SPICE_MODEL_SCFF :
case SPICE_MODEL_VDD :
case SPICE_MODEL_GND :
case SPICE_MODEL_IOPAD :
/* Other block, we just count the number SRAM ports defined by user */
num_reserved_conf_bits = 0 ;
sram_ports = find_spice_model_ports ( cur_spice_model , SPICE_MODEL_PORT_SRAM , & num_sram_port , TRUE ) ;
/* TODO: could be more smart!
* Support Non - volatile RRAM - based SRAM */
if ( 0 < num_sram_port ) {
assert ( NULL ! = sram_ports ) ;
for ( iport = 0 ; iport < num_sram_port ; iport + + ) {
assert ( NULL ! = sram_ports [ iport ] - > spice_model ) ;
/* TODO: could be more smart!
* Support Non - volatile RRAM - based SRAM */
switch ( sram_ports [ iport ] - > spice_model - > design_tech ) {
case SPICE_MODEL_DESIGN_RRAM :
/* Non-volatile SRAM requires 2 BLs and 2 WLs for each 1 memory bit,
* Number of memory bits is still same as CMOS SRAM
*/
temp_num_reserved_conf_bits =
count_num_reserved_conf_bits_one_rram_sram_spice_model ( sram_ports [ iport ] - > spice_model ,
cur_sram_orgz_type ) ;
if ( temp_num_reserved_conf_bits > num_reserved_conf_bits ) {
num_reserved_conf_bits = temp_num_reserved_conf_bits ;
}
break ;
case SPICE_MODEL_DESIGN_CMOS :
num_reserved_conf_bits = 0 ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (FILE:%s,LINE[%d])Invalid design_technology of LUT(name: %s) \n " ,
__FILE__ , __LINE__ , cur_spice_model - > name ) ;
exit ( 1 ) ;
}
}
}
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s, [LINE%d])Invalid spice_model_type! \n " , __FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
/* Free */
my_free ( sram_ports ) ;
return num_reserved_conf_bits ;
}
/* Count the number of configuration bits of a spice model */
int count_num_conf_bits_one_spice_model ( t_spice_model * cur_spice_model ,
enum e_sram_orgz cur_sram_orgz_type ,
int mux_size ) {
int num_conf_bits = 0 ;
int iport ;
int lut_size ;
int num_input_port = 0 ;
t_spice_model_port * * input_ports = NULL ;
int num_output_port = 0 ;
t_spice_model_port * * output_ports = NULL ;
int num_sram_port = 0 ;
t_spice_model_port * * sram_ports = NULL ;
assert ( NULL ! = cur_spice_model ) ;
/* Only LUT and MUX requires configuration bits*/
switch ( cur_spice_model - > type ) {
case SPICE_MODEL_LUT :
/* Determine size of LUT*/
input_ports = find_spice_model_ports ( cur_spice_model , SPICE_MODEL_PORT_INPUT , & num_input_port , TRUE ) ;
output_ports = find_spice_model_ports ( cur_spice_model , SPICE_MODEL_PORT_OUTPUT , & num_output_port , TRUE ) ;
sram_ports = find_spice_model_ports ( cur_spice_model , SPICE_MODEL_PORT_SRAM , & num_sram_port , TRUE ) ;
assert ( 1 = = num_input_port ) ;
assert ( 1 = = num_output_port ) ;
assert ( 1 = = num_sram_port ) ;
lut_size = input_ports [ 0 ] - > size ;
num_conf_bits = ( int ) pow ( 2. , ( double ) ( lut_size ) ) ;
assert ( num_conf_bits = = sram_ports [ 0 ] - > size ) ;
assert ( 1 = = output_ports [ 0 ] - > size ) ;
/* TODO: could be more smart! Use mapped spice_model of SRAM ports!
* Support Non - volatile RRAM - based SRAM */
switch ( sram_ports [ 0 ] - > spice_model - > design_tech ) {
case SPICE_MODEL_DESIGN_RRAM :
/* Non-volatile SRAM requires 2 BLs and 2 WLs for each 1 memory bit,
* In memory bank , by intensively share the Bit / Word Lines ,
* we only need 1 additional BL and WL for each memory bit .
* Number of memory bits is still same as CMOS SRAM
*/
switch ( cur_sram_orgz_type ) {
case SPICE_SRAM_MEMORY_BANK :
break ;
case SPICE_SRAM_SCAN_CHAIN :
case SPICE_SRAM_STANDALONE :
num_conf_bits = 2 * num_conf_bits ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (FILE:%s,LINE[%d])Invalid type of SRAM organization! \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
break ;
case SPICE_MODEL_DESIGN_CMOS :
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (FILE:%s,LINE[%d])Invalid design_technology of LUT(name: %s) \n " ,
__FILE__ , __LINE__ , cur_spice_model - > name ) ;
exit ( 1 ) ;
}
break ;
case SPICE_MODEL_MUX :
assert ( ( 2 = = mux_size ) | | ( 2 < mux_size ) ) ;
/* Number of configuration bits depends on the MUX structure */
switch ( cur_spice_model - > design_tech_info . structure ) {
case SPICE_MODEL_STRUCTURE_TREE :
num_conf_bits = determine_tree_mux_level ( mux_size ) ;
break ;
case SPICE_MODEL_STRUCTURE_ONELEVEL :
num_conf_bits = mux_size ;
break ;
case SPICE_MODEL_STRUCTURE_MULTILEVEL :
num_conf_bits = cur_spice_model - > design_tech_info . mux_num_level
* determine_num_input_basis_multilevel_mux ( mux_size ,
cur_spice_model - > design_tech_info . mux_num_level ) ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid structure for spice model (%s)! \n " ,
__FILE__ , __LINE__ , cur_spice_model - > name ) ;
exit ( 1 ) ;
}
/* For 2:1 MUX, whatever structure, there is only one level */
if ( 2 = = mux_size ) {
num_conf_bits = 1 ;
}
/* Also the number of configuration bits depends on the technology*/
switch ( cur_spice_model - > design_tech ) {
case SPICE_MODEL_DESIGN_RRAM :
switch ( cur_sram_orgz_type ) {
case SPICE_SRAM_MEMORY_BANK :
/* In memory bank, by intensively share the Bit/Word Lines,
* we only need 1 additional BL and WL for each MUX level .
*/
num_conf_bits = cur_spice_model - > design_tech_info . mux_num_level ;
/* For 2:1 MUX, whatever structure, there is only one level */
if ( 2 = = mux_size ) {
num_conf_bits = 1 ;
}
break ;
case SPICE_SRAM_SCAN_CHAIN :
case SPICE_SRAM_STANDALONE :
/* Currently we keep the same as CMOS MUX */
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (FILE:%s,LINE[%d])Invalid type of SRAM organization! \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
break ;
case SPICE_MODEL_DESIGN_CMOS :
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (FILE:%s,LINE[%d])Invalid design_technology of MUX(name: %s) \n " ,
__FILE__ , __LINE__ , cur_spice_model - > name ) ;
exit ( 1 ) ;
}
break ;
case SPICE_MODEL_WIRE :
case SPICE_MODEL_FF :
case SPICE_MODEL_SRAM :
case SPICE_MODEL_HARDLOGIC :
case SPICE_MODEL_SCFF :
case SPICE_MODEL_VDD :
case SPICE_MODEL_GND :
case SPICE_MODEL_IOPAD :
/* Other block, we just count the number SRAM ports defined by user */
num_conf_bits = 0 ;
sram_ports = find_spice_model_ports ( cur_spice_model , SPICE_MODEL_PORT_SRAM , & num_sram_port , TRUE ) ;
/* TODO: could be more smart!
* Support Non - volatile RRAM - based SRAM */
if ( 0 < num_sram_port ) {
assert ( NULL ! = sram_ports ) ;
for ( iport = 0 ; iport < num_sram_port ; iport + + ) {
assert ( NULL ! = sram_ports [ iport ] - > spice_model ) ;
/* TODO: could be more smart!
* Support Non - volatile RRAM - based SRAM */
switch ( sram_ports [ iport ] - > spice_model - > design_tech ) {
case SPICE_MODEL_DESIGN_RRAM :
/* Non-volatile SRAM requires 2 BLs and 2 WLs for each 1 memory bit,
* Number of memory bits is still same as CMOS SRAM
*/
switch ( cur_sram_orgz_type ) {
case SPICE_SRAM_MEMORY_BANK :
num_conf_bits + = sram_ports [ iport ] - > size ;
break ;
case SPICE_SRAM_SCAN_CHAIN :
case SPICE_SRAM_STANDALONE :
num_conf_bits + = sram_ports [ iport ] - > size ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (FILE:%s,LINE[%d])Invalid type of SRAM organization! \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
break ;
case SPICE_MODEL_DESIGN_CMOS :
/* Non-volatile SRAM requires 2 BLs and 2 WLs for each 1 memory bit,
* Number of memory bits is still same as CMOS SRAM
*/
switch ( cur_sram_orgz_type ) {
case SPICE_SRAM_MEMORY_BANK :
num_conf_bits + = sram_ports [ iport ] - > size ;
break ;
case SPICE_SRAM_SCAN_CHAIN :
case SPICE_SRAM_STANDALONE :
num_conf_bits + = sram_ports [ iport ] - > size ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (FILE:%s,LINE[%d])Invalid type of SRAM organization! \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (FILE:%s,LINE[%d])Invalid design_technology of LUT(name: %s) \n " ,
__FILE__ , __LINE__ , cur_spice_model - > name ) ;
exit ( 1 ) ;
}
}
}
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s, [LINE%d])Invalid spice_model_type! \n " , __FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
/* Free */
my_free ( input_ports ) ;
my_free ( output_ports ) ;
my_free ( sram_ports ) ;
return num_conf_bits ;
}
int count_num_reserved_conf_bit_one_interc ( t_interconnect * cur_interc ,
enum e_sram_orgz cur_sram_orgz_type ) {
int fan_in = 0 ;
enum e_interconnect spice_interc_type = DIRECT_INTERC ;
int num_reserved_conf_bits = 0 ;
int temp_num_reserved_conf_bits = 0 ;
/* 1. identify pin interconnection type,
* 2. Identify the number of fan - in ( Consider interconnection edges of only selected mode )
* 3. Select and print the SPICE netlist
*/
if ( NULL = = cur_interc ) {
return num_reserved_conf_bits ;
} else {
fan_in = cur_interc - > fan_in ;
if ( 0 = = fan_in ) {
return num_reserved_conf_bits ;
}
}
/* Initialize the interconnection type that will be implemented in SPICE netlist*/
switch ( cur_interc - > type ) {
case DIRECT_INTERC :
assert ( cur_interc - > fan_out = = fan_in ) ;
spice_interc_type = DIRECT_INTERC ;
break ;
case COMPLETE_INTERC :
if ( 1 = = fan_in ) {
spice_interc_type = DIRECT_INTERC ;
} else {
assert ( ( 2 = = fan_in ) | | ( 2 < fan_in ) ) ;
spice_interc_type = MUX_INTERC ;
}
break ;
case MUX_INTERC :
assert ( ( 2 = = fan_in ) | | ( 2 < fan_in ) ) ;
spice_interc_type = MUX_INTERC ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid interconnection type for %s (Arch[LINE%d])! \n " ,
__FILE__ , __LINE__ , cur_interc - > name , cur_interc - > line_num ) ;
exit ( 1 ) ;
}
/* This time, (2nd round), count the number of configuration bits, according to interc type*/
switch ( spice_interc_type ) {
case DIRECT_INTERC :
/* Check :
* 1. Direct interc has only one fan - in !
*/
assert ( ( cur_interc - > fan_out = = fan_in )
| | ( ( COMPLETE_INTERC = = cur_interc - > type ) & & ( 1 = = fan_in ) ) ) ;
break ;
case COMPLETE_INTERC :
case MUX_INTERC :
/* Check :
* MUX should have at least 2 fan_in
*/
assert ( ( 2 = = fan_in ) | | ( 2 < fan_in ) ) ;
assert ( ( 1 = = cur_interc - > fan_out ) | | ( 1 < cur_interc - > fan_out ) ) ;
/* 2. spice_model is a wire */
assert ( NULL ! = cur_interc - > spice_model ) ;
assert ( SPICE_MODEL_MUX = = cur_interc - > spice_model - > type ) ;
temp_num_reserved_conf_bits = count_num_reserved_conf_bits_one_spice_model ( cur_interc - > spice_model ,
cur_sram_orgz_type , fan_in ) ;
/* FOR COMPLETE_INTERC: we should consider fan_out number ! */
if ( temp_num_reserved_conf_bits > num_reserved_conf_bits ) {
num_reserved_conf_bits = temp_num_reserved_conf_bits ;
}
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid interconnection type for %s (Arch[LINE%d])! \n " ,
__FILE__ , __LINE__ , cur_interc - > name , cur_interc - > line_num ) ;
exit ( 1 ) ;
}
return num_reserved_conf_bits ;
}
int count_num_conf_bit_one_interc ( t_interconnect * cur_interc ,
enum e_sram_orgz cur_sram_orgz_type ) {
int fan_in = 0 ;
enum e_interconnect spice_interc_type = DIRECT_INTERC ;
int num_conf_bits = 0 ;
/* 1. identify pin interconnection type,
* 2. Identify the number of fan - in ( Consider interconnection edges of only selected mode )
* 3. Select and print the SPICE netlist
*/
if ( NULL = = cur_interc ) {
return num_conf_bits ;
} else {
fan_in = cur_interc - > fan_in ;
if ( 0 = = fan_in ) {
return num_conf_bits ;
}
}
/* Initialize the interconnection type that will be implemented in SPICE netlist*/
switch ( cur_interc - > type ) {
case DIRECT_INTERC :
assert ( cur_interc - > fan_out = = fan_in ) ;
spice_interc_type = DIRECT_INTERC ;
break ;
case COMPLETE_INTERC :
if ( 1 = = fan_in ) {
spice_interc_type = DIRECT_INTERC ;
} else {
assert ( ( 2 = = fan_in ) | | ( 2 < fan_in ) ) ;
spice_interc_type = MUX_INTERC ;
}
break ;
case MUX_INTERC :
assert ( ( 2 = = fan_in ) | | ( 2 < fan_in ) ) ;
spice_interc_type = MUX_INTERC ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid interconnection type for %s (Arch[LINE%d])! \n " ,
__FILE__ , __LINE__ , cur_interc - > name , cur_interc - > line_num ) ;
exit ( 1 ) ;
}
/* This time, (2nd round), count the number of configuration bits, according to interc type*/
switch ( spice_interc_type ) {
case DIRECT_INTERC :
/* Check :
* 1. Direct interc has only one fan - in !
*/
assert ( ( cur_interc - > fan_out = = fan_in )
| | ( ( COMPLETE_INTERC = = cur_interc - > type ) & & ( 1 = = fan_in ) ) ) ;
break ;
case COMPLETE_INTERC :
case MUX_INTERC :
/* Check :
* MUX should have at least 2 fan_in
*/
assert ( ( 2 = = fan_in ) | | ( 2 < fan_in ) ) ;
assert ( ( 1 = = cur_interc - > fan_out ) | | ( 1 < cur_interc - > fan_out ) ) ;
/* 2. spice_model is a wire */
assert ( NULL ! = cur_interc - > spice_model ) ;
assert ( SPICE_MODEL_MUX = = cur_interc - > spice_model - > type ) ;
num_conf_bits = count_num_conf_bits_one_spice_model ( cur_interc - > spice_model ,
cur_sram_orgz_type , fan_in ) ;
/* FOR COMPLETE_INTERC: we should consider fan_out number ! */
num_conf_bits = num_conf_bits * cur_interc - > fan_out ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid interconnection type for %s (Arch[LINE%d])! \n " ,
__FILE__ , __LINE__ , cur_interc - > name , cur_interc - > line_num ) ;
exit ( 1 ) ;
}
return num_conf_bits ;
}
/* Count the number of configuration bits of interconnection inside a pb_type in its default mode */
int count_num_conf_bits_pb_type_mode_interc ( t_mode * cur_pb_type_mode ,
enum e_sram_orgz cur_sram_orgz_type ) {
int num_conf_bits = 0 ;
int jinterc = 0 ;
for ( jinterc = 0 ; jinterc < cur_pb_type_mode - > num_interconnect ; jinterc + + ) {
num_conf_bits + = count_num_conf_bit_one_interc ( & ( cur_pb_type_mode - > interconnect [ jinterc ] ) ,
cur_sram_orgz_type ) ;
}
return num_conf_bits ;
}
/* Count the number of configuration bits of interconnection inside a pb_type in its default mode */
int count_num_reserved_conf_bits_pb_type_mode_interc ( t_mode * cur_pb_type_mode ,
enum e_sram_orgz cur_sram_orgz_type ) {
int num_reserved_conf_bits = 0 ;
int temp_num_reserved_conf_bits = 0 ;
int jinterc = 0 ;
for ( jinterc = 0 ; jinterc < cur_pb_type_mode - > num_interconnect ; jinterc + + ) {
/* num of reserved configuration bits is determined by the largest one */
temp_num_reserved_conf_bits =
count_num_reserved_conf_bit_one_interc ( & ( cur_pb_type_mode - > interconnect [ jinterc ] ) ,
cur_sram_orgz_type ) ;
if ( temp_num_reserved_conf_bits > num_reserved_conf_bits ) {
num_reserved_conf_bits = temp_num_reserved_conf_bits ;
}
}
return num_reserved_conf_bits ;
}
/* Count the number of configuration bits of a grid (type_descriptor) in default mode */
int rec_count_num_conf_bits_pb_type_default_mode ( t_pb_type * cur_pb_type ,
t_sram_orgz_info * cur_sram_orgz_info ) {
int mode_index , ipb , jpb ;
int sum_num_conf_bits = 0 ;
int num_reserved_conf_bits = 0 ;
int temp_num_reserved_conf_bits = 0 ;
cur_pb_type - > default_mode_num_conf_bits = 0 ;
/* Recursively finish all the child pb_types*/
if ( NULL = = cur_pb_type - > spice_model ) {
/* Find the mode that define_idle_mode*/
mode_index = find_pb_type_idle_mode_index ( ( * cur_pb_type ) ) ;
for ( ipb = 0 ; ipb < cur_pb_type - > modes [ mode_index ] . num_pb_type_children ; ipb + + ) {
for ( jpb = 0 ; jpb < cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . num_pb ; jpb + + ) {
rec_count_num_conf_bits_pb_type_default_mode ( & ( cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] ) , cur_sram_orgz_info ) ;
}
}
}
/* Check if this has defined a spice_model*/
if ( NULL ! = cur_pb_type - > spice_model ) {
sum_num_conf_bits = count_num_conf_bits_one_spice_model ( cur_pb_type - > spice_model , cur_sram_orgz_info - > type , 0 ) ;
cur_pb_type - > default_mode_num_conf_bits = sum_num_conf_bits ;
/* calculate the number of reserved configuration bits */
cur_pb_type - > default_mode_num_reserved_conf_bits =
count_num_reserved_conf_bits_one_spice_model ( cur_pb_type - > spice_model ,
cur_sram_orgz_info - > type , 0 ) ;
} else { /* Count the sum of configuration bits of all the children pb_types */
/* Find the mode that define_idle_mode*/
mode_index = find_pb_type_idle_mode_index ( ( * cur_pb_type ) ) ;
/* Quote all child pb_types */
for ( ipb = 0 ; ipb < cur_pb_type - > modes [ mode_index ] . num_pb_type_children ; ipb + + ) {
/* Each child may exist multiple times in the hierarchy*/
for ( jpb = 0 ; jpb < cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . num_pb ; jpb + + ) {
/* Count in the number of configuration bits of on child pb_type */
sum_num_conf_bits + = cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . default_mode_num_conf_bits ;
temp_num_reserved_conf_bits =
cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . default_mode_num_reserved_conf_bits ;
/* number of reserved conf. bits is deteremined by the largest number of reserved conf. bits !*/
if ( temp_num_reserved_conf_bits > num_reserved_conf_bits ) {
num_reserved_conf_bits = temp_num_reserved_conf_bits ;
}
}
}
/* Count the number of configuration bits of interconnection */
sum_num_conf_bits + = count_num_conf_bits_pb_type_mode_interc ( & ( cur_pb_type - > modes [ mode_index ] ) , cur_sram_orgz_info - > type ) ;
/* Count the number of reserved_configuration bits of interconnection */
temp_num_reserved_conf_bits =
count_num_reserved_conf_bits_pb_type_mode_interc ( & ( cur_pb_type - > modes [ mode_index ] ) ,
cur_sram_orgz_info - > type ) ;
/* number of reserved conf. bits is deteremined by the largest number of reserved conf. bits !*/
if ( temp_num_reserved_conf_bits > num_reserved_conf_bits ) {
num_reserved_conf_bits = temp_num_reserved_conf_bits ;
}
/* Update the info in pb_type */
cur_pb_type - > default_mode_num_reserved_conf_bits = num_reserved_conf_bits ;
cur_pb_type - > default_mode_num_conf_bits = sum_num_conf_bits ;
}
return sum_num_conf_bits ;
}
/* Count the number of configuration bits of a grid (type_descriptor) in default mode */
int rec_count_num_conf_bits_pb_type_physical_mode ( t_pb_type * cur_pb_type ,
t_sram_orgz_info * cur_sram_orgz_info ) {
int mode_index , ipb , jpb ;
int sum_num_conf_bits = 0 ;
int num_reserved_conf_bits = 0 ;
int temp_num_reserved_conf_bits = 0 ;
cur_pb_type - > physical_mode_num_conf_bits = 0 ;
/* Recursively finish all the child pb_types*/
if ( NULL = = cur_pb_type - > spice_model ) {
/* Find the mode that define_idle_mode*/
mode_index = find_pb_type_physical_mode_index ( ( * cur_pb_type ) ) ;
for ( ipb = 0 ; ipb < cur_pb_type - > modes [ mode_index ] . num_pb_type_children ; ipb + + ) {
for ( jpb = 0 ; jpb < cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . num_pb ; jpb + + ) {
rec_count_num_conf_bits_pb_type_physical_mode ( & ( cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] ) , cur_sram_orgz_info ) ;
}
}
}
/* Check if this has defined a spice_model*/
if ( NULL ! = cur_pb_type - > spice_model ) {
sum_num_conf_bits = count_num_conf_bits_one_spice_model ( cur_pb_type - > spice_model , cur_sram_orgz_info - > type , 0 ) ;
cur_pb_type - > physical_mode_num_conf_bits = sum_num_conf_bits ;
/* calculate the number of reserved configuration bits */
cur_pb_type - > physical_mode_num_reserved_conf_bits =
count_num_reserved_conf_bits_one_spice_model ( cur_pb_type - > spice_model ,
cur_sram_orgz_info - > type , 0 ) ;
} else { /* Count the sum of configuration bits of all the children pb_types */
/* Find the mode that define_idle_mode*/
mode_index = find_pb_type_physical_mode_index ( ( * cur_pb_type ) ) ;
/* Quote all child pb_types */
for ( ipb = 0 ; ipb < cur_pb_type - > modes [ mode_index ] . num_pb_type_children ; ipb + + ) {
/* Each child may exist multiple times in the hierarchy*/
for ( jpb = 0 ; jpb < cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . num_pb ; jpb + + ) {
/* Count in the number of configuration bits of on child pb_type */
sum_num_conf_bits + = cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . physical_mode_num_conf_bits ;
temp_num_reserved_conf_bits = cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . physical_mode_num_reserved_conf_bits ;
/* number of reserved conf. bits is deteremined by the largest number of reserved conf. bits !*/
if ( temp_num_reserved_conf_bits > num_reserved_conf_bits ) {
num_reserved_conf_bits = temp_num_reserved_conf_bits ;
}
}
}
/* Count the number of configuration bits of interconnection */
sum_num_conf_bits + = count_num_conf_bits_pb_type_mode_interc ( & ( cur_pb_type - > modes [ mode_index ] ) ,
cur_sram_orgz_info - > type ) ;
/* Count the number of reserved_configuration bits of interconnection */
temp_num_reserved_conf_bits =
count_num_reserved_conf_bits_pb_type_mode_interc ( & ( cur_pb_type - > modes [ mode_index ] ) ,
cur_sram_orgz_info - > type ) ;
/* number of reserved conf. bits is deteremined by the largest number of reserved conf. bits !*/
if ( temp_num_reserved_conf_bits > num_reserved_conf_bits ) {
num_reserved_conf_bits = temp_num_reserved_conf_bits ;
}
/* Update the info in pb_type */
cur_pb_type - > physical_mode_num_reserved_conf_bits = num_reserved_conf_bits ;
cur_pb_type - > physical_mode_num_conf_bits = sum_num_conf_bits ;
}
return sum_num_conf_bits ;
}
/* Count the number of configuration bits of a pb_graph_node */
int rec_count_num_conf_bits_pb ( t_pb * cur_pb ,
t_sram_orgz_info * cur_sram_orgz_info ) {
int mode_index , ipb , jpb ;
t_pb_type * cur_pb_type = NULL ;
t_pb_graph_node * cur_pb_graph_node = NULL ;
int sum_num_conf_bits = 0 ;
int num_reserved_conf_bits = 0 ;
int temp_num_reserved_conf_bits = 0 ;
/* Check cur_pb_graph_node*/
if ( NULL = = cur_pb ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid cur_pb. \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
cur_pb_graph_node = cur_pb - > pb_graph_node ;
cur_pb_type = cur_pb_graph_node - > pb_type ;
mode_index = cur_pb - > mode ;
cur_pb - > num_conf_bits = 0 ;
/* Recursively finish all the child pb_types*/
if ( NULL = = cur_pb_type - > spice_model ) {
/* recursive for the child_pbs*/
for ( ipb = 0 ; ipb < cur_pb_type - > modes [ mode_index ] . num_pb_type_children ; ipb + + ) {
for ( jpb = 0 ; jpb < cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . num_pb ; jpb + + ) {
/* Recursive*/
/* Refer to pack/output_clustering.c [LINE 392] */
if ( ( NULL ! = cur_pb - > child_pbs [ ipb ] ) & & ( NULL ! = cur_pb - > child_pbs [ ipb ] [ jpb ] . name ) ) {
rec_count_num_conf_bits_pb ( & ( cur_pb - > child_pbs [ ipb ] [ jpb ] ) , cur_sram_orgz_info ) ;
} else {
/* Check if this pb has no children, no children mean idle*/
rec_count_num_conf_bits_pb_type_default_mode ( cur_pb - > child_pbs [ ipb ] [ jpb ] . pb_graph_node - > pb_type ,
cur_sram_orgz_info ) ;
}
}
}
}
/* Check if this has defined a spice_model*/
if ( NULL ! = cur_pb_type - > spice_model ) {
sum_num_conf_bits + = count_num_conf_bits_one_spice_model ( cur_pb_type - > spice_model ,
cur_sram_orgz_info - > type , 0 ) ;
cur_pb - > num_conf_bits = sum_num_conf_bits ;
/* calculate the number of reserved configuration bits */
cur_pb - > num_reserved_conf_bits =
count_num_reserved_conf_bits_one_spice_model ( cur_pb_type - > spice_model ,
cur_sram_orgz_info - > type , 0 ) ;
} else {
/* Definition ends*/
/* Quote all child pb_types */
for ( ipb = 0 ; ipb < cur_pb_type - > modes [ mode_index ] . num_pb_type_children ; ipb + + ) {
/* Each child may exist multiple times in the hierarchy*/
for ( jpb = 0 ; jpb < cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . num_pb ; jpb + + ) {
/* we should make sure this placement index == child_pb_type[jpb]*/
assert ( jpb = = cur_pb_graph_node - > child_pb_graph_nodes [ mode_index ] [ ipb ] [ jpb ] . placement_index ) ;
if ( ( NULL ! = cur_pb - > child_pbs [ ipb ] ) & & ( NULL ! = cur_pb - > child_pbs [ ipb ] [ jpb ] . name ) ) {
/* Count in the number of configuration bits of on child pb */
sum_num_conf_bits + = cur_pb - > child_pbs [ ipb ] [ jpb ] . num_conf_bits ;
temp_num_reserved_conf_bits = cur_pb - > child_pbs [ ipb ] [ jpb ] . num_reserved_conf_bits ;
} else {
/* Count in the number of configuration bits of on child pb_type */
sum_num_conf_bits + = cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . default_mode_num_conf_bits ;
temp_num_reserved_conf_bits =
cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . default_mode_num_reserved_conf_bits ;
}
/* number of reserved conf. bits is deteremined by the largest number of reserved conf. bits !*/
if ( temp_num_reserved_conf_bits > num_reserved_conf_bits ) {
num_reserved_conf_bits = temp_num_reserved_conf_bits ;
}
}
}
/* Count the number of configuration bits of interconnection */
sum_num_conf_bits + = count_num_conf_bits_pb_type_mode_interc ( & ( cur_pb_type - > modes [ mode_index ] ) ,
cur_sram_orgz_info - > type ) ;
/* Count the number of reserved_configuration bits of interconnection */
temp_num_reserved_conf_bits =
count_num_reserved_conf_bits_pb_type_mode_interc ( & ( cur_pb_type - > modes [ mode_index ] ) ,
cur_sram_orgz_info - > type ) ;
/* number of reserved conf. bits is deteremined by the largest number of reserved conf. bits !*/
if ( temp_num_reserved_conf_bits > num_reserved_conf_bits ) {
num_reserved_conf_bits = temp_num_reserved_conf_bits ;
}
/* Update the info in pb_type */
cur_pb - > num_reserved_conf_bits = num_reserved_conf_bits ;
cur_pb - > num_conf_bits = sum_num_conf_bits ;
}
return sum_num_conf_bits ;
}
/* Initialize the number of configuraion bits for one grid */
void init_one_grid_num_conf_bits ( int ix , int iy ,
t_sram_orgz_info * cur_sram_orgz_info ) {
t_block * mapped_block = NULL ;
int iz ;
int cur_block_index = 0 ;
int capacity ;
/* Check */
assert ( ( ! ( 0 > ix ) ) & & ( ! ( ix > ( nx + 1 ) ) ) ) ;
assert ( ( ! ( 0 > iy ) ) & & ( ! ( iy > ( ny + 1 ) ) ) ) ;
2018-08-01 15:04:28 -05:00
if ( ( NULL = = grid [ ix ] [ iy ] . type )
| | ( EMPTY_TYPE = = grid [ ix ] [ iy ] . type )
| | ( 0 ! = grid [ ix ] [ iy ] . offset ) ) {
2018-07-26 12:28:21 -05:00
/* Empty grid, directly return */
return ;
}
capacity = grid [ ix ] [ iy ] . type - > capacity ;
assert ( 0 < capacity ) ;
/* check capacity and if this has been mapped */
for ( iz = 0 ; iz < capacity ; iz + + ) {
/* Check in all the blocks(clustered logic block), there is a match x,y,z*/
mapped_block = search_mapped_block ( ix , iy , iz ) ;
rec_count_num_conf_bits_pb_type_physical_mode ( grid [ ix ] [ iy ] . type - > pb_type , cur_sram_orgz_info ) ;
/* Comments: Grid [x][y]*/
if ( NULL = = mapped_block ) {
/* Print a consider a idle pb_type ...*/
rec_count_num_conf_bits_pb_type_default_mode ( grid [ ix ] [ iy ] . type - > pb_type , cur_sram_orgz_info ) ;
} else {
if ( iz = = mapped_block - > z ) {
// assert(mapped_block == &(block[grid[ix][iy].blocks[cur_block_index]]));
cur_block_index + + ;
}
rec_count_num_conf_bits_pb ( mapped_block - > pb , cur_sram_orgz_info ) ;
}
}
assert ( cur_block_index = = grid [ ix ] [ iy ] . usage ) ;
return ;
}
/* Initialize the number of configuraion bits for all grids */
void init_grids_num_conf_bits ( t_sram_orgz_info * cur_sram_orgz_info ) {
int ix , iy ;
/* Core grid */
vpr_printf ( TIO_MESSAGE_INFO , " INFO: Initializing number of configuration bits of Core grids... \n " ) ;
for ( ix = 1 ; ix < ( nx + 1 ) ; ix + + ) {
for ( iy = 1 ; iy < ( ny + 1 ) ; iy + + ) {
init_one_grid_num_conf_bits ( ix , iy , cur_sram_orgz_info ) ;
}
}
/* Consider the IO pads */
vpr_printf ( TIO_MESSAGE_INFO , " INFO: Initializing number of configuration bits of I/O grids... \n " ) ;
/* Left side: x = 0, y = 1 .. ny*/
ix = 0 ;
for ( iy = 1 ; iy < ( ny + 1 ) ; iy + + ) {
/* Ensure this is a io */
assert ( IO_TYPE = = grid [ ix ] [ iy ] . type ) ;
init_one_grid_num_conf_bits ( ix , iy , cur_sram_orgz_info ) ;
}
/* Right side : x = nx + 1, y = 1 .. ny*/
ix = nx + 1 ;
for ( iy = 1 ; iy < ( ny + 1 ) ; iy + + ) {
/* Ensure this is a io */
assert ( IO_TYPE = = grid [ ix ] [ iy ] . type ) ;
init_one_grid_num_conf_bits ( ix , iy , cur_sram_orgz_info ) ;
}
/* Bottom side : x = 1 .. nx + 1, y = 0 */
iy = 0 ;
for ( ix = 1 ; ix < ( nx + 1 ) ; ix + + ) {
/* Ensure this is a io */
assert ( IO_TYPE = = grid [ ix ] [ iy ] . type ) ;
init_one_grid_num_conf_bits ( ix , iy , cur_sram_orgz_info ) ;
}
/* Top side : x = 1 .. nx + 1, y = nx + 1 */
iy = ny + 1 ;
for ( ix = 1 ; ix < ( nx + 1 ) ; ix + + ) {
/* Ensure this is a io */
assert ( IO_TYPE = = grid [ ix ] [ iy ] . type ) ;
init_one_grid_num_conf_bits ( ix , iy , cur_sram_orgz_info ) ;
}
return ;
}
/* Reset the counter of each spice_model to be zero */
void zero_spice_models_cnt ( int num_spice_models , t_spice_model * spice_model ) {
int imodel = 0 ;
for ( imodel = 0 ; imodel < num_spice_models ; imodel + + ) {
spice_model [ imodel ] . cnt = 0 ;
}
return ;
}
void zero_one_spice_model_routing_index_low_high ( t_spice_model * cur_spice_model ) {
int ix , iy ;
/* Initialize */
for ( ix = 0 ; ix < ( nx + 1 ) ; ix + + ) {
for ( iy = 0 ; iy < ( ny + 1 ) ; iy + + ) {
cur_spice_model - > sb_index_low [ ix ] [ iy ] = 0 ;
cur_spice_model - > cbx_index_low [ ix ] [ iy ] = 0 ;
cur_spice_model - > cby_index_low [ ix ] [ iy ] = 0 ;
cur_spice_model - > sb_index_high [ ix ] [ iy ] = 0 ;
cur_spice_model - > cbx_index_high [ ix ] [ iy ] = 0 ;
cur_spice_model - > cby_index_high [ ix ] [ iy ] = 0 ;
}
}
return ;
}
void zero_spice_models_routing_index_low_high ( int num_spice_models ,
t_spice_model * spice_model ) {
int i ;
for ( i = 0 ; i < num_spice_models ; i + + ) {
zero_one_spice_model_routing_index_low_high ( & ( spice_model [ i ] ) ) ;
}
return ;
}
/* Malloc routing_index_low and routing_index_high for a spice_model */
void alloc_spice_model_routing_index_low_high ( t_spice_model * cur_spice_model ) {
int ix ;
/* [cbx|cby|sb]_index_low */
/* x - direction*/
cur_spice_model - > sb_index_low = ( int * * ) my_malloc ( sizeof ( int * ) * ( nx + 1 ) ) ;
cur_spice_model - > cbx_index_low = ( int * * ) my_malloc ( sizeof ( int * ) * ( nx + 1 ) ) ;
cur_spice_model - > cby_index_low = ( int * * ) my_malloc ( sizeof ( int * ) * ( nx + 1 ) ) ;
/* y - direction*/
for ( ix = 0 ; ix < ( nx + 1 ) ; ix + + ) {
cur_spice_model - > sb_index_low [ ix ] = ( int * ) my_malloc ( sizeof ( int ) * ( ny + 1 ) ) ;
cur_spice_model - > cbx_index_low [ ix ] = ( int * ) my_malloc ( sizeof ( int ) * ( ny + 1 ) ) ;
cur_spice_model - > cby_index_low [ ix ] = ( int * ) my_malloc ( sizeof ( int ) * ( ny + 1 ) ) ;
}
/* grid_index_high */
/* x - direction*/
cur_spice_model - > sb_index_high = ( int * * ) my_malloc ( sizeof ( int * ) * ( nx + 1 ) ) ;
cur_spice_model - > cbx_index_high = ( int * * ) my_malloc ( sizeof ( int * ) * ( nx + 1 ) ) ;
cur_spice_model - > cby_index_high = ( int * * ) my_malloc ( sizeof ( int * ) * ( nx + 1 ) ) ;
/* y - direction*/
for ( ix = 0 ; ix < ( nx + 1 ) ; ix + + ) {
cur_spice_model - > sb_index_high [ ix ] = ( int * ) my_malloc ( sizeof ( int ) * ( ny + 1 ) ) ;
cur_spice_model - > cbx_index_high [ ix ] = ( int * ) my_malloc ( sizeof ( int ) * ( ny + 1 ) ) ;
cur_spice_model - > cby_index_high [ ix ] = ( int * ) my_malloc ( sizeof ( int ) * ( ny + 1 ) ) ;
}
zero_one_spice_model_routing_index_low_high ( cur_spice_model ) ;
return ;
}
void free_one_spice_model_routing_index_low_high ( t_spice_model * cur_spice_model ) {
int ix ;
/* index_high */
for ( ix = 0 ; ix < ( nx + 1 ) ; ix + + ) {
my_free ( cur_spice_model - > sb_index_low [ ix ] ) ;
my_free ( cur_spice_model - > cbx_index_low [ ix ] ) ;
my_free ( cur_spice_model - > cby_index_low [ ix ] ) ;
my_free ( cur_spice_model - > sb_index_high [ ix ] ) ;
my_free ( cur_spice_model - > cbx_index_high [ ix ] ) ;
my_free ( cur_spice_model - > cby_index_high [ ix ] ) ;
}
my_free ( cur_spice_model - > sb_index_low ) ;
my_free ( cur_spice_model - > cbx_index_low ) ;
my_free ( cur_spice_model - > cby_index_low ) ;
my_free ( cur_spice_model - > sb_index_high ) ;
my_free ( cur_spice_model - > cbx_index_high ) ;
my_free ( cur_spice_model - > cby_index_high ) ;
return ;
}
void free_spice_model_routing_index_low_high ( int num_spice_models ,
t_spice_model * spice_model ) {
int i ;
for ( i = 0 ; i < num_spice_models ; i + + ) {
free_one_spice_model_routing_index_low_high ( & ( spice_model [ i ] ) ) ;
}
return ;
}
void update_one_spice_model_routing_index_high ( int x , int y , t_rr_type chan_type ,
t_spice_model * cur_spice_model ) {
/* Check */
assert ( ( ! ( 0 > x ) ) & & ( ! ( x > ( nx + 1 ) ) ) ) ;
assert ( ( ! ( 0 > y ) ) & & ( ! ( y > ( ny + 1 ) ) ) ) ;
assert ( NULL ! = cur_spice_model ) ;
assert ( NULL ! = cur_spice_model - > sb_index_high ) ;
assert ( NULL ! = cur_spice_model - > sb_index_high [ x ] ) ;
assert ( NULL ! = cur_spice_model - > cbx_index_high ) ;
assert ( NULL ! = cur_spice_model - > cbx_index_high [ x ] ) ;
assert ( NULL ! = cur_spice_model - > cby_index_high ) ;
assert ( NULL ! = cur_spice_model - > cby_index_high [ x ] ) ;
/* Assigne the low */
if ( CHANX = = chan_type ) {
cur_spice_model - > cbx_index_high [ x ] [ y ] = cur_spice_model - > cnt ;
} else if ( CHANY = = chan_type ) {
cur_spice_model - > cby_index_high [ x ] [ y ] = cur_spice_model - > cnt ;
} else if ( SOURCE = = chan_type ) {
cur_spice_model - > sb_index_high [ x ] [ y ] = cur_spice_model - > cnt ;
}
return ;
}
void update_spice_models_routing_index_high ( int x , int y , t_rr_type chan_type ,
int num_spice_models ,
t_spice_model * spice_model ) {
int i ;
for ( i = 0 ; i < num_spice_models ; i + + ) {
update_one_spice_model_routing_index_high ( x , y , chan_type , & ( spice_model [ i ] ) ) ;
}
return ;
}
void update_one_spice_model_routing_index_low ( int x , int y , t_rr_type chan_type ,
t_spice_model * cur_spice_model ) {
/* Check */
assert ( ( ! ( 0 > x ) ) & & ( ! ( x > ( nx + 1 ) ) ) ) ;
assert ( ( ! ( 0 > y ) ) & & ( ! ( y > ( ny + 1 ) ) ) ) ;
assert ( NULL ! = cur_spice_model ) ;
assert ( NULL ! = cur_spice_model - > sb_index_low ) ;
assert ( NULL ! = cur_spice_model - > sb_index_low [ x ] ) ;
assert ( NULL ! = cur_spice_model - > cbx_index_low ) ;
assert ( NULL ! = cur_spice_model - > cbx_index_low [ x ] ) ;
assert ( NULL ! = cur_spice_model - > cby_index_low ) ;
assert ( NULL ! = cur_spice_model - > cby_index_low [ x ] ) ;
/* Assigne the low */
if ( CHANX = = chan_type ) {
cur_spice_model - > cbx_index_low [ x ] [ y ] = cur_spice_model - > cnt ;
} else if ( CHANY = = chan_type ) {
cur_spice_model - > cby_index_low [ x ] [ y ] = cur_spice_model - > cnt ;
} else if ( SOURCE = = chan_type ) {
cur_spice_model - > sb_index_low [ x ] [ y ] = cur_spice_model - > cnt ;
}
return ;
}
void update_spice_models_routing_index_low ( int x , int y , t_rr_type chan_type ,
int num_spice_models ,
t_spice_model * spice_model ) {
int i ;
for ( i = 0 ; i < num_spice_models ; i + + ) {
update_one_spice_model_routing_index_low ( x , y , chan_type , & ( spice_model [ i ] ) ) ;
}
return ;
}
/* Count the number of inpad and outpad of a grid (type_descriptor) in default mode */
void rec_count_num_iopads_pb_type_physical_mode ( t_pb_type * cur_pb_type ) {
int mode_index , ipb , jpb ;
int sum_num_iopads = 0 ;
cur_pb_type - > physical_mode_num_iopads = 0 ;
/* Recursively finish all the child pb_types*/
if ( NULL = = cur_pb_type - > spice_model ) {
/* Find the mode that define_idle_mode*/
mode_index = find_pb_type_physical_mode_index ( ( * cur_pb_type ) ) ;
for ( ipb = 0 ; ipb < cur_pb_type - > modes [ mode_index ] . num_pb_type_children ; ipb + + ) {
for ( jpb = 0 ; jpb < cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . num_pb ; jpb + + ) {
rec_count_num_iopads_pb_type_physical_mode ( & ( cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] ) ) ;
}
}
}
/* Check if this has defined a spice_model*/
if ( NULL ! = cur_pb_type - > spice_model ) {
if ( SPICE_MODEL_IOPAD = = cur_pb_type - > spice_model - > type ) {
sum_num_iopads = 1 ;
cur_pb_type - > physical_mode_num_iopads = sum_num_iopads ;
}
} else { /* Count the sum of configuration bits of all the children pb_types */
/* Find the mode that define_idle_mode*/
mode_index = find_pb_type_physical_mode_index ( ( * cur_pb_type ) ) ;
/* Quote all child pb_types */
for ( ipb = 0 ; ipb < cur_pb_type - > modes [ mode_index ] . num_pb_type_children ; ipb + + ) {
/* Each child may exist multiple times in the hierarchy*/
for ( jpb = 0 ; jpb < cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . num_pb ; jpb + + ) {
/* Count in the number of configuration bits of on child pb_type */
sum_num_iopads + = cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . physical_mode_num_iopads ;
}
}
/* Count the number of configuration bits of interconnection */
/* Update the info in pb_type */
cur_pb_type - > physical_mode_num_iopads = sum_num_iopads ;
}
return ;
}
/* Count the number of inpad and outpad of a grid (type_descriptor) in default mode */
void rec_count_num_iopads_pb_type_default_mode ( t_pb_type * cur_pb_type ) {
int mode_index , ipb , jpb ;
int sum_num_iopads = 0 ;
cur_pb_type - > default_mode_num_iopads = 0 ;
/* Recursively finish all the child pb_types*/
if ( NULL = = cur_pb_type - > spice_model ) {
/* Find the mode that define_idle_mode*/
mode_index = find_pb_type_idle_mode_index ( ( * cur_pb_type ) ) ;
for ( ipb = 0 ; ipb < cur_pb_type - > modes [ mode_index ] . num_pb_type_children ; ipb + + ) {
for ( jpb = 0 ; jpb < cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . num_pb ; jpb + + ) {
rec_count_num_iopads_pb_type_default_mode ( & ( cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] ) ) ;
}
}
}
/* Check if this has defined a spice_model*/
if ( NULL ! = cur_pb_type - > spice_model ) {
if ( SPICE_MODEL_IOPAD = = cur_pb_type - > spice_model - > type ) {
sum_num_iopads = 1 ;
cur_pb_type - > default_mode_num_iopads = sum_num_iopads ;
}
} else { /* Count the sum of configuration bits of all the children pb_types */
/* Find the mode that define_idle_mode*/
mode_index = find_pb_type_idle_mode_index ( ( * cur_pb_type ) ) ;
/* Quote all child pb_types */
for ( ipb = 0 ; ipb < cur_pb_type - > modes [ mode_index ] . num_pb_type_children ; ipb + + ) {
/* Each child may exist multiple times in the hierarchy*/
for ( jpb = 0 ; jpb < cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . num_pb ; jpb + + ) {
/* Count in the number of configuration bits of on child pb_type */
sum_num_iopads + = cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . default_mode_num_iopads ;
}
}
/* Count the number of configuration bits of interconnection */
/* Update the info in pb_type */
cur_pb_type - > default_mode_num_iopads = sum_num_iopads ;
}
return ;
}
/* Count the number of configuration bits of a pb_graph_node */
void rec_count_num_iopads_pb ( t_pb * cur_pb ) {
int mode_index , ipb , jpb ;
t_pb_type * cur_pb_type = NULL ;
t_pb_graph_node * cur_pb_graph_node = NULL ;
int sum_num_iopads = 0 ;
/* Check cur_pb_graph_node*/
if ( NULL = = cur_pb ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid cur_pb. \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
cur_pb_graph_node = cur_pb - > pb_graph_node ;
cur_pb_type = cur_pb_graph_node - > pb_type ;
mode_index = cur_pb - > mode ;
cur_pb - > num_iopads = 0 ;
/* Recursively finish all the child pb_types*/
if ( NULL = = cur_pb_type - > spice_model ) {
/* recursive for the child_pbs*/
for ( ipb = 0 ; ipb < cur_pb_type - > modes [ mode_index ] . num_pb_type_children ; ipb + + ) {
for ( jpb = 0 ; jpb < cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . num_pb ; jpb + + ) {
/* Recursive*/
/* Refer to pack/output_clustering.c [LINE 392] */
if ( ( NULL ! = cur_pb - > child_pbs [ ipb ] ) & & ( NULL ! = cur_pb - > child_pbs [ ipb ] [ jpb ] . name ) ) {
rec_count_num_iopads_pb ( & ( cur_pb - > child_pbs [ ipb ] [ jpb ] ) ) ;
} else {
/* Check if this pb has no children, no children mean idle*/
rec_count_num_iopads_pb_type_default_mode ( cur_pb - > child_pbs [ ipb ] [ jpb ] . pb_graph_node - > pb_type ) ;
}
}
}
}
/* Check if this has defined a spice_model*/
if ( NULL ! = cur_pb_type - > spice_model ) {
if ( SPICE_MODEL_IOPAD = = cur_pb_type - > spice_model - > type ) {
sum_num_iopads = 1 ;
cur_pb - > num_iopads = sum_num_iopads ;
}
} else {
/* Definition ends*/
/* Quote all child pb_types */
for ( ipb = 0 ; ipb < cur_pb_type - > modes [ mode_index ] . num_pb_type_children ; ipb + + ) {
/* Each child may exist multiple times in the hierarchy*/
for ( jpb = 0 ; jpb < cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . num_pb ; jpb + + ) {
/* we should make sure this placement index == child_pb_type[jpb]*/
assert ( jpb = = cur_pb_graph_node - > child_pb_graph_nodes [ mode_index ] [ ipb ] [ jpb ] . placement_index ) ;
if ( ( NULL ! = cur_pb - > child_pbs [ ipb ] ) & & ( NULL ! = cur_pb - > child_pbs [ ipb ] [ jpb ] . name ) ) {
/* Count in the number of configuration bits of on child pb */
sum_num_iopads + = cur_pb - > child_pbs [ ipb ] [ jpb ] . num_iopads ;
} else {
/* Count in the number of configuration bits of on child pb_type */
sum_num_iopads + = cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . default_mode_num_iopads ;
}
}
}
/* Count the number of configuration bits of interconnection */
/* Update the info in pb_type */
cur_pb - > num_iopads = sum_num_iopads ;
}
return ;
}
/* Initialize the number of configuraion bits for one grid */
void init_one_grid_num_iopads ( int ix , int iy ) {
t_block * mapped_block = NULL ;
int iz ;
int cur_block_index = 0 ;
int capacity ;
/* Check */
assert ( ( ! ( 0 > ix ) ) & & ( ! ( ix > ( nx + 1 ) ) ) ) ;
assert ( ( ! ( 0 > iy ) ) & & ( ! ( iy > ( ny + 1 ) ) ) ) ;
2018-08-01 15:04:28 -05:00
if ( ( NULL = = grid [ ix ] [ iy ] . type )
| | ( EMPTY_TYPE = = grid [ ix ] [ iy ] . type )
| | ( 0 ! = grid [ ix ] [ iy ] . offset ) ) {
2018-07-26 12:28:21 -05:00
/* Empty grid, directly return */
return ;
}
capacity = grid [ ix ] [ iy ] . type - > capacity ;
assert ( 0 < capacity ) ;
/* check capacity and if this has been mapped */
for ( iz = 0 ; iz < capacity ; iz + + ) {
/* Check in all the blocks(clustered logic block), there is a match x,y,z*/
mapped_block = search_mapped_block ( ix , iy , iz ) ;
rec_count_num_iopads_pb_type_physical_mode ( grid [ ix ] [ iy ] . type - > pb_type ) ;
/* Comments: Grid [x][y]*/
if ( NULL = = mapped_block ) {
/* Print a consider a idle pb_type ...*/
rec_count_num_iopads_pb_type_default_mode ( grid [ ix ] [ iy ] . type - > pb_type ) ;
} else {
if ( iz = = mapped_block - > z ) {
// assert(mapped_block == &(block[grid[ix][iy].blocks[cur_block_index]]));
cur_block_index + + ;
}
rec_count_num_iopads_pb ( mapped_block - > pb ) ;
}
}
assert ( cur_block_index = = grid [ ix ] [ iy ] . usage ) ;
return ;
}
/* Initialize the number of configuraion bits for all grids */
void init_grids_num_iopads ( ) {
int ix , iy ;
/* Core grid */
vpr_printf ( TIO_MESSAGE_INFO , " INFO: Initializing number of I/O pads of Core grids... \n " ) ;
for ( ix = 1 ; ix < ( nx + 1 ) ; ix + + ) {
for ( iy = 1 ; iy < ( ny + 1 ) ; iy + + ) {
init_one_grid_num_iopads ( ix , iy ) ;
}
}
/* Consider the IO pads */
vpr_printf ( TIO_MESSAGE_INFO , " INFO: Initializing number of I/O pads of I/O grids... \n " ) ;
/* Left side: x = 0, y = 1 .. ny*/
ix = 0 ;
for ( iy = 1 ; iy < ( ny + 1 ) ; iy + + ) {
/* Ensure this is a io */
assert ( IO_TYPE = = grid [ ix ] [ iy ] . type ) ;
init_one_grid_num_iopads ( ix , iy ) ;
}
/* Right side : x = nx + 1, y = 1 .. ny*/
ix = nx + 1 ;
for ( iy = 1 ; iy < ( ny + 1 ) ; iy + + ) {
/* Ensure this is a io */
assert ( IO_TYPE = = grid [ ix ] [ iy ] . type ) ;
init_one_grid_num_iopads ( ix , iy ) ;
}
/* Bottom side : x = 1 .. nx + 1, y = 0 */
iy = 0 ;
for ( ix = 1 ; ix < ( nx + 1 ) ; ix + + ) {
/* Ensure this is a io */
assert ( IO_TYPE = = grid [ ix ] [ iy ] . type ) ;
init_one_grid_num_iopads ( ix , iy ) ;
}
/* Top side : x = 1 .. nx + 1, y = nx + 1 */
iy = ny + 1 ;
for ( ix = 1 ; ix < ( nx + 1 ) ; ix + + ) {
/* Ensure this is a io */
assert ( IO_TYPE = = grid [ ix ] [ iy ] . type ) ;
init_one_grid_num_iopads ( ix , iy ) ;
}
return ;
}
/* Count the number of mode configuration bits of a grid (type_descriptor) in default mode */
void rec_count_num_mode_bits_pb_type_default_mode ( t_pb_type * cur_pb_type ) {
int mode_index , ipb , jpb ;
int sum_num_mode_bits = 0 ;
cur_pb_type - > default_mode_num_mode_bits = 0 ;
/* Recursively finish all the child pb_types*/
if ( NULL = = cur_pb_type - > spice_model ) {
/* Find the mode that define_idle_mode*/
mode_index = find_pb_type_idle_mode_index ( ( * cur_pb_type ) ) ;
for ( ipb = 0 ; ipb < cur_pb_type - > modes [ mode_index ] . num_pb_type_children ; ipb + + ) {
for ( jpb = 0 ; jpb < cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . num_pb ; jpb + + ) {
rec_count_num_mode_bits_pb_type_default_mode ( & ( cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] ) ) ;
}
}
}
/* Check if this has defined a spice_model*/
if ( NULL ! = cur_pb_type - > spice_model ) {
if ( SPICE_MODEL_IOPAD = = cur_pb_type - > spice_model - > type ) {
sum_num_mode_bits = 1 ;
cur_pb_type - > default_mode_num_mode_bits = sum_num_mode_bits ;
}
} else { /* Count the sum of configuration bits of all the children pb_types */
/* Find the mode that define_idle_mode*/
mode_index = find_pb_type_idle_mode_index ( ( * cur_pb_type ) ) ;
/* Quote all child pb_types */
for ( ipb = 0 ; ipb < cur_pb_type - > modes [ mode_index ] . num_pb_type_children ; ipb + + ) {
/* Each child may exist multiple times in the hierarchy*/
for ( jpb = 0 ; jpb < cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . num_pb ; jpb + + ) {
/* Count in the number of configuration bits of on child pb_type */
sum_num_mode_bits + = cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . default_mode_num_mode_bits ;
}
}
/* Count the number of configuration bits of interconnection */
/* Update the info in pb_type */
cur_pb_type - > default_mode_num_mode_bits = sum_num_mode_bits ;
}
return ;
}
/* Count the number of configuration bits of a pb_graph_node */
void rec_count_num_mode_bits_pb ( t_pb * cur_pb ) {
int mode_index , ipb , jpb ;
t_pb_type * cur_pb_type = NULL ;
t_pb_graph_node * cur_pb_graph_node = NULL ;
int sum_num_mode_bits = 0 ;
/* Check cur_pb_graph_node*/
if ( NULL = = cur_pb ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid cur_pb. \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
cur_pb_graph_node = cur_pb - > pb_graph_node ;
cur_pb_type = cur_pb_graph_node - > pb_type ;
mode_index = cur_pb - > mode ;
cur_pb - > num_mode_bits = 0 ;
/* Recursively finish all the child pb_types*/
if ( NULL = = cur_pb_type - > spice_model ) {
/* recursive for the child_pbs*/
for ( ipb = 0 ; ipb < cur_pb_type - > modes [ mode_index ] . num_pb_type_children ; ipb + + ) {
for ( jpb = 0 ; jpb < cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . num_pb ; jpb + + ) {
/* Recursive*/
/* Refer to pack/output_clustering.c [LINE 392] */
if ( ( NULL ! = cur_pb - > child_pbs [ ipb ] ) & & ( NULL ! = cur_pb - > child_pbs [ ipb ] [ jpb ] . name ) ) {
rec_count_num_mode_bits_pb ( & ( cur_pb - > child_pbs [ ipb ] [ jpb ] ) ) ;
} else {
/* Check if this pb has no children, no children mean idle*/
rec_count_num_mode_bits_pb_type_default_mode ( cur_pb - > child_pbs [ ipb ] [ jpb ] . pb_graph_node - > pb_type ) ;
}
}
}
}
/* Check if this has defined a spice_model*/
if ( NULL ! = cur_pb_type - > spice_model ) {
if ( SPICE_MODEL_IOPAD = = cur_pb_type - > spice_model - > type ) {
sum_num_mode_bits = 1 ;
cur_pb - > num_mode_bits = sum_num_mode_bits ;
}
} else {
/* Definition ends*/
/* Quote all child pb_types */
for ( ipb = 0 ; ipb < cur_pb_type - > modes [ mode_index ] . num_pb_type_children ; ipb + + ) {
/* Each child may exist multiple times in the hierarchy*/
for ( jpb = 0 ; jpb < cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . num_pb ; jpb + + ) {
/* we should make sure this placement index == child_pb_type[jpb]*/
assert ( jpb = = cur_pb_graph_node - > child_pb_graph_nodes [ mode_index ] [ ipb ] [ jpb ] . placement_index ) ;
if ( ( NULL ! = cur_pb - > child_pbs [ ipb ] ) & & ( NULL ! = cur_pb - > child_pbs [ ipb ] [ jpb ] . name ) ) {
/* Count in the number of configuration bits of on child pb */
sum_num_mode_bits + = cur_pb - > child_pbs [ ipb ] [ jpb ] . num_mode_bits ;
} else {
/* Count in the number of configuration bits of on child pb_type */
sum_num_mode_bits + = cur_pb_type - > modes [ mode_index ] . pb_type_children [ ipb ] . default_mode_num_mode_bits ;
}
}
}
/* Count the number of configuration bits of interconnection */
/* Update the info in pb_type */
cur_pb - > num_mode_bits = sum_num_mode_bits ;
}
return ;
}
/* Initialize the number of configuraion bits for one grid */
void init_one_grid_num_mode_bits ( int ix , int iy ) {
t_block * mapped_block = NULL ;
int iz ;
int cur_block_index = 0 ;
int capacity ;
/* Check */
assert ( ( ! ( 0 > ix ) ) & & ( ! ( ix > ( nx + 1 ) ) ) ) ;
assert ( ( ! ( 0 > iy ) ) & & ( ! ( iy > ( ny + 1 ) ) ) ) ;
if ( ( NULL = = grid [ ix ] [ iy ] . type ) | | ( 0 ! = grid [ ix ] [ iy ] . offset ) ) {
/* Empty grid, directly return */
return ;
}
capacity = grid [ ix ] [ iy ] . type - > capacity ;
assert ( 0 < capacity ) ;
/* check capacity and if this has been mapped */
for ( iz = 0 ; iz < capacity ; iz + + ) {
/* Check in all the blocks(clustered logic block), there is a match x,y,z*/
mapped_block = search_mapped_block ( ix , iy , iz ) ;
/* Comments: Grid [x][y]*/
if ( NULL = = mapped_block ) {
/* Print a consider a idle pb_type ...*/
rec_count_num_mode_bits_pb_type_default_mode ( grid [ ix ] [ iy ] . type - > pb_type ) ;
} else {
if ( iz = = mapped_block - > z ) {
// assert(mapped_block == &(block[grid[ix][iy].blocks[cur_block_index]]));
cur_block_index + + ;
}
rec_count_num_mode_bits_pb ( mapped_block - > pb ) ;
}
}
assert ( cur_block_index = = grid [ ix ] [ iy ] . usage ) ;
return ;
}
/* Initialize the number of configuraion bits for all grids */
void init_grids_num_mode_bits ( ) {
int ix , iy ;
/* Core grid */
vpr_printf ( TIO_MESSAGE_INFO , " INFO: Initializing number of mode configuraiton bits of Core grids... \n " ) ;
for ( ix = 1 ; ix < ( nx + 1 ) ; ix + + ) {
for ( iy = 1 ; iy < ( ny + 1 ) ; iy + + ) {
init_one_grid_num_mode_bits ( ix , iy ) ;
}
}
/* Consider the IO pads */
vpr_printf ( TIO_MESSAGE_INFO , " INFO: Initializing number of mode configuration bits of I/O grids... \n " ) ;
/* Left side: x = 0, y = 1 .. ny*/
ix = 0 ;
for ( iy = 1 ; iy < ( ny + 1 ) ; iy + + ) {
/* Ensure this is a io */
assert ( IO_TYPE = = grid [ ix ] [ iy ] . type ) ;
init_one_grid_num_mode_bits ( ix , iy ) ;
}
/* Right side : x = nx + 1, y = 1 .. ny*/
ix = nx + 1 ;
for ( iy = 1 ; iy < ( ny + 1 ) ; iy + + ) {
/* Ensure this is a io */
assert ( IO_TYPE = = grid [ ix ] [ iy ] . type ) ;
init_one_grid_num_mode_bits ( ix , iy ) ;
}
/* Bottom side : x = 1 .. nx + 1, y = 0 */
iy = 0 ;
for ( ix = 1 ; ix < ( nx + 1 ) ; ix + + ) {
/* Ensure this is a io */
assert ( IO_TYPE = = grid [ ix ] [ iy ] . type ) ;
init_one_grid_num_mode_bits ( ix , iy ) ;
}
/* Top side : x = 1 .. nx + 1, y = nx + 1 */
iy = ny + 1 ;
for ( ix = 1 ; ix < ( nx + 1 ) ; ix + + ) {
/* Ensure this is a io */
assert ( IO_TYPE = = grid [ ix ] [ iy ] . type ) ;
init_one_grid_num_mode_bits ( ix , iy ) ;
}
return ;
}
/* Check if this SPICE model defined as SRAM
* contain necessary ports for its functionality
*/
void check_sram_spice_model_ports ( t_spice_model * cur_spice_model ,
boolean include_bl_wl ) {
int num_input_ports ;
t_spice_model_port * * input_ports = NULL ;
int num_output_ports ;
t_spice_model_port * * output_ports = NULL ;
int num_bl_ports ;
t_spice_model_port * * bl_ports = NULL ;
int num_wl_ports ;
t_spice_model_port * * wl_ports = NULL ;
int iport ;
int num_global_ports = 0 ;
int num_err = 0 ;
/* Check the type of SPICE model */
assert ( SPICE_MODEL_SRAM = = cur_spice_model - > type ) ;
/* Check if we has 1 input other than global ports */
input_ports = find_spice_model_ports ( cur_spice_model , SPICE_MODEL_PORT_INPUT , & num_input_ports , TRUE ) ;
num_global_ports = 0 ;
for ( iport = 0 ; iport < num_input_ports ; iport + + ) {
if ( TRUE = = input_ports [ iport ] - > is_global ) {
num_global_ports + + ;
}
}
if ( 1 ! = ( num_input_ports - num_global_ports ) ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d]) SRAM SPICE MODEL should have only 1 non-global input port! \n " ,
__FILE__ , __LINE__ ) ;
num_err + + ;
if ( 1 ! = input_ports [ 0 ] - > size ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d]) SRAM SPICE MODEL should have an input port with size 1! \n " ,
__FILE__ , __LINE__ ) ;
num_err + + ;
}
}
/* Check if we has 1 output with size 2 */
output_ports = find_spice_model_ports ( cur_spice_model , SPICE_MODEL_PORT_OUTPUT , & num_output_ports , TRUE ) ;
num_global_ports = 0 ;
for ( iport = 0 ; iport < num_output_ports ; iport + + ) {
if ( TRUE = = output_ports [ iport ] - > is_global ) {
num_global_ports + + ;
}
}
if ( 1 ! = ( num_output_ports - num_global_ports ) ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d]) SRAM SPICE MODEL should have only 1 non-global output port! \n " ,
__FILE__ , __LINE__ ) ;
num_err + + ;
if ( 2 ! = output_ports [ 0 ] - > size ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d]) SRAM SPICE MODEL should have a output port with size 2! \n " ,
__FILE__ , __LINE__ ) ;
num_err + + ;
}
}
if ( FALSE = = include_bl_wl ) {
if ( 0 = = num_err ) {
return ;
} else {
exit ( 1 ) ;
}
}
/* If bl and wl are required, check their existence */
bl_ports = find_spice_model_ports ( cur_spice_model , SPICE_MODEL_PORT_BL , & num_bl_ports , TRUE ) ;
if ( 1 ! = num_bl_ports ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d]) SRAM SPICE MODEL with BL and WL should have only 1 BL port! \n " ,
__FILE__ , __LINE__ ) ;
num_err + + ;
exit ( 1 ) ;
if ( 1 ! = bl_ports [ 0 ] - > size ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d]) SRAM SPICE MODEL should have a BL port with size 1! \n " ,
__FILE__ , __LINE__ ) ;
num_err + + ;
}
}
wl_ports = find_spice_model_ports ( cur_spice_model , SPICE_MODEL_PORT_WL , & num_wl_ports , TRUE ) ;
if ( 1 ! = num_wl_ports ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d]) SRAM SPICE MODEL with WL and WL should have only 1 WL port! \n " ,
__FILE__ , __LINE__ ) ;
num_err + + ;
exit ( 1 ) ;
if ( 1 ! = wl_ports [ 0 ] - > size ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d]) SRAM SPICE MODEL should have a WL port with size 1! \n " ,
__FILE__ , __LINE__ ) ;
num_err + + ;
}
}
if ( 0 < num_err ) {
exit ( 1 ) ;
}
/* Free */
my_free ( input_ports ) ;
my_free ( output_ports ) ;
my_free ( bl_ports ) ;
my_free ( wl_ports ) ;
return ;
}
void check_ff_spice_model_ports ( t_spice_model * cur_spice_model ,
boolean is_scff ) {
int iport ;
int num_input_ports ;
t_spice_model_port * * input_ports = NULL ;
int num_output_ports ;
t_spice_model_port * * output_ports = NULL ;
int num_clock_ports ;
t_spice_model_port * * clock_ports = NULL ;
int num_err = 0 ;
/* Check the type of SPICE model */
if ( FALSE = = is_scff ) {
assert ( SPICE_MODEL_FF = = cur_spice_model - > type ) ;
} else {
assert ( SPICE_MODEL_SCFF = = cur_spice_model - > type ) ;
}
/* Check if we have D, Set and Reset */
input_ports = find_spice_model_ports ( cur_spice_model , SPICE_MODEL_PORT_INPUT , & num_input_ports , FALSE ) ;
if ( TRUE = = is_scff ) {
if ( 1 > num_input_ports ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d]) SCFF SPICE MODEL should at least have an input port! \n " ,
__FILE__ , __LINE__ ) ;
num_err + + ;
}
for ( iport = 0 ; iport < num_input_ports ; iport + + ) {
if ( 1 ! = input_ports [ iport ] - > size ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d]) SCFF SPICE MODEL: each input port with size 1! \n " ,
__FILE__ , __LINE__ ) ;
num_err + + ;
}
}
} else {
if ( 3 ! = num_input_ports ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d]) FF SPICE MODEL should have only 3 input port! \n " ,
__FILE__ , __LINE__ ) ;
num_err + + ;
}
for ( iport = 0 ; iport < num_input_ports ; iport + + ) {
if ( 1 ! = input_ports [ iport ] - > size ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d]) FF SPICE MODEL: each input port with size 1! \n " ,
__FILE__ , __LINE__ ) ;
num_err + + ;
}
}
}
/* Check if we have clock */
clock_ports = find_spice_model_ports ( cur_spice_model , SPICE_MODEL_PORT_CLOCK , & num_clock_ports , FALSE ) ;
if ( 1 > num_clock_ports ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d]) [FF|SCFF] SPICE MODEL should have at least 1 clock port! \n " ,
__FILE__ , __LINE__ ) ;
num_err + + ;
}
for ( iport = 0 ; iport < num_clock_ports ; iport + + ) {
if ( 1 ! = clock_ports [ iport ] - > size ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d]) [FF|SCFF] SPICE MODEL: 1 clock port with size 1! \n " ,
__FILE__ , __LINE__ ) ;
num_err + + ;
}
}
/* Check if we have output */
output_ports = find_spice_model_ports ( cur_spice_model , SPICE_MODEL_PORT_OUTPUT , & num_output_ports , TRUE ) ;
if ( FALSE = = is_scff ) {
if ( 1 ! = output_ports [ 0 ] - > size ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d]) FF SPICE MODEL: each output port with size 1! \n " ,
__FILE__ , __LINE__ ) ;
num_err + + ;
}
} else {
if ( 1 ! = num_output_ports ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d]) SCFF SPICE MODEL should have only 1 output port! \n " ,
__FILE__ , __LINE__ ) ;
num_err + + ;
if ( 2 ! = output_ports [ 0 ] - > size ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d]) SCFF SPICE MODEL: the output port with size 2! \n " ,
__FILE__ , __LINE__ ) ;
num_err + + ;
}
}
}
/* Error out if required */
if ( 0 < num_err ) {
exit ( 1 ) ;
}
/* Free */
my_free ( input_ports ) ;
my_free ( output_ports ) ;
my_free ( clock_ports ) ;
return ;
}
/* Free a conf_bit_info */
void free_conf_bit ( t_conf_bit * conf_bit ) {
return ;
}
void free_conf_bit_info ( t_conf_bit_info * conf_bit_info ) {
free_conf_bit ( conf_bit_info - > sram_bit ) ;
my_free ( conf_bit_info - > sram_bit ) ;
free_conf_bit ( conf_bit_info - > bl ) ;
my_free ( conf_bit_info - > bl ) ;
free_conf_bit ( conf_bit_info - > wl ) ;
my_free ( conf_bit_info - > wl ) ;
return ;
}
/* Fill the information into a confbit_info */
t_conf_bit_info *
alloc_one_conf_bit_info ( int index ,
t_conf_bit * sram_val ,
t_conf_bit * bl_val , t_conf_bit * wl_val ,
t_spice_model * parent_spice_model ) {
t_conf_bit_info * new_conf_bit_info = ( t_conf_bit_info * ) my_malloc ( sizeof ( t_conf_bit_info ) ) ;
/* Check if we have a valid conf_bit_info */
if ( NULL = = new_conf_bit_info ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Fail to malloc a new conf_bit_info! \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
/* Fill the information */
new_conf_bit_info - > index = index ;
new_conf_bit_info - > sram_bit = sram_val ;
new_conf_bit_info - > bl = bl_val ;
new_conf_bit_info - > wl = wl_val ;
new_conf_bit_info - > parent_spice_model = parent_spice_model ;
new_conf_bit_info - > parent_spice_model_index = parent_spice_model - > cnt ;
return new_conf_bit_info ;
}
/* Add an element to linked-list */
t_llist *
add_conf_bit_info_to_llist ( t_llist * head , int index ,
t_conf_bit * sram_val , t_conf_bit * bl_val , t_conf_bit * wl_val ,
t_spice_model * parent_spice_model ) {
t_llist * temp = NULL ;
t_conf_bit_info * new_conf_bit_info = NULL ;
/* if head is NULL, we create a head */
if ( NULL = = head ) {
temp = create_llist ( 1 ) ;
new_conf_bit_info = alloc_one_conf_bit_info ( index , sram_val , bl_val , wl_val , parent_spice_model ) ;
assert ( NULL ! = new_conf_bit_info ) ;
temp - > dptr = ( void * ) new_conf_bit_info ;
assert ( NULL = = temp - > next ) ;
return temp ;
} else {
/* If head is a valid pointer, we add a new element to the tail of this linked-list */
temp = insert_llist_node_before_head ( head ) ;
new_conf_bit_info = alloc_one_conf_bit_info ( index , sram_val , bl_val , wl_val , parent_spice_model ) ;
assert ( NULL ! = new_conf_bit_info ) ;
temp - > dptr = ( void * ) new_conf_bit_info ;
return temp ;
}
}
/* add configuration bits of a MUX to linked-list
* when SRAM organization type is scan - chain */
void
add_mux_scff_conf_bits_to_llist ( int mux_size ,
t_sram_orgz_info * cur_sram_orgz_info ,
int num_mux_sram_bits , int * mux_sram_bits ,
t_spice_model * mux_spice_model ) {
int ibit , cur_mem_bit ;
t_conf_bit * * sram_bit = NULL ;
/* Assert*/
assert ( NULL ! = cur_sram_orgz_info ) ;
assert ( NULL ! = mux_spice_model ) ;
cur_mem_bit = get_sram_orgz_info_num_mem_bit ( cur_sram_orgz_info ) ;
/* Depend on the design technology of mux_spice_model
* Fill the conf_bits information */
switch ( mux_spice_model - > design_tech ) {
case SPICE_MODEL_DESIGN_CMOS :
case SPICE_MODEL_DESIGN_RRAM :
/* Count how many configuration bits need to program
* Scan - chain needs to know each memory bit whatever it is 0 or 1
*/
/* Allocate the array */
sram_bit = ( t_conf_bit * * ) my_malloc ( num_mux_sram_bits * sizeof ( t_conf_bit * ) ) ;
for ( ibit = 0 ; ibit < num_mux_sram_bits ; ibit + + ) {
sram_bit [ ibit ] = ( t_conf_bit * ) my_malloc ( sizeof ( t_conf_bit ) ) ;
}
/* Fill the array: sram_bit */
for ( ibit = 0 ; ibit < num_mux_sram_bits ; ibit + + ) {
sram_bit [ ibit ] - > addr = cur_mem_bit + ibit ;
sram_bit [ ibit ] - > val = mux_sram_bits [ ibit ] ;
}
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid design technology! " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
/* Fill the linked list */
for ( ibit = 0 ; ibit < num_mux_sram_bits ; ibit + + ) {
cur_sram_orgz_info - > conf_bit_head =
add_conf_bit_info_to_llist ( cur_sram_orgz_info - > conf_bit_head , cur_mem_bit + ibit ,
sram_bit [ ibit ] , NULL , NULL ,
mux_spice_model ) ;
}
/* Free */
my_free ( sram_bit ) ;
return ;
}
/* add configuration bits of a MUX to linked-list
* when SRAM organization type is scan - chain */
void
add_mux_membank_conf_bits_to_llist ( int mux_size ,
t_sram_orgz_info * cur_sram_orgz_info ,
int num_mux_sram_bits , int * mux_sram_bits ,
t_spice_model * mux_spice_model ) {
int ibit , cur_mem_bit , num_conf_bits , cur_bit , cur_bl , cur_wl ;
int ilevel ;
int num_bl_enabled , num_wl_enabled ;
t_conf_bit * * sram_bit = NULL ;
t_conf_bit * * wl_bit = NULL ;
t_conf_bit * * bl_bit = NULL ;
/* Assert*/
assert ( NULL ! = cur_sram_orgz_info ) ;
assert ( NULL ! = mux_spice_model ) ;
cur_mem_bit = get_sram_orgz_info_num_mem_bit ( cur_sram_orgz_info ) ;
get_sram_orgz_info_num_blwl ( cur_sram_orgz_info , & cur_bl , & cur_wl ) ;
/* Depend on the design technology of mux_spice_model
* Fill the conf_bits information */
switch ( mux_spice_model - > design_tech ) {
case SPICE_MODEL_DESIGN_CMOS :
/* Count how many configuration bits need to program
* Assume all the SRAMs are zero initially .
* only Configuration to bit 1 requires a programming operation
*/
num_conf_bits = num_mux_sram_bits ;
/* Allocate the array */
bl_bit = ( t_conf_bit * * ) my_malloc ( num_mux_sram_bits * sizeof ( t_conf_bit * ) ) ;
wl_bit = ( t_conf_bit * * ) my_malloc ( num_mux_sram_bits * sizeof ( t_conf_bit * ) ) ;
for ( ibit = 0 ; ibit < num_mux_sram_bits ; ibit + + ) {
bl_bit [ ibit ] = ( t_conf_bit * ) my_malloc ( sizeof ( t_conf_bit ) ) ;
wl_bit [ ibit ] = ( t_conf_bit * ) my_malloc ( sizeof ( t_conf_bit ) ) ;
}
/* SRAMs are typically organized in an array where BLs and WLs are efficiently shared
* Actual BL / WL address in the array is hard to predict here ,
* they will be handled in the top_netlist and top_testbench generation
*/
for ( ibit = 0 ; ibit < num_mux_sram_bits ; ibit + + ) {
bl_bit [ ibit ] - > addr = cur_mem_bit + ibit ;
bl_bit [ ibit ] - > val = mux_sram_bits [ ibit ] ;
wl_bit [ ibit ] - > addr = cur_mem_bit + ibit ;
wl_bit [ ibit ] - > val = 1 ; /* We always assume WL is the write enable signal of a SRAM */
}
break ;
case SPICE_MODEL_DESIGN_RRAM :
/* Count how many configuration bits need to program
* only BL and WL are both 1 requires a programming operation
* Each level of a MUX requires 1 RRAM to be configured .
* Therefore , the number of configuration bits should be num_mux_levels
*/
num_bl_enabled = 0 ;
/* Check how many Bit lines are 1 */
for ( ibit = 0 ; ibit < num_mux_sram_bits / 2 ; ibit + + ) {
if ( 1 = = mux_sram_bits [ ibit ] ) {
num_bl_enabled + + ;
}
}
num_wl_enabled = 0 ;
/* Check how many Word lines are 1 */
for ( ibit = 0 ; ibit < num_mux_sram_bits / 2 ; ibit + + ) {
if ( 1 = = mux_sram_bits [ ibit + num_mux_sram_bits / 2 ] ) {
num_wl_enabled + + ;
}
}
/* The number of enabled Bit and Word lines should be the same */
assert ( num_bl_enabled = = num_wl_enabled ) ;
/* Assign num_conf_bits */
num_conf_bits = num_bl_enabled ;
/* Allocate the array */
bl_bit = ( t_conf_bit * * ) my_malloc ( num_conf_bits * sizeof ( t_conf_bit * ) ) ;
wl_bit = ( t_conf_bit * * ) my_malloc ( num_conf_bits * sizeof ( t_conf_bit * ) ) ;
for ( ibit = 0 ; ibit < num_conf_bits ; ibit + + ) {
bl_bit [ ibit ] = ( t_conf_bit * ) my_malloc ( sizeof ( t_conf_bit ) ) ;
wl_bit [ ibit ] = ( t_conf_bit * ) my_malloc ( sizeof ( t_conf_bit ) ) ;
}
/* For one-level RRAM MUX:
* There should be only 1 BL and 1 WL whose value is 1
* First half of mux_sram_bits are BL , the rest are WL
* For multi - level RRAM MUX :
* There could be more than 1 BL and 1 WL whose value is 1
* We need to divde the mux_sram_bits into small part ,
* each part has only 1 BL and 1 WL whose value is 1
*/
/* Assign bit lines address and values */
cur_bit = 0 ;
/* We slice the BL part of array mux_sram_bits to N=num_conf_bits parts */
for ( ilevel = 0 ; ilevel < num_conf_bits ; ilevel + + ) {
for ( ibit = ilevel * num_mux_sram_bits / ( 2 * num_conf_bits ) ; /* Start address of each slice*/
ibit < ( ilevel + 1 ) * num_mux_sram_bits / ( 2 * num_conf_bits ) ; /* End address of each slice*/
ibit + + ) {
if ( 0 = = mux_sram_bits [ ibit ] ) {
continue ; /* Skip non-zero bits */
}
assert ( 1 = = mux_sram_bits [ ibit ] ) ;
if ( ibit = = ( ilevel + 1 ) * num_mux_sram_bits / ( 2 * num_conf_bits ) - 1 ) {
bl_bit [ cur_bit ] - > addr = cur_bl + ilevel ;
/* Last conf_bit should use a new BL/WL */
} else {
/* First part of conf_bit should use reserved BL/WL */
bl_bit [ cur_bit ] - > addr = ibit ;
}
bl_bit [ cur_bit ] - > val = mux_sram_bits [ ibit ] ;
cur_bit + + ;
}
}
assert ( num_conf_bits = = cur_bit ) ;
/* Assign Word lines address and values */
cur_bit = 0 ;
for ( ilevel = 0 ; ilevel < num_conf_bits ; ilevel + + ) {
for ( ibit = num_mux_sram_bits / 2 + ilevel * num_mux_sram_bits / ( 2 * num_conf_bits ) ; /* Start address of each slice*/
ibit < num_mux_sram_bits / 2 + ( ilevel + 1 ) * num_mux_sram_bits / ( 2 * num_conf_bits ) ; /* End address of each slice*/
ibit + + ) {
if ( 0 = = mux_sram_bits [ ibit ] ) {
continue ; /* Skip non-zero bits */
}
assert ( 1 = = mux_sram_bits [ ibit ] ) ;
if ( ibit = = num_mux_sram_bits / 2 + ( ilevel + 1 ) * num_mux_sram_bits / ( 2 * num_conf_bits ) - 1 ) {
wl_bit [ cur_bit ] - > addr = cur_wl + ilevel ;
/* Last conf_bit should use a new BL/WL */
} else {
/* First part of conf_bit should use reserved BL/WL */
wl_bit [ cur_bit ] - > addr = ibit ;
}
wl_bit [ cur_bit ] - > val = mux_sram_bits [ ibit ] ;
cur_bit + + ;
}
}
assert ( num_conf_bits = = cur_bit ) ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid design technology! " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
/* Fill the linked list */
for ( ibit = 0 ; ibit < num_conf_bits ; ibit + + ) {
cur_sram_orgz_info - > conf_bit_head =
add_conf_bit_info_to_llist ( cur_sram_orgz_info - > conf_bit_head , cur_mem_bit + ibit ,
NULL , bl_bit [ ibit ] , wl_bit [ ibit ] ,
mux_spice_model ) ;
}
/* Free */
my_free ( sram_bit ) ;
my_free ( bl_bit ) ;
my_free ( wl_bit ) ;
return ;
}
/* Should we return a value ? */
void
add_mux_conf_bits_to_llist ( int mux_size ,
t_sram_orgz_info * cur_sram_orgz_info ,
int num_mux_sram_bits , int * mux_sram_bits ,
t_spice_model * mux_spice_model ) {
/* According to the type, we allocate structs */
switch ( cur_sram_orgz_info - > type ) {
case SPICE_SRAM_STANDALONE :
case SPICE_SRAM_SCAN_CHAIN :
add_mux_scff_conf_bits_to_llist ( mux_size , cur_sram_orgz_info ,
num_mux_sram_bits , mux_sram_bits ,
mux_spice_model ) ;
break ;
case SPICE_SRAM_MEMORY_BANK :
add_mux_membank_conf_bits_to_llist ( mux_size , cur_sram_orgz_info ,
num_mux_sram_bits , mux_sram_bits ,
mux_spice_model ) ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid type of SRAM organization! " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
return ;
}
/* Add SCFF configutration bits to a linked list*/
void
add_sram_scff_conf_bits_to_llist ( t_sram_orgz_info * cur_sram_orgz_info ,
int num_sram_bits , int * sram_bits ) {
int ibit , cur_mem_bit ;
t_conf_bit * * sram_bit = NULL ;
t_spice_model * cur_sram_spice_model = NULL ;
/* Assert*/
assert ( NULL ! = cur_sram_orgz_info ) ;
cur_mem_bit = get_sram_orgz_info_num_mem_bit ( cur_sram_orgz_info ) ;
/* Get memory model */
get_sram_orgz_info_mem_model ( cur_sram_orgz_info , & cur_sram_spice_model ) ;
assert ( NULL ! = cur_sram_spice_model ) ;
/* Count how many configuration bits need to program
* Scan - chain needs to know each memory bit whatever it is 0 or 1
*/
/* Allocate the array */
sram_bit = ( t_conf_bit * * ) my_malloc ( num_sram_bits * sizeof ( t_conf_bit * ) ) ;
for ( ibit = 0 ; ibit < num_sram_bits ; ibit + + ) {
sram_bit [ ibit ] = ( t_conf_bit * ) my_malloc ( sizeof ( t_conf_bit ) ) ;
}
/* Fill the array: sram_bit */
for ( ibit = 0 ; ibit < num_sram_bits ; ibit + + ) {
sram_bit [ ibit ] - > addr = cur_mem_bit + ibit ;
sram_bit [ ibit ] - > val = sram_bits [ ibit ] ;
}
/* Fill the linked list */
for ( ibit = 0 ; ibit < num_sram_bits ; ibit + + ) {
cur_sram_orgz_info - > conf_bit_head =
add_conf_bit_info_to_llist ( cur_sram_orgz_info - > conf_bit_head , cur_mem_bit + ibit ,
sram_bit [ ibit ] , NULL , NULL ,
cur_sram_spice_model ) ;
}
/* Free */
my_free ( sram_bit ) ;
return ;
}
/* Add SRAM configuration bits in memory bank organization to a linked list */
void add_sram_membank_conf_bits_to_llist ( t_sram_orgz_info * cur_sram_orgz_info , int mem_index ,
int num_bls , int num_wls ,
int * bl_conf_bits , int * wl_conf_bits ) {
int ibit , cur_bl , cur_wl , cur_mem_bit ;
t_spice_model * cur_sram_spice_model = NULL ;
t_conf_bit * bl_bit = NULL ;
t_conf_bit * wl_bit = NULL ;
int bit_cnt = 0 ;
/* Assert*/
assert ( NULL ! = cur_sram_orgz_info ) ;
/* Get current counter of sram_spice_model */
cur_mem_bit = get_sram_orgz_info_num_mem_bit ( cur_sram_orgz_info ) ;
get_sram_orgz_info_num_blwl ( cur_sram_orgz_info , & cur_bl , & cur_wl ) ;
/* Get memory model */
get_sram_orgz_info_mem_model ( cur_sram_orgz_info , & cur_sram_spice_model ) ;
assert ( NULL ! = cur_sram_spice_model ) ;
/* Malloc */
bl_bit = ( t_conf_bit * ) my_malloc ( sizeof ( t_conf_bit ) ) ;
wl_bit = ( t_conf_bit * ) my_malloc ( sizeof ( t_conf_bit ) ) ;
/* Depend on the memory technology, we have different configuration bits */
switch ( cur_sram_spice_model - > design_tech ) {
case SPICE_MODEL_DESIGN_CMOS :
assert ( ( 1 = = num_bls ) & & ( 1 = = num_wls ) ) ;
bl_bit - > addr = mem_index ;
wl_bit - > addr = mem_index ;
bl_bit - > val = bl_conf_bits [ 0 ] ;
wl_bit - > val = wl_conf_bits [ 0 ] ;
break ;
case SPICE_MODEL_DESIGN_RRAM :
/* Fill information */
bit_cnt = 0 ; /* Check counter */
for ( ibit = 0 ; ibit < num_bls ; ibit + + ) {
/* Bypass zero bit */
if ( 0 = = bl_conf_bits [ ibit ] ) {
continue ;
}
/* Check if this bit is in reserved bls */
if ( ibit = = num_bls - 1 ) {
/* Last bit is always independent */
bl_bit - > addr = mem_index ;
bl_bit - > val = 1 ;
} else {
/* Other bits are shared */
bl_bit - > addr = ibit ;
bl_bit - > val = 1 ;
}
/* Update check counter */
bit_cnt + + ;
}
/* Check */
assert ( 1 = = bit_cnt ) ;
bit_cnt = 0 ; /* Check counter */
for ( ibit = 0 ; ibit < num_wls ; ibit + + ) {
/* Bypass zero bit */
if ( 0 = = wl_conf_bits [ ibit ] ) {
continue ;
}
/* Check if this bit is in reserved bls */
if ( ibit = = num_wls - 1 ) {
/* Last bit is always independent */
wl_bit - > addr = mem_index ;
wl_bit - > val = 1 ;
} else {
/* Other bits are shared */
wl_bit - > addr = ibit ;
wl_bit - > val = 1 ;
}
/* Update check counter */
bit_cnt + + ;
}
/* Check */
assert ( 1 = = bit_cnt ) ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid design technology! " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
/* Fill the linked list */
cur_sram_orgz_info - > conf_bit_head =
add_conf_bit_info_to_llist ( cur_sram_orgz_info - > conf_bit_head , mem_index ,
NULL , bl_bit , wl_bit ,
cur_sram_spice_model ) ;
return ;
}
/* Add SRAM configuration bits to a linked list */
void
add_sram_conf_bits_to_llist ( t_sram_orgz_info * cur_sram_orgz_info , int mem_index ,
int num_sram_bits , int * sram_bits ) {
int num_bls , num_wls ;
int * bl_conf_bits = NULL ;
int * wl_conf_bits = NULL ;
/* According to the type, we allocate structs */
switch ( cur_sram_orgz_info - > type ) {
case SPICE_SRAM_STANDALONE :
case SPICE_SRAM_SCAN_CHAIN :
add_sram_scff_conf_bits_to_llist ( cur_sram_orgz_info ,
num_sram_bits , sram_bits ) ;
break ;
case SPICE_SRAM_MEMORY_BANK :
/* Initialize parameters */
/* Number of BLs should be same as WLs */
num_bls = num_sram_bits / 2 ;
num_wls = num_sram_bits / 2 ;
/* Convention: first part of Array (sram_bits) is BL configuration bits,
* second part is WL configuration bits .
*/
bl_conf_bits = sram_bits ;
wl_conf_bits = sram_bits + num_bls ;
add_sram_membank_conf_bits_to_llist ( cur_sram_orgz_info , mem_index ,
num_bls , num_wls ,
bl_conf_bits , wl_conf_bits ) ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid type of SRAM organization! " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
return ;
}
/* Find BL and WL ports for a SRAM model.
* And check if the number of BL / WL satisfy the technology needs
*/
void find_bl_wl_ports_spice_model ( t_spice_model * cur_spice_model ,
int * num_bl_ports , t_spice_model_port * * * bl_ports ,
int * num_wl_ports , t_spice_model_port * * * wl_ports ) {
int i ;
/* Check */
assert ( NULL ! = cur_spice_model ) ;
/* Find BL ports */
( * bl_ports ) = find_spice_model_ports ( cur_spice_model , SPICE_MODEL_PORT_BL , num_bl_ports , TRUE ) ;
/* Find WL ports */
( * wl_ports ) = find_spice_model_ports ( cur_spice_model , SPICE_MODEL_PORT_WL , num_wl_ports , TRUE ) ;
/* port size of BL/WL should be at least 1 !*/
assert ( ( * num_bl_ports ) = = ( * num_wl_ports ) ) ;
/* Check the size of BL/WL ports */
switch ( cur_spice_model - > design_tech ) {
case SPICE_MODEL_DESIGN_RRAM :
/* This check may be too tight */
for ( i = 0 ; i < ( * num_bl_ports ) ; i + + ) {
assert ( 0 < ( * bl_ports ) [ i ] - > size ) ;
}
for ( i = 0 ; i < ( * num_wl_ports ) ; i + + ) {
assert ( 0 < ( * wl_ports ) [ i ] - > size ) ;
}
break ;
case SPICE_MODEL_DESIGN_CMOS :
for ( i = 0 ; i < ( * num_bl_ports ) ; i + + ) {
assert ( 0 < ( * bl_ports ) [ i ] - > size ) ;
}
for ( i = 0 ; i < ( * num_wl_ports ) ; i + + ) {
assert ( 0 < ( * wl_ports ) [ i ] - > size ) ;
}
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (FILE:%s,LINE[%d])Invalid design_technology of MUX(name: %s) \n " ,
__FILE__ , __LINE__ , cur_spice_model - > name ) ;
exit ( 1 ) ;
}
return ;
}
/* Find BL and WL ports for a SRAM model.
* And check if the number of BL / WL satisfy the technology needs
*/
void find_blb_wlb_ports_spice_model ( t_spice_model * cur_spice_model ,
int * num_blb_ports , t_spice_model_port * * * blb_ports ,
int * num_wlb_ports , t_spice_model_port * * * wlb_ports ) {
int i ;
/* Check */
assert ( NULL ! = cur_spice_model ) ;
/* Find BL ports */
( * blb_ports ) = find_spice_model_ports ( cur_spice_model , SPICE_MODEL_PORT_BLB , num_blb_ports , TRUE ) ;
/* Find WL ports */
( * wlb_ports ) = find_spice_model_ports ( cur_spice_model , SPICE_MODEL_PORT_WLB , num_wlb_ports , TRUE ) ;
return ;
}
/* Decode mode bits "01..." to a SRAM bits array */
int * decode_mode_bits ( char * mode_bits , int * num_sram_bits ) {
int * sram_bits = NULL ;
int i ;
assert ( NULL ! = mode_bits ) ;
( * num_sram_bits ) = strlen ( mode_bits ) ;
sram_bits = ( int * ) my_calloc ( ( * num_sram_bits ) , sizeof ( int ) ) ;
for ( i = 0 ; i < ( * num_sram_bits ) ; i + + ) {
switch ( mode_bits [ i ] ) {
case ' 1 ' :
sram_bits [ i ] = 1 ;
break ;
case ' 0 ' :
sram_bits [ i ] = 0 ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid mode_bits(%s)! \n " ,
__FILE__ , __LINE__ , mode_bits ) ;
exit ( 1 ) ;
}
}
return sram_bits ;
}
/* For LUTs without SPICE netlist defined, we can create a SPICE netlist
* In this case , we need a MUX
*/
void stats_lut_spice_mux ( t_llist * * muxes_head ,
t_spice_model * spice_model ) {
int lut_mux_size = 0 ;
int num_input_port = 0 ;
t_spice_model_port * * input_ports = NULL ;
if ( NULL = = spice_model ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid Spice_model pointer! \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
/* Check */
assert ( SPICE_MODEL_LUT = = spice_model - > type ) ;
/* Get input ports */
input_ports = find_spice_model_ports ( spice_model , SPICE_MODEL_PORT_INPUT , & num_input_port , TRUE ) ;
assert ( 1 = = num_input_port ) ;
lut_mux_size = ( int ) pow ( 2. , ( double ) ( input_ports [ 0 ] - > size ) ) ;
/* MUX size = 2^lut_size */
check_and_add_mux_to_linked_list ( muxes_head , lut_mux_size , spice_model ) ;
return ;
}
char * complete_truth_table_line ( int lut_size ,
char * input_truth_table_line ) {
char * ret = NULL ;
int num_token = 0 ;
char * * tokens = NULL ;
int cover_len = 0 ;
int j ;
/* Due to the size of truth table may be less than the lut size.
* i . e . in LUT - 6 architecture , there exists LUT1 - 6 in technology - mapped netlists
* So , in truth table line , there may be 10 - 1
* In this case , we should complete it by - - 10 - 1
*/
/*Malloc the completed truth table, lut_size + space + truth_val + '\0'*/
ret = ( char * ) my_malloc ( sizeof ( char ) * lut_size + 3 ) ;
/* Split one line of truth table line*/
tokens = my_strtok ( input_truth_table_line , " " , & num_token ) ;
/* Check, only 2 tokens*/
/* Sometimes, the truth table is ' 0' or ' 1', which corresponds to a constant */
if ( 1 = = num_token ) {
/* restore the token[0]*/
tokens = ( char * * ) realloc ( tokens , 2 * sizeof ( char * ) ) ;
tokens [ 1 ] = tokens [ 0 ] ;
tokens [ 0 ] = my_strdup ( " - " ) ;
num_token = 2 ;
}
/* In Most cases, there should be 2 tokens. */
assert ( 2 = = num_token ) ;
if ( ( 0 ! = strcmp ( tokens [ 1 ] , " 1 " ) ) & & ( 0 ! = strcmp ( tokens [ 1 ] , " 0 " ) ) ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s, [LINE%d])Last token of truth table line should be [0|1]! \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
/* Complete the truth table line*/
cover_len = strlen ( tokens [ 0 ] ) ;
assert ( ( cover_len < lut_size ) | | ( cover_len = = lut_size ) ) ;
/* Copy the original truth table line */
for ( j = 0 ; j < cover_len ; j + + ) {
ret [ j ] = tokens [ 0 ] [ j ] ;
}
/* Add the number of '-' we should add in the back !!! */
for ( j = cover_len ; j < lut_size ; j + + ) {
ret [ j ] = ' - ' ;
}
/* Copy the original truth table line */
sprintf ( ret + lut_size , " %s " , tokens [ 1 ] ) ;
/* Free */
for ( j = 0 ; j < num_token ; j + + ) {
my_free ( tokens [ j ] ) ;
}
return ret ;
}
/* For each lut_bit_lines, we should recover the truth table,
* and then set the sram bits to " 1 " if the truth table defines so .
* Start_point : the position we start decode recursively
*/
void configure_lut_sram_bits_per_line_rec ( int * * sram_bits ,
int lut_size ,
char * truth_table_line ,
int start_point ) {
int i ;
int num_sram_bit = ( int ) pow ( 2. , ( double ) ( lut_size ) ) ;
char * temp_line = my_strdup ( truth_table_line ) ;
int do_config = 1 ;
int sram_id = 0 ;
/* Check the length of sram bits and truth table line */
//assert((sizeof(int)*num_sram_bit) == sizeof(*sram_bits)); /*TODO: fix this assert*/
assert ( ( unsigned ) ( lut_size + 1 + 1 ) = = strlen ( truth_table_line ) ) ; /* lut_size + space + '1' */
/* End of truth_table_line should be "space" and "1" */
assert ( ( 0 = = strcmp ( " 1 " , truth_table_line + lut_size ) ) | | ( 0 = = strcmp ( " 0 " , truth_table_line + lut_size ) ) ) ;
/* Make sure before start point there is no '-' */
for ( i = 0 ; i < start_point ; i + + ) {
assert ( ' - ' ! = truth_table_line [ i ] ) ;
}
/* Configure sram bits recursively */
for ( i = start_point ; i < lut_size ; i + + ) {
if ( ' - ' = = truth_table_line [ i ] ) {
do_config = 0 ;
/* if we find a dont_care, we don't do configure now but recursively*/
/* '0' branch */
temp_line [ i ] = ' 0 ' ;
configure_lut_sram_bits_per_line_rec ( sram_bits , lut_size , temp_line , start_point + 1 ) ;
/* '1' branch */
temp_line [ i ] = ' 1 ' ;
configure_lut_sram_bits_per_line_rec ( sram_bits , lut_size , temp_line , start_point + 1 ) ;
break ;
}
}
/* do_config*/
if ( do_config ) {
for ( i = 0 ; i < lut_size ; i + + ) {
/* Should be either '0' or '1' */
switch ( truth_table_line [ i ] ) {
case ' 0 ' :
/* We assume the 1-lut pass sram1 when input = 0 */
sram_id + = ( int ) pow ( 2. , ( double ) ( i ) ) ;
break ;
case ' 1 ' :
/* We assume the 1-lut pass sram0 when input = 1 */
break ;
case ' - ' :
assert ( ' - ' ! = truth_table_line [ i ] ) ; /* Make sure there is no dont_care */
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s, [LINE%d])Invalid truth_table bit(%c), should be [0|1|'-]! \n " ,
__FILE__ , __LINE__ , truth_table_line [ i ] ) ;
exit ( 1 ) ;
}
}
/* Set the sram bit to '1'*/
assert ( ( - 1 < sram_id ) & & ( sram_id < num_sram_bit ) ) ;
if ( 0 = = strcmp ( " 1 " , truth_table_line + lut_size ) ) {
( * sram_bits ) [ sram_id ] = 1 ; /* on set*/
} else if ( 0 = = strcmp ( " 0 " , truth_table_line + lut_size ) ) {
( * sram_bits ) [ sram_id ] = 0 ; /* off set */
} else {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid truth_table_line ending(=%s)! \n " ,
__FILE__ , __LINE__ , truth_table_line + lut_size ) ;
exit ( 1 ) ;
}
}
/* Free */
my_free ( temp_line ) ;
return ;
}
int * generate_lut_sram_bits ( int truth_table_len ,
char * * truth_table ,
int lut_size ,
int default_sram_bit_value ) {
int num_sram = ( int ) pow ( 2. , ( double ) ( lut_size ) ) ;
int * ret = ( int * ) my_malloc ( sizeof ( int ) * num_sram ) ;
char * * completed_truth_table = ( char * * ) my_malloc ( sizeof ( char * ) * truth_table_len ) ;
int on_set = 0 ;
int off_set = 0 ;
int i ;
/* if No truth_table, do default*/
if ( 0 = = truth_table_len ) {
switch ( default_sram_bit_value ) {
case 0 :
off_set = 0 ;
on_set = 1 ;
break ;
case 1 :
off_set = 1 ;
on_set = 0 ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid default_signal_init_value(=%d)! \n " ,
__FILE__ , __LINE__ , default_sram_bit_value ) ;
exit ( 1 ) ;
}
}
/* Read in truth table lines, decode one by one */
for ( i = 0 ; i < truth_table_len ; i + + ) {
/* Complete the truth table line by line*/
//printf("truth_table[%d] = %s\n", i, truth_table[i]);
completed_truth_table [ i ] = complete_truth_table_line ( lut_size , truth_table [ i ] ) ;
//printf("Completed_truth_table[%d] = %s\n", i, completed_truth_table[i]);
if ( 0 = = strcmp ( " 1 " , completed_truth_table [ i ] + lut_size ) ) {
on_set = 1 ;
} else if ( 0 = = strcmp ( " 0 " , completed_truth_table [ i ] + lut_size ) ) {
off_set = 1 ;
}
}
//printf("on_set=%d off_set=%d", on_set, off_set);
assert ( 1 = = ( on_set + off_set ) ) ;
if ( 1 = = on_set ) {
/* Initial all sram bits to 0*/
for ( i = 0 ; i < num_sram ; i + + ) {
ret [ i ] = 0 ;
}
} else if ( 1 = = off_set ) {
/* Initial all sram bits to 1*/
for ( i = 0 ; i < num_sram ; i + + ) {
ret [ i ] = 1 ;
}
}
for ( i = 0 ; i < truth_table_len ; i + + ) {
/* Update the truth table, sram_bits */
configure_lut_sram_bits_per_line_rec ( & ret , lut_size , completed_truth_table [ i ] , 0 ) ;
}
/* Free */
for ( i = 0 ; i < truth_table_len ; i + + ) {
my_free ( completed_truth_table [ i ] ) ;
}
return ret ;
}
char * * assign_lut_truth_table ( t_logical_block * mapped_logical_block ,
int * truth_table_length ) {
char * * truth_table = NULL ;
t_linked_vptr * head = NULL ;
int cur = 0 ;
if ( NULL = = mapped_logical_block ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid mapped_logical_block! \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
/* Count the lines of truth table*/
head = mapped_logical_block - > truth_table ;
while ( head ) {
( * truth_table_length ) + + ;
head = head - > next ;
}
/* Allocate truth_tables */
truth_table = ( char * * ) my_malloc ( sizeof ( char * ) * ( * truth_table_length ) ) ;
/* Fill truth_tables*/
cur = 0 ;
head = mapped_logical_block - > truth_table ;
while ( head ) {
truth_table [ cur ] = my_strdup ( ( char * ) head - > data_vptr ) ;
head = head - > next ;
cur + + ;
}
assert ( cur = = ( * truth_table_length ) ) ;
return truth_table ;
}
2018-08-10 14:46:00 -05:00
/* Get initial value of a Latch/FF output*/
int get_ff_output_init_val ( t_logical_block * ff_logical_block ) {
assert ( ( 0 = = ff_logical_block - > init_val ) | | ( 1 = = ff_logical_block - > init_val ) ) ;
return ff_logical_block - > init_val ;
}
/* Get initial value of a mapped LUT output*/
2018-07-26 12:28:21 -05:00
int get_lut_output_init_val ( t_logical_block * lut_logical_block ) {
int i ;
int * sram_bits = NULL ; /* decoded SRAM bits */
int truth_table_length = 0 ;
char * * truth_table = NULL ;
int lut_size = 0 ;
int input_net_index = OPEN ;
int * input_init_val = NULL ;
int init_path_id = 0 ;
int output_init_val = 0 ;
t_spice_model * lut_spice_model = NULL ;
int num_sram_port = 0 ;
t_spice_model_port * * sram_ports = NULL ;
/* Ensure a valid file handler*/
if ( NULL = = lut_logical_block ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid LUT logical block! \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
/* Get SPICE model */
assert ( ( NULL ! = lut_logical_block - > pb )
& & ( NULL ! = lut_logical_block - > pb - > pb_graph_node )
& & ( NULL ! = lut_logical_block - > pb - > pb_graph_node - > pb_type ) ) ;
lut_spice_model = lut_logical_block - > pb - > pb_graph_node - > pb_type - > parent_mode - > parent_pb_type - > spice_model ;
2018-08-01 15:04:28 -05:00
2018-07-26 12:28:21 -05:00
assert ( SPICE_MODEL_LUT = = lut_spice_model - > type ) ;
2018-08-01 15:04:28 -05:00
2018-07-26 12:28:21 -05:00
sram_ports = find_spice_model_ports ( lut_spice_model , SPICE_MODEL_PORT_SRAM ,
& num_sram_port , TRUE ) ;
assert ( 1 = = num_sram_port ) ;
/* Get the truth table */
truth_table = assign_lut_truth_table ( lut_logical_block , & truth_table_length ) ;
lut_size = lut_logical_block - > used_input_pins ;
assert ( ! ( 0 > lut_size ) ) ;
/* Special for LUT_size = 0 */
if ( 0 = = lut_size ) {
/* Generate sram bits*/
sram_bits = generate_lut_sram_bits ( truth_table_length , truth_table ,
1 , sram_ports [ 0 ] - > default_val ) ;
/* This is constant generator, SRAM bits should be the same */
output_init_val = sram_bits [ 0 ] ;
for ( i = 0 ; i < ( int ) pow ( 2. , ( double ) lut_size ) ; i + + ) {
assert ( sram_bits [ i ] = = output_init_val ) ;
}
} else {
/* Generate sram bits*/
sram_bits = generate_lut_sram_bits ( truth_table_length , truth_table ,
lut_size , sram_ports [ 0 ] - > default_val ) ;
assert ( 1 = = lut_logical_block - > pb - > pb_graph_node - > num_input_ports ) ;
assert ( 1 = = lut_logical_block - > pb - > pb_graph_node - > num_output_ports ) ;
/* Get the initial path id */
input_init_val = ( int * ) my_malloc ( sizeof ( int ) * lut_size ) ;
for ( i = 0 ; i < lut_size ; i + + ) {
input_net_index = lut_logical_block - > input_nets [ 0 ] [ i ] ;
input_init_val [ i ] = vpack_net [ input_net_index ] . spice_net_info - > init_val ;
}
init_path_id = determine_lut_path_id ( lut_size , input_init_val ) ;
/* Check */
assert ( ( ! ( 0 > init_path_id ) ) & & ( init_path_id < ( int ) pow ( 2. , ( double ) lut_size ) ) ) ;
output_init_val = sram_bits [ init_path_id ] ;
}
/*Free*/
for ( i = 0 ; i < truth_table_length ; i + + ) {
free ( truth_table [ i ] ) ;
}
free ( truth_table ) ;
my_free ( sram_bits ) ;
return output_init_val ;
}
2018-08-01 15:04:28 -05:00
/* Deteremine the initial value of an output of a logical block
* The logical block could be a LUT , a memory block or a multiplier
*/
int get_logical_block_output_init_val ( t_logical_block * cur_logical_block ) {
int output_init_val = 0 ;
t_spice_model * cur_spice_model = NULL ;
/* Get the spice_model of current logical_block */
assert ( ( NULL ! = cur_logical_block - > pb )
& & ( NULL ! = cur_logical_block - > pb - > pb_graph_node )
& & ( NULL ! = cur_logical_block - > pb - > pb_graph_node - > pb_type ) ) ;
cur_spice_model = cur_logical_block - > pb - > pb_graph_node - > pb_type - > parent_mode - > parent_pb_type - > spice_model ;
/* Switch to specific cases*/
switch ( cur_spice_model - > type ) {
case SPICE_MODEL_LUT :
/* Determine the initial value from LUT inputs */
output_init_val = get_lut_output_init_val ( cur_logical_block ) ;
break ;
case SPICE_MODEL_HARDLOGIC :
/* We have no information, give a default 0 now...
* TODO : find a smarter way !
*/
2018-08-10 14:46:00 -05:00
output_init_val = get_ff_output_init_val ( cur_logical_block ) ;
2018-08-01 15:04:28 -05:00
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid type of SPICE MODEL (name=%s) in determining the initial output value of logical block(name=%s)! \n " ,
__FILE__ , __LINE__ , cur_spice_model - > name , cur_logical_block - > name ) ;
exit ( 1 ) ;
}
return output_init_val ;
}
2018-07-26 12:28:21 -05:00
/* Functions to manipulate struct sram_orgz_info */
t_sram_orgz_info * alloc_one_sram_orgz_info ( ) {
return ( t_sram_orgz_info * ) my_malloc ( sizeof ( t_sram_orgz_info ) ) ;
}
t_mem_bank_info * alloc_one_mem_bank_info ( ) {
return ( t_mem_bank_info * ) my_malloc ( sizeof ( t_mem_bank_info ) ) ;
}
void free_one_mem_bank_info ( t_mem_bank_info * mem_bank_info ) {
return ;
}
t_scff_info * alloc_one_scff_info ( ) {
return ( t_scff_info * ) my_malloc ( sizeof ( t_scff_info ) ) ;
}
void free_one_scff_info ( t_scff_info * scff_info ) {
return ;
}
t_standalone_sram_info * alloc_one_standalone_sram_info ( ) {
return ( t_standalone_sram_info * ) my_malloc ( sizeof ( t_standalone_sram_info ) ) ;
}
void free_one_standalone_sram_info ( t_standalone_sram_info * standalone_sram_info ) {
return ;
}
void init_mem_bank_info ( t_mem_bank_info * cur_mem_bank_info ,
t_spice_model * cur_mem_model ) {
assert ( NULL ! = cur_mem_bank_info ) ;
assert ( NULL ! = cur_mem_model ) ;
cur_mem_bank_info - > mem_model = cur_mem_model ;
cur_mem_bank_info - > num_mem_bit = 0 ;
cur_mem_bank_info - > num_bl = 0 ;
cur_mem_bank_info - > num_wl = 0 ;
cur_mem_bank_info - > reserved_bl = 0 ;
cur_mem_bank_info - > reserved_wl = 0 ;
return ;
}
void update_mem_bank_info_num_mem_bit ( t_mem_bank_info * cur_mem_bank_info ,
int num_mem_bit ) {
assert ( NULL ! = cur_mem_bank_info ) ;
cur_mem_bank_info - > num_mem_bit = num_mem_bit ;
return ;
}
void init_scff_info ( t_scff_info * cur_scff_info ,
t_spice_model * cur_mem_model ) {
assert ( NULL ! = cur_scff_info ) ;
assert ( NULL ! = cur_mem_model ) ;
cur_scff_info - > mem_model = cur_mem_model ;
cur_scff_info - > num_mem_bit = 0 ;
cur_scff_info - > num_scff = 0 ;
return ;
}
void update_scff_info_num_mem_bit ( t_scff_info * cur_scff_info ,
int num_mem_bit ) {
assert ( NULL ! = cur_scff_info ) ;
cur_scff_info - > num_mem_bit = num_mem_bit ;
return ;
}
void init_standalone_sram_info ( t_standalone_sram_info * cur_standalone_sram_info ,
t_spice_model * cur_mem_model ) {
assert ( NULL ! = cur_standalone_sram_info ) ;
assert ( NULL ! = cur_mem_model ) ;
cur_standalone_sram_info - > mem_model = cur_mem_model ;
cur_standalone_sram_info - > num_mem_bit = 0 ;
cur_standalone_sram_info - > num_sram = 0 ;
return ;
}
void update_standalone_sram_info_num_mem_bit ( t_standalone_sram_info * cur_standalone_sram_info ,
int num_mem_bit ) {
assert ( NULL ! = cur_standalone_sram_info ) ;
cur_standalone_sram_info - > num_mem_bit = num_mem_bit ;
return ;
}
void init_sram_orgz_info ( t_sram_orgz_info * cur_sram_orgz_info ,
enum e_sram_orgz cur_sram_orgz_type ,
t_spice_model * cur_mem_model ,
int grid_nx , int grid_ny ) {
int i , num_bl_per_sram , num_wl_per_sram ;
int num_bl_ports ;
t_spice_model_port * * bl_port = NULL ;
int num_wl_ports ;
t_spice_model_port * * wl_port = NULL ;
assert ( NULL ! = cur_sram_orgz_info ) ;
cur_sram_orgz_info - > type = cur_sram_orgz_type ;
cur_sram_orgz_info - > conf_bit_head = NULL ; /* Configuration bits will be allocated later */
/* According to the type, we allocate structs */
switch ( cur_sram_orgz_info - > type ) {
case SPICE_SRAM_MEMORY_BANK :
cur_sram_orgz_info - > mem_bank_info = alloc_one_mem_bank_info ( ) ;
init_mem_bank_info ( cur_sram_orgz_info - > mem_bank_info , cur_mem_model ) ;
find_bl_wl_ports_spice_model ( cur_mem_model ,
& num_bl_ports , & bl_port , & num_wl_ports , & wl_port ) ;
assert ( 1 = = num_bl_ports ) ;
assert ( 1 = = num_wl_ports ) ;
num_bl_per_sram = bl_port [ 0 ] - > size ;
num_wl_per_sram = wl_port [ 0 ] - > size ;
try_update_sram_orgz_info_reserved_blwl ( cur_sram_orgz_info ,
num_bl_per_sram , num_wl_per_sram ) ;
break ;
case SPICE_SRAM_SCAN_CHAIN :
cur_sram_orgz_info - > scff_info = alloc_one_scff_info ( ) ;
init_scff_info ( cur_sram_orgz_info - > scff_info , cur_mem_model ) ;
break ;
case SPICE_SRAM_STANDALONE :
cur_sram_orgz_info - > standalone_sram_info = alloc_one_standalone_sram_info ( ) ;
init_standalone_sram_info ( cur_sram_orgz_info - > standalone_sram_info , cur_mem_model ) ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid type of SRAM organization! " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
/* Alloc the configuration bit information per grid */
cur_sram_orgz_info - > grid_reserved_conf_bits = ( int * * ) my_malloc ( grid_nx * sizeof ( int * ) ) ;
for ( i = 0 ; i < grid_nx ; i + + ) {
cur_sram_orgz_info - > grid_reserved_conf_bits [ i ] = ( int * ) my_calloc ( grid_ny , sizeof ( int ) ) ;
}
cur_sram_orgz_info - > grid_conf_bits_lsb = ( int * * ) my_malloc ( grid_nx * sizeof ( int * ) ) ;
for ( i = 0 ; i < grid_nx ; i + + ) {
cur_sram_orgz_info - > grid_conf_bits_lsb [ i ] = ( int * ) my_calloc ( grid_ny , sizeof ( int ) ) ;
}
cur_sram_orgz_info - > grid_conf_bits_msb = ( int * * ) my_malloc ( grid_nx * sizeof ( int * ) ) ;
for ( i = 0 ; i < grid_nx ; i + + ) {
cur_sram_orgz_info - > grid_conf_bits_msb [ i ] = ( int * ) my_calloc ( grid_ny , sizeof ( int ) ) ;
}
return ;
}
void free_sram_orgz_info ( t_sram_orgz_info * cur_sram_orgz_info ,
enum e_sram_orgz cur_sram_orgz_type ,
int grid_nx , int grid_ny ) {
int i ;
t_llist * temp = NULL ;
assert ( NULL ! = cur_sram_orgz_info ) ;
/* According to the type, we allocate structs */
switch ( cur_sram_orgz_info - > type ) {
case SPICE_SRAM_MEMORY_BANK :
free_one_mem_bank_info ( cur_sram_orgz_info - > mem_bank_info ) ;
break ;
case SPICE_SRAM_SCAN_CHAIN :
free_one_scff_info ( cur_sram_orgz_info - > scff_info ) ;
break ;
case SPICE_SRAM_STANDALONE :
free_one_standalone_sram_info ( cur_sram_orgz_info - > standalone_sram_info ) ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid type of SRAM organization! " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
/* Free configuration bits linked-list */
temp = cur_sram_orgz_info - > conf_bit_head ;
while ( NULL ! = temp ) {
free_conf_bit_info ( ( t_conf_bit_info * ) ( temp - > dptr ) ) ;
/* Set the data pointor to NULL, then we can call linked list free function */
temp - > dptr = NULL ;
/* Go the next */
temp = temp - > next ;
}
free_llist ( cur_sram_orgz_info - > conf_bit_head ) ;
/* Free the configuration bit information per grid */
for ( i = 0 ; i < grid_nx ; i + + ) {
my_free ( cur_sram_orgz_info - > grid_reserved_conf_bits [ i ] ) ;
}
my_free ( cur_sram_orgz_info - > grid_reserved_conf_bits ) ;
for ( i = 0 ; i < grid_nx ; i + + ) {
my_free ( cur_sram_orgz_info - > grid_conf_bits_lsb [ i ] ) ;
}
my_free ( cur_sram_orgz_info - > grid_conf_bits_lsb ) ;
for ( i = 0 ; i < grid_nx ; i + + ) {
my_free ( cur_sram_orgz_info - > grid_conf_bits_msb [ i ] ) ;
}
my_free ( cur_sram_orgz_info - > grid_conf_bits_msb ) ;
return ;
}
void update_mem_bank_info_reserved_blwl ( t_mem_bank_info * cur_mem_bank_info ,
int updated_reserved_bl , int updated_reserved_wl ) {
assert ( NULL ! = cur_mem_bank_info ) ;
cur_mem_bank_info - > reserved_bl = updated_reserved_bl ;
cur_mem_bank_info - > reserved_wl = updated_reserved_wl ;
return ;
}
void get_mem_bank_info_reserved_blwl ( t_mem_bank_info * cur_mem_bank_info ,
int * num_reserved_bl , int * num_reserved_wl ) {
assert ( NULL ! = cur_mem_bank_info ) ;
( * num_reserved_bl ) = cur_mem_bank_info - > reserved_bl ;
( * num_reserved_wl ) = cur_mem_bank_info - > reserved_wl ;
return ;
}
void update_mem_bank_info_num_blwl ( t_mem_bank_info * cur_mem_bank_info ,
int updated_bl , int updated_wl ) {
assert ( NULL ! = cur_mem_bank_info ) ;
cur_mem_bank_info - > num_bl = updated_bl ;
cur_mem_bank_info - > num_wl = updated_wl ;
return ;
}
/* Initialize the number of normal/reserved BLs and WLs, mem_bits in sram_orgz_info
* If the updated_reserved_bl | wl is larger than the existed value ,
* we update the reserved_bl | wl
*/
void try_update_sram_orgz_info_reserved_blwl ( t_sram_orgz_info * cur_sram_orgz_info ,
int updated_reserved_bl , int updated_reserved_wl ) {
t_spice_model * mem_model = NULL ;
int cur_bl , cur_wl ;
/* Check */
assert ( updated_reserved_bl = = updated_reserved_wl ) ;
/* get memory model */
get_sram_orgz_info_mem_model ( cur_sram_orgz_info , & mem_model ) ;
/* According to the type, we allocate structs */
switch ( cur_sram_orgz_info - > type ) {
case SPICE_SRAM_STANDALONE :
break ;
case SPICE_SRAM_SCAN_CHAIN :
break ;
case SPICE_SRAM_MEMORY_BANK :
/* CMOS technology does not need to update */
switch ( mem_model - > design_tech ) {
case SPICE_MODEL_DESIGN_CMOS :
break ;
case SPICE_MODEL_DESIGN_RRAM :
/* get the current number of reserved bls and wls */
get_sram_orgz_info_reserved_blwl ( cur_sram_orgz_info , & cur_bl , & cur_wl ) ;
if ( ( updated_reserved_bl > cur_bl ) | | ( updated_reserved_wl > cur_wl ) ) {
update_sram_orgz_info_reserved_blwl ( cur_sram_orgz_info ,
updated_reserved_bl , updated_reserved_wl ) ;
update_sram_orgz_info_num_mem_bit ( cur_sram_orgz_info ,
updated_reserved_bl ) ;
update_sram_orgz_info_num_blwl ( cur_sram_orgz_info ,
updated_reserved_bl , updated_reserved_wl ) ;
}
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid type of design technology! " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid type of SRAM organization! " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
}
/* Force to update the number of reserved BLs and WLs in sram_orgz_info
* we always update the reserved_bl | wl
*/
void update_sram_orgz_info_reserved_blwl ( t_sram_orgz_info * cur_sram_orgz_info ,
int updated_reserved_bl , int updated_reserved_wl ) {
assert ( NULL ! = cur_sram_orgz_info ) ;
/* According to the type, we allocate structs */
switch ( cur_sram_orgz_info - > type ) {
case SPICE_SRAM_STANDALONE :
break ;
case SPICE_SRAM_SCAN_CHAIN :
break ;
case SPICE_SRAM_MEMORY_BANK :
update_mem_bank_info_reserved_blwl ( cur_sram_orgz_info - > mem_bank_info ,
updated_reserved_bl , updated_reserved_wl ) ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid type of SRAM organization! " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
return ;
}
void get_sram_orgz_info_reserved_blwl ( t_sram_orgz_info * cur_sram_orgz_info ,
int * num_reserved_bl , int * num_reserved_wl ) {
assert ( NULL ! = cur_sram_orgz_info ) ;
/* According to the type, we allocate structs */
switch ( cur_sram_orgz_info - > type ) {
case SPICE_SRAM_STANDALONE :
break ;
case SPICE_SRAM_SCAN_CHAIN :
break ;
case SPICE_SRAM_MEMORY_BANK :
get_mem_bank_info_reserved_blwl ( cur_sram_orgz_info - > mem_bank_info ,
num_reserved_bl , num_reserved_wl ) ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid type of SRAM organization! " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
return ;
}
void get_sram_orgz_info_num_blwl ( t_sram_orgz_info * cur_sram_orgz_info ,
int * cur_bl , int * cur_wl ) {
assert ( NULL ! = cur_bl ) ;
assert ( NULL ! = cur_wl ) ;
assert ( NULL ! = cur_sram_orgz_info ) ;
/* According to the type, we allocate structs */
switch ( cur_sram_orgz_info - > type ) {
case SPICE_SRAM_STANDALONE :
case SPICE_SRAM_SCAN_CHAIN :
( * cur_bl ) = 0 ;
( * cur_wl ) = 0 ;
break ;
case SPICE_SRAM_MEMORY_BANK :
( * cur_bl ) = cur_sram_orgz_info - > mem_bank_info - > num_bl ;
( * cur_wl ) = cur_sram_orgz_info - > mem_bank_info - > num_wl ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid type of SRAM organization! " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
return ;
}
int get_sram_orgz_info_num_mem_bit ( t_sram_orgz_info * cur_sram_orgz_info ) {
assert ( NULL ! = cur_sram_orgz_info ) ;
/* According to the type, we allocate structs */
switch ( cur_sram_orgz_info - > type ) {
case SPICE_SRAM_STANDALONE :
return cur_sram_orgz_info - > standalone_sram_info - > num_mem_bit ;
case SPICE_SRAM_SCAN_CHAIN :
return cur_sram_orgz_info - > scff_info - > num_mem_bit ;
case SPICE_SRAM_MEMORY_BANK :
return cur_sram_orgz_info - > mem_bank_info - > num_mem_bit ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid type of SRAM organization! " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
return 0 ;
}
void update_sram_orgz_info_num_mem_bit ( t_sram_orgz_info * cur_sram_orgz_info ,
int new_num_mem_bit ) {
assert ( NULL ! = cur_sram_orgz_info ) ;
/* According to the type, we allocate structs */
switch ( cur_sram_orgz_info - > type ) {
case SPICE_SRAM_STANDALONE :
update_standalone_sram_info_num_mem_bit ( cur_sram_orgz_info - > standalone_sram_info , new_num_mem_bit ) ;
break ;
case SPICE_SRAM_SCAN_CHAIN :
update_scff_info_num_mem_bit ( cur_sram_orgz_info - > scff_info , new_num_mem_bit ) ;
break ;
case SPICE_SRAM_MEMORY_BANK :
update_mem_bank_info_num_mem_bit ( cur_sram_orgz_info - > mem_bank_info , new_num_mem_bit ) ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid type of SRAM organization! " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
return ;
}
void update_sram_orgz_info_num_blwl ( t_sram_orgz_info * cur_sram_orgz_info ,
int new_bl , int new_wl ) {
assert ( NULL ! = cur_sram_orgz_info ) ;
/* According to the type, we allocate structs */
switch ( cur_sram_orgz_info - > type ) {
case SPICE_SRAM_STANDALONE :
break ;
case SPICE_SRAM_SCAN_CHAIN :
break ;
case SPICE_SRAM_MEMORY_BANK :
update_mem_bank_info_num_blwl ( cur_sram_orgz_info - > mem_bank_info , new_bl , new_wl ) ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid type of SRAM organization! " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
return ;
}
void get_sram_orgz_info_mem_model ( t_sram_orgz_info * cur_sram_orgz_info ,
t_spice_model * * mem_model_ptr ) {
assert ( NULL ! = cur_sram_orgz_info ) ;
assert ( NULL ! = mem_model_ptr ) ;
/* According to the type, we allocate structs */
switch ( cur_sram_orgz_info - > type ) {
case SPICE_SRAM_STANDALONE :
( * mem_model_ptr ) = cur_sram_orgz_info - > standalone_sram_info - > mem_model ;
break ;
case SPICE_SRAM_SCAN_CHAIN :
( * mem_model_ptr ) = cur_sram_orgz_info - > scff_info - > mem_model ;
break ;
case SPICE_SRAM_MEMORY_BANK :
( * mem_model_ptr ) = cur_sram_orgz_info - > mem_bank_info - > mem_model ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid type of SRAM organization! " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
assert ( NULL ! = ( * mem_model_ptr ) ) ;
return ;
}
/* Manipulating functions for struct t_reserved_syntax_char */
void init_reserved_syntax_char ( t_reserved_syntax_char * cur_reserved_syntax_char ,
char cur_syntax_char , boolean cur_verilog_reserved , boolean cur_spice_reserved ) {
assert ( NULL ! = cur_reserved_syntax_char ) ;
cur_reserved_syntax_char - > syntax_char = cur_syntax_char ;
cur_reserved_syntax_char - > verilog_reserved = cur_verilog_reserved ;
cur_reserved_syntax_char - > spice_reserved = cur_spice_reserved ;
return ;
}
void check_mem_model_blwl_inverted ( t_spice_model * cur_mem_model ,
enum e_spice_model_port_type blwl_port_type ,
boolean * blwl_inverted ) {
int num_blwl_ports = 0 ;
t_spice_model_port * * blwl_port = NULL ;
/* Check */
assert ( ( SPICE_MODEL_PORT_BL = = blwl_port_type ) | | ( SPICE_MODEL_PORT_WL = = blwl_port_type ) ) ;
/* Find BL and WL ports */
blwl_port = find_spice_model_ports ( cur_mem_model , blwl_port_type , & num_blwl_ports , TRUE ) ;
/* If we cannot find any return with warnings */
if ( 0 = = num_blwl_ports ) {
( * blwl_inverted ) = FALSE ;
vpr_printf ( TIO_MESSAGE_WARNING , " (FILE:%s,[LINE%d])Unable to find any BL/WL port for memory model(%s)! \n " ,
__FILE__ , __LINE__ , cur_mem_model - > name ) ;
return ;
}
/* Only 1 port should be found */
assert ( 1 = = num_blwl_ports ) ;
/* And port size should be at least 1 */
assert ( 0 < blwl_port [ 0 ] - > size ) ;
/* if default value of a BL/WL port is 0, we do not need an inversion. */
if ( 0 = = blwl_port [ 0 ] - > default_val ) {
( * blwl_inverted ) = FALSE ;
} else {
/* if default value of a BL/WL port is 1, we need an inversion! */
assert ( 1 = = blwl_port [ 0 ] - > default_val ) ;
( * blwl_inverted ) = TRUE ;
}
return ;
}
/* Useful functions for MUX architecture */
void init_spice_mux_arch ( t_spice_model * spice_model ,
t_spice_mux_arch * spice_mux_arch ,
int mux_size ) {
int cur ;
int i ;
/* Make sure we have a valid pointer*/
if ( NULL = = spice_mux_arch ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,LINE[%d])Invalid spice_mux_arch! \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
/* Basic info*/
spice_mux_arch - > structure = spice_model - > design_tech_info . structure ;
spice_mux_arch - > num_input = mux_size ;
/* For different structure */
switch ( spice_model - > design_tech_info . structure ) {
case SPICE_MODEL_STRUCTURE_TREE :
spice_mux_arch - > num_level = determine_tree_mux_level ( spice_mux_arch - > num_input ) ;
spice_mux_arch - > num_input_basis = 2 ;
/* Determine the level and index of per MUX inputs*/
spice_mux_arch - > num_input_last_level = tree_mux_last_level_input_num ( spice_mux_arch - > num_level , mux_size ) ;
break ;
case SPICE_MODEL_STRUCTURE_ONELEVEL :
spice_mux_arch - > num_level = 1 ;
spice_mux_arch - > num_input_basis = mux_size ;
/* Determine the level and index of per MUX inputs*/
spice_mux_arch - > num_input_last_level = mux_size ;
break ;
case SPICE_MODEL_STRUCTURE_MULTILEVEL :
/* Handle speical case: input size is 2 */
if ( 2 = = mux_size ) {
spice_mux_arch - > num_level = 1 ;
} else {
spice_mux_arch - > num_level = spice_model - > design_tech_info . mux_num_level ;
}
spice_mux_arch - > num_input_basis = determine_num_input_basis_multilevel_mux ( mux_size , spice_mux_arch - > num_level ) ;
/* Determine the level and index of per MUX inputs*/
spice_mux_arch - > num_input_last_level = multilevel_mux_last_level_input_num ( spice_mux_arch - > num_level , spice_mux_arch - > num_input_basis , mux_size ) ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid structure for spice model (%s)! \n " ,
__FILE__ , __LINE__ , spice_model - > name ) ;
exit ( 1 ) ;
}
/* Alloc*/
spice_mux_arch - > num_input_per_level = ( int * ) my_malloc ( sizeof ( int ) * spice_mux_arch - > num_level ) ;
spice_mux_arch - > input_level = ( int * ) my_malloc ( sizeof ( int ) * spice_mux_arch - > num_input ) ;
spice_mux_arch - > input_offset = ( int * ) my_malloc ( sizeof ( int ) * spice_mux_arch - > num_input ) ;
/* Assign inputs info for the last level first */
for ( i = 0 ; i < spice_mux_arch - > num_input_last_level ; i + + ) {
spice_mux_arch - > input_level [ i ] = spice_mux_arch - > num_level ;
spice_mux_arch - > input_offset [ i ] = i ;
}
/* For the last second level*/
if ( spice_mux_arch - > num_input > spice_mux_arch - > num_input_last_level ) {
cur = spice_mux_arch - > num_input_last_level / spice_mux_arch - > num_input_basis ;
/* Start from the input ports that are not occupied by the last level
* last level has ( cur ) outputs
*/
for ( i = spice_mux_arch - > num_input_last_level ; i < spice_mux_arch - > num_input ; i + + ) {
spice_mux_arch - > input_level [ i ] = spice_mux_arch - > num_level - 1 ;
spice_mux_arch - > input_offset [ i ] = cur ;
cur + + ;
}
assert ( ( cur < ( int ) pow ( ( double ) spice_mux_arch - > num_input_basis , ( double ) ( spice_mux_arch - > num_level - 1 ) ) )
| | ( cur = = ( int ) pow ( ( double ) spice_mux_arch - > num_input_basis , ( double ) ( spice_mux_arch - > num_level - 1 ) ) ) ) ;
}
/* Fill the num_input_per_level*/
for ( i = 0 ; i < spice_mux_arch - > num_level ; i + + ) {
cur = i + 1 ;
spice_mux_arch - > num_input_per_level [ i ] = ( int ) pow ( ( double ) spice_mux_arch - > num_input_basis , ( double ) cur ) ;
if ( ( cur = = spice_mux_arch - > num_level )
& & ( spice_mux_arch - > num_input_last_level < spice_mux_arch - > num_input_per_level [ i ] ) ) {
spice_mux_arch - > num_input_per_level [ i ] = spice_mux_arch - > num_input_last_level ;
}
}
return ;
}
/* Determine if we need a speical basis.
* If we need one , we give the MUX size of this special basis
*/
int find_spice_mux_arch_special_basis_size ( t_spice_mux_arch spice_mux_arch ) {
int im ;
int mux_size = spice_mux_arch . num_input ;
int num_input_basis = spice_mux_arch . num_input_basis ;
int num_input_special_basis = 0 ;
int special_basis_start = 0 ;
/* For different structure */
switch ( spice_mux_arch . structure ) {
case SPICE_MODEL_STRUCTURE_TREE :
break ;
case SPICE_MODEL_STRUCTURE_ONELEVEL :
break ;
case SPICE_MODEL_STRUCTURE_MULTILEVEL :
special_basis_start = mux_size - mux_size % num_input_basis ;
for ( im = special_basis_start ; im < mux_size ; im + + ) {
if ( spice_mux_arch . num_level = = spice_mux_arch . input_level [ im ] ) {
num_input_special_basis + + ;
}
}
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,[LINE%d])Invalid structure for spice_mux_arch! \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
return num_input_special_basis ;
}
/* Search the linked list, if we have the same mux size and spice_model
* return 1 , if not we return 0
*/
t_llist * search_mux_linked_list ( t_llist * mux_head ,
int mux_size ,
t_spice_model * spice_model ) {
t_llist * temp = mux_head ;
t_spice_mux_model * cur_mux = NULL ;
/* traversal the linked list*/
while ( temp ) {
cur_mux = ( t_spice_mux_model * ) ( temp - > dptr ) ;
if ( ( cur_mux - > size = = mux_size )
& & ( spice_model = = cur_mux - > spice_model ) ) {
return temp ;
}
/* next */
temp = temp - > next ;
}
return NULL ;
}
/* Check the linked list if we have a mux stored with same spice model
* if not , we create a new one .
*/
void check_and_add_mux_to_linked_list ( t_llist * * muxes_head ,
int mux_size ,
t_spice_model * spice_model ) {
t_spice_mux_model * cur_mux = NULL ;
t_llist * temp = NULL ;
/* Check code: to avoid mistake, we should check the mux size
* the mux_size should be at least 2 so that we need a mux
*/
if ( mux_size < 2 ) {
printf ( " Warning:(File:%s,LINE[%d]) ilegal mux size (%d), expect to be at least 2! \n " ,
__FILE__ , __LINE__ , mux_size ) ;
return ;
}
/* Search the linked list */
if ( NULL ! = search_mux_linked_list ( ( * muxes_head ) , mux_size , spice_model ) ) {
/* We find one, there is no need to create a new one*/
return ;
}
/*Create a linked list, if head is NULL*/
if ( NULL = = ( * muxes_head ) ) {
( * muxes_head ) = create_llist ( 1 ) ;
( * muxes_head ) - > dptr = my_malloc ( sizeof ( t_spice_mux_model ) ) ;
cur_mux = ( t_spice_mux_model * ) ( ( * muxes_head ) - > dptr ) ;
} else {
/* We have to create a new elment in linked list*/
temp = insert_llist_node ( ( * muxes_head ) ) ;
temp - > dptr = my_malloc ( sizeof ( t_spice_mux_model ) ) ;
cur_mux = ( t_spice_mux_model * ) ( temp - > dptr ) ;
}
/* Fill the new SPICE MUX Model*/
cur_mux - > size = mux_size ;
cur_mux - > spice_model = spice_model ;
cur_mux - > cnt = 1 ; /* Initialize the counter*/
return ;
}
/* Free muxes linked list
*/
void free_muxes_llist ( t_llist * muxes_head ) {
t_llist * temp = muxes_head ;
while ( temp ) {
/* Free the mux_spice_model, remember to set the pointer to NULL */
free ( temp - > dptr ) ;
temp - > dptr = NULL ;
/* Move on to the next pointer*/
temp = temp - > next ;
}
free_llist ( muxes_head ) ;
return ;
}
/* Stats the multiplexer sizes and structure in the global routing architecture*/
void stats_spice_muxes_routing_arch ( t_llist * * muxes_head ,
int num_switch ,
t_switch_inf * switches ,
t_spice * spice ,
t_det_routing_arch * routing_arch ) {
int inode ;
t_rr_node * node ;
t_spice_model * sb_switch_spice_model = NULL ;
t_spice_model * cb_switch_spice_model = NULL ;
/* Current Version: Support Uni-directional routing architecture only*/
if ( UNI_DIRECTIONAL ! = routing_arch - > directionality ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (FILE:%s, LINE[%d])Spice Modeling Only support uni-directional routing architecture. \n " , __FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
/* The routing path is.
* OPIN - - - - > CHAN - - - - > . . . - - - - > CHAN - - - - > IPIN
* Each edge is a switch , for IPIN , the switch is a connection block ,
* for the rest is a switch box
*/
/* Count the sizes of muliplexers in routing architecture */
/* Visit the global variable : num_rr_nodes, rr_node */
for ( inode = 0 ; inode < num_rr_nodes ; inode + + ) {
node = & rr_node [ inode ] ;
switch ( node - > type ) {
case IPIN :
/* Have to consider the fan_in only, it is a connection box(multiplexer)*/
assert ( ( node - > fan_in > 0 ) | | ( 0 = = node - > fan_in ) ) ;
if ( 0 = = node - > fan_in ) {
break ;
}
/* Find the spice_model for multiplexers in connection blocks */
cb_switch_spice_model = switches [ node - > driver_switch ] . spice_model ;
/* we should select a spice model for the connection box*/
assert ( NULL ! = cb_switch_spice_model ) ;
check_and_add_mux_to_linked_list ( muxes_head , node - > fan_in , cb_switch_spice_model ) ;
break ;
case CHANX :
case CHANY :
/* Channels are the same, have to consider the fan_in as well,
* it could be a switch box if previous rr_node is a channel
* or it could be a connection box if previous rr_node is a IPIN or OPIN
*/
assert ( ( node - > fan_in > 0 ) | | ( 0 = = node - > fan_in ) ) ;
if ( 0 = = node - > fan_in ) {
break ;
}
/* Find the spice_model for multiplexers in switch blocks*/
sb_switch_spice_model = switches [ node - > driver_switch ] . spice_model ;
/* we should select a spice model for the Switch box*/
assert ( NULL ! = sb_switch_spice_model ) ;
check_and_add_mux_to_linked_list ( muxes_head , node - > fan_in , sb_switch_spice_model ) ;
break ;
case OPIN :
/* Actually, in single driver routing architecture, the OPIN, source of a routing path,
* is directly connected to Switch Box multiplexers
*/
break ;
default :
break ;
}
}
return ;
}
/* Recursively do statistics for the
* multiplexer spice models inside pb_types
*/
void stats_mux_spice_model_pb_type_rec ( t_llist * * muxes_head ,
t_pb_type * cur_pb_type ) {
int imode , ichild , jinterc ;
t_spice_model * interc_spice_model = NULL ;
if ( NULL = = cur_pb_type ) {
vpr_printf ( TIO_MESSAGE_WARNING , " (File:%s,LINE[%d])cur_pb_type is null pointor! \n " , __FILE__ , __LINE__ ) ;
return ;
}
/* If there is spice_model_name, this is a leaf node!*/
if ( NULL ! = cur_pb_type - > spice_model_name ) {
/* What annoys me is VPR create a sub pb_type for each lut which suppose to be a leaf node
* This may bring software convience but ruins SPICE modeling
*/
assert ( NULL ! = cur_pb_type - > spice_model ) ;
return ;
}
/* Traversal the hierarchy*/
for ( imode = 0 ; imode < cur_pb_type - > num_modes ; imode + + ) {
/* Then we have to statisitic the interconnections*/
for ( jinterc = 0 ; jinterc < cur_pb_type - > modes [ imode ] . num_interconnect ; jinterc + + ) {
/* Check the num_mux and fan_in*/
assert ( ( 0 = = cur_pb_type - > modes [ imode ] . interconnect [ jinterc ] . num_mux )
| | ( 0 < cur_pb_type - > modes [ imode ] . interconnect [ jinterc ] . num_mux ) ) ;
if ( 0 = = cur_pb_type - > modes [ imode ] . interconnect [ jinterc ] . num_mux ) {
continue ;
}
interc_spice_model = cur_pb_type - > modes [ imode ] . interconnect [ jinterc ] . spice_model ;
assert ( NULL ! = interc_spice_model ) ;
check_and_add_mux_to_linked_list ( muxes_head ,
cur_pb_type - > modes [ imode ] . interconnect [ jinterc ] . fan_in ,
interc_spice_model ) ;
}
for ( ichild = 0 ; ichild < cur_pb_type - > modes [ imode ] . num_pb_type_children ; ichild + + ) {
stats_mux_spice_model_pb_type_rec ( muxes_head ,
& cur_pb_type - > modes [ imode ] . pb_type_children [ ichild ] ) ;
}
}
return ;
}
/* Statistics the MUX SPICE MODEL with the help of pb_graph
* Not the most efficient function to finish the job
* Abandon it . But remains a good framework that could be re - used in connecting
* spice components together
*/
void stats_mux_spice_model_pb_node_rec ( t_llist * * muxes_head ,
t_pb_graph_node * cur_pb_node ) {
int imode , ipb , ichild , iport , ipin ;
t_pb_type * cur_pb_type = cur_pb_node - > pb_type ;
t_spice_model * interc_spice_model = NULL ;
enum e_interconnect pin_interc_type ;
if ( NULL = = cur_pb_node ) {
vpr_printf ( TIO_MESSAGE_WARNING , " (File:%s,LINE[%d])cur_pb_node is null pointor! \n " , __FILE__ , __LINE__ ) ;
return ;
}
if ( NULL = = cur_pb_type ) {
vpr_printf ( TIO_MESSAGE_WARNING , " (File:%s,LINE[%d])cur_pb_type is null pointor! \n " , __FILE__ , __LINE__ ) ;
return ;
}
/* If there is 0 mode, this is a leaf node!*/
if ( NULL ! = cur_pb_type - > blif_model ) {
assert ( 0 = = cur_pb_type - > num_modes ) ;
assert ( NULL = = cur_pb_type - > modes ) ;
/* Ensure there is blif_model, and spice_model*/
assert ( NULL ! = cur_pb_type - > model ) ;
assert ( NULL ! = cur_pb_type - > spice_model_name ) ;
assert ( NULL ! = cur_pb_type - > spice_model ) ;
return ;
}
/* Traversal the hierarchy*/
for ( imode = 0 ; imode < cur_pb_type - > num_modes ; imode + + ) {
/* Then we have to statisitic the interconnections*/
/* See the input ports*/
for ( iport = 0 ; iport < cur_pb_node - > num_input_ports ; iport + + ) {
for ( ipin = 0 ; ipin < cur_pb_node - > num_input_pins [ iport ] ; ipin + + ) {
/* Ensure this is an input port */
assert ( IN_PORT = = cur_pb_node - > input_pins [ iport ] [ ipin ] . port - > type ) ;
/* See the edges, if the interconnetion type infer a MUX, we go next step*/
pin_interc_type = find_pb_graph_pin_in_edges_interc_type ( cur_pb_node - > input_pins [ iport ] [ ipin ] ) ;
if ( ( COMPLETE_INTERC ! = pin_interc_type ) & & ( MUX_INTERC ! = pin_interc_type ) ) {
continue ;
}
/* We shoule check the size of inputs, in some case of complete, the input_edge is one...*/
if ( ( COMPLETE_INTERC = = pin_interc_type ) & & ( 1 = = cur_pb_node - > input_pins [ iport ] [ ipin ] . num_input_edges ) ) {
continue ;
}
/* Note: i do care the input_edges only! They may infer multiplexers*/
interc_spice_model = find_pb_graph_pin_in_edges_interc_spice_model ( cur_pb_node - > input_pins [ iport ] [ ipin ] ) ;
check_and_add_mux_to_linked_list ( muxes_head ,
cur_pb_node - > input_pins [ iport ] [ ipin ] . num_input_edges ,
interc_spice_model ) ;
}
}
/* See the output ports*/
for ( iport = 0 ; iport < cur_pb_node - > num_output_ports ; iport + + ) {
for ( ipin = 0 ; ipin < cur_pb_node - > num_output_pins [ iport ] ; ipin + + ) {
/* Ensure this is an input port */
assert ( OUT_PORT = = cur_pb_node - > output_pins [ iport ] [ ipin ] . port - > type ) ;
/* See the edges, if the interconnetion type infer a MUX, we go next step*/
pin_interc_type = find_pb_graph_pin_in_edges_interc_type ( cur_pb_node - > output_pins [ iport ] [ ipin ] ) ;
if ( ( COMPLETE_INTERC ! = pin_interc_type ) & & ( MUX_INTERC ! = pin_interc_type ) ) {
continue ;
}
/* We shoule check the size of inputs, in some case of complete, the input_edge is one...*/
if ( ( COMPLETE_INTERC = = pin_interc_type ) & & ( 1 = = cur_pb_node - > output_pins [ iport ] [ ipin ] . num_input_edges ) ) {
continue ;
}
/* Note: i do care the input_edges only! They may infer multiplexers*/
interc_spice_model = find_pb_graph_pin_in_edges_interc_spice_model ( cur_pb_node - > output_pins [ iport ] [ ipin ] ) ;
check_and_add_mux_to_linked_list ( muxes_head ,
cur_pb_node - > output_pins [ iport ] [ ipin ] . num_input_edges ,
interc_spice_model ) ;
}
}
/* See the clock ports*/
for ( iport = 0 ; iport < cur_pb_node - > num_clock_ports ; iport + + ) {
for ( ipin = 0 ; ipin < cur_pb_node - > num_clock_pins [ iport ] ; ipin + + ) {
/* Ensure this is an input port */
assert ( IN_PORT = = cur_pb_node - > clock_pins [ iport ] [ ipin ] . port - > type ) ;
/* See the edges, if the interconnetion type infer a MUX, we go next step*/
pin_interc_type = find_pb_graph_pin_in_edges_interc_type ( cur_pb_node - > clock_pins [ iport ] [ ipin ] ) ;
if ( ( COMPLETE_INTERC ! = pin_interc_type ) & & ( MUX_INTERC ! = pin_interc_type ) ) {
continue ;
}
/* We shoule check the size of inputs, in some case of complete, the input_edge is one...*/
if ( ( COMPLETE_INTERC = = pin_interc_type ) & & ( 1 = = cur_pb_node - > clock_pins [ iport ] [ ipin ] . num_input_edges ) ) {
continue ;
}
/* Note: i do care the input_edges only! They may infer multiplexers*/
interc_spice_model = find_pb_graph_pin_in_edges_interc_spice_model ( cur_pb_node - > clock_pins [ iport ] [ ipin ] ) ;
check_and_add_mux_to_linked_list ( muxes_head ,
cur_pb_node - > clock_pins [ iport ] [ ipin ] . num_input_edges ,
interc_spice_model ) ;
}
}
for ( ichild = 0 ; ichild < cur_pb_type - > modes [ imode ] . num_pb_type_children ; ichild + + ) {
/* num_pb is the number of such pb_type in a mode*/
for ( ipb = 0 ; ipb < cur_pb_type - > modes [ imode ] . pb_type_children [ ichild ] . num_pb ; ipb + + ) {
/* child_pb_grpah_nodes: [0..num_modes-1][0..num_pb_type_in_mode-1][0..num_pb_type-1]*/
stats_mux_spice_model_pb_node_rec ( muxes_head ,
& cur_pb_node - > child_pb_graph_nodes [ imode ] [ ichild ] [ ipb ] ) ;
}
}
}
return ;
}
/* Statistic for all the multiplexers in FPGA
* We determine the sizes and its structure ( according to spice_model ) for each type of multiplexers
* We search multiplexers in Switch Blocks , Connection blocks and Configurable Logic Blocks
* In additional to multiplexers , this function also consider crossbars .
* All the statistics are stored in a linked list , as a return value
*/
t_llist * stats_spice_muxes ( int num_switches ,
t_switch_inf * switches ,
t_spice * spice ,
t_det_routing_arch * routing_arch ) {
int iedge ;
int itype ;
int imodel ;
/* Linked-list to store the information of Multiplexers*/
t_llist * muxes_head = NULL ;
/* Step 1: We should check the multiplexer spice models defined in routing architecture.*/
stats_spice_muxes_routing_arch ( & muxes_head , num_switches , switches , spice , routing_arch ) ;
/* Statistics after search routing resources */
/*
temp = muxes_head ;
while ( temp ) {
t_spice_mux_model * spice_mux_model = ( t_spice_mux_model * ) temp - > dptr ;
vpr_printf ( TIO_MESSAGE_INFO , " Routing multiplexers: size=%d \n " , spice_mux_model - > size ) ;
temp = temp - > next ;
}
*/
/* Step 2: Count the sizes of multiplexers in complex logic blocks */
for ( itype = 0 ; itype < num_types ; itype + + ) {
if ( NULL ! = type_descriptors [ itype ] . pb_type ) {
stats_mux_spice_model_pb_type_rec ( & muxes_head , type_descriptors [ itype ] . pb_type ) ;
}
}
/* Step 3: count the size of multiplexer that will be used in LUTs*/
for ( imodel = 0 ; imodel < spice - > num_spice_model ; imodel + + ) {
/* For those LUTs that netlists are not provided. We create a netlist and thus need a MUX*/
if ( ( SPICE_MODEL_LUT = = spice - > spice_models [ imodel ] . type )
& & ( NULL = = spice - > spice_models [ imodel ] . model_netlist ) ) {
stats_lut_spice_mux ( & muxes_head , & ( spice - > spice_models [ imodel ] ) ) ;
}
}
/* Statistics after search routing resources */
/*
temp = muxes_head ;
while ( temp ) {
t_spice_mux_model * spice_mux_model = ( t_spice_mux_model * ) temp - > dptr ;
vpr_printf ( TIO_MESSAGE_INFO , " Pb_types multiplexers: size=%d \n " , spice_mux_model - > size ) ;
temp = temp - > next ;
}
*/
return muxes_head ;
}
/* Find the interconnection type of pb_graph_pin edges*/
enum e_interconnect find_pb_graph_pin_in_edges_interc_type ( t_pb_graph_pin pb_graph_pin ) {
enum e_interconnect interc_type ;
int def_interc_type = 0 ;
int iedge ;
for ( iedge = 0 ; iedge < pb_graph_pin . num_input_edges ; iedge + + ) {
/* Make sure all edges are legal: 1 input_pin, 1 output_pin*/
check_pb_graph_edge ( * ( pb_graph_pin . input_edges [ iedge ] ) ) ;
/* Make sure all the edges interconnect type is the same*/
if ( 0 = = def_interc_type ) {
interc_type = pb_graph_pin . input_edges [ iedge ] - > interconnect - > type ;
} else if ( interc_type ! = pb_graph_pin . input_edges [ iedge ] - > interconnect - > type ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,LINE[%d])Interconnection type are not same for port(%s),pin(%d). \n " ,
__FILE__ , __LINE__ , pb_graph_pin . port - > name , pb_graph_pin . pin_number ) ;
exit ( 1 ) ;
}
}
return interc_type ;
}
/* Find the interconnection type of pb_graph_pin edges*/
t_spice_model * find_pb_graph_pin_in_edges_interc_spice_model ( t_pb_graph_pin pb_graph_pin ) {
t_spice_model * interc_spice_model ;
int def_interc_model = 0 ;
int iedge ;
for ( iedge = 0 ; iedge < pb_graph_pin . num_input_edges ; iedge + + ) {
/* Make sure all edges are legal: 1 input_pin, 1 output_pin*/
check_pb_graph_edge ( * ( pb_graph_pin . input_edges [ iedge ] ) ) ;
/* Make sure all the edges interconnect type is the same*/
if ( 0 = = def_interc_model ) {
interc_spice_model = pb_graph_pin . input_edges [ iedge ] - > interconnect - > spice_model ;
} else if ( interc_spice_model ! = pb_graph_pin . input_edges [ iedge ] - > interconnect - > spice_model ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s,LINE[%d])Interconnection spice_model are not same for port(%s),pin(%d). \n " ,
__FILE__ , __LINE__ , pb_graph_pin . port - > name , pb_graph_pin . pin_number ) ;
exit ( 1 ) ;
}
}
return interc_spice_model ;
}
int find_path_id_between_pb_rr_nodes ( t_rr_node * local_rr_graph ,
int src_node ,
int des_node ) {
int path_id = - 1 ;
int prev_edge = - 1 ;
int path_count = 0 ;
int iedge ;
t_interconnect * cur_interc = NULL ;
/* Check */
assert ( NULL ! = local_rr_graph ) ;
assert ( ( 0 = = src_node ) | | ( 0 < src_node ) ) ;
assert ( ( 0 = = des_node ) | | ( 0 < des_node ) ) ;
prev_edge = local_rr_graph [ des_node ] . prev_edge ;
check_pb_graph_edge ( * ( local_rr_graph [ src_node ] . pb_graph_pin - > output_edges [ prev_edge ] ) ) ;
assert ( local_rr_graph [ src_node ] . pb_graph_pin - > output_edges [ prev_edge ] - > output_pins [ 0 ] = = local_rr_graph [ des_node ] . pb_graph_pin ) ;
cur_interc = local_rr_graph [ src_node ] . pb_graph_pin - > output_edges [ prev_edge ] - > interconnect ;
/* Search des_node input edges */
for ( iedge = 0 ; iedge < local_rr_graph [ des_node ] . pb_graph_pin - > num_input_edges ; iedge + + ) {
if ( local_rr_graph [ des_node ] . pb_graph_pin - > input_edges [ iedge ] - > input_pins [ 0 ]
= = local_rr_graph [ src_node ] . pb_graph_pin ) {
/* Strict check */
assert ( local_rr_graph [ src_node ] . pb_graph_pin - > output_edges [ prev_edge ]
= = local_rr_graph [ des_node ] . pb_graph_pin - > input_edges [ iedge ] ) ;
path_id = path_count ;
break ;
}
if ( cur_interc = = local_rr_graph [ des_node ] . pb_graph_pin - > input_edges [ iedge ] - > interconnect ) {
path_count + + ;
}
}
return path_id ;
}
/* Return a child_pb if it is mapped.*/
t_pb * get_child_pb_for_phy_pb_graph_node ( t_pb * cur_pb , int ipb , int jpb ) {
t_pb * child_pb = NULL ;
/* TODO: more check ? */
if ( NULL = = cur_pb ) {
return NULL ;
}
if ( ( NULL ! = cur_pb - > child_pbs [ ipb ] ) & & ( NULL ! = cur_pb - > child_pbs [ ipb ] [ jpb ] . name ) ) {
child_pb = & ( cur_pb - > child_pbs [ ipb ] [ jpb ] ) ;
}
return child_pb ;
}
/* Check if all the SRAM ports have the correct SPICE MODEL */
void config_spice_models_sram_port_spice_model ( int num_spice_model ,
t_spice_model * spice_models ,
t_spice_model * default_sram_spice_model ) {
int i , iport ;
for ( i = 0 ; i < num_spice_model ; i + + ) {
for ( iport = 0 ; iport < spice_models [ i ] . num_port ; iport + + ) {
/* Bypass non SRAM ports */
if ( SPICE_MODEL_PORT_SRAM ! = spice_models [ i ] . ports [ iport ] . type ) {
continue ;
}
/* Write for the default SRAM SPICE model! */
spice_models [ i ] . ports [ iport ] . spice_model = default_sram_spice_model ;
/* Only show warning when we try to override the given spice_model_name ! */
if ( NULL = = spice_models [ i ] . ports [ iport ] . spice_model_name ) {
continue ;
}
/* Give a warning !!! */
if ( 0 ! = strcmp ( default_sram_spice_model - > name , spice_models [ i ] . ports [ iport ] . spice_model_name ) ) {
vpr_printf ( TIO_MESSAGE_WARNING ,
" (FILE:%s, LINE[%d]) Overwrite SRAM SPICE MODEL of SPICE model port (name:%s, port:%s) to be the correct one (name:%s)! \n " ,
__FILE__ , __LINE__ ,
spice_models [ i ] . name ,
spice_models [ i ] . ports [ iport ] . prefix ,
default_sram_spice_model - > name ) ;
}
}
}
return ;
}
2018-08-01 15:04:28 -05:00
/* Return the child_pb of a LUT pb
* Because the mapping information is stored in the child_pb ! ! !
*/
2018-07-26 12:28:21 -05:00
t_pb * get_lut_child_pb ( t_pb * cur_lut_pb ,
int mode_index ) {
assert ( SPICE_MODEL_LUT = = cur_lut_pb - > pb_graph_node - > pb_type - > spice_model - > type ) ;
assert ( 1 = = cur_lut_pb - > pb_graph_node - > pb_type - > modes [ mode_index ] . num_pb_type_children ) ;
assert ( 1 = = cur_lut_pb - > pb_graph_node - > pb_type - > num_pb ) ;
return ( & ( cur_lut_pb - > child_pbs [ 0 ] [ 0 ] ) ) ;
}
2018-08-01 15:04:28 -05:00
/* Return the child_pb of a hardlogic pb
* Because the mapping information is stored in the child_pb ! ! !
*/
t_pb * get_hardlogic_child_pb ( t_pb * cur_hardlogic_pb ,
int mode_index ) {
assert ( SPICE_MODEL_HARDLOGIC = = cur_hardlogic_pb - > pb_graph_node - > pb_type - > spice_model - > type ) ;
assert ( 1 = = cur_hardlogic_pb - > pb_graph_node - > pb_type - > modes [ mode_index ] . num_pb_type_children ) ;
assert ( 1 = = cur_hardlogic_pb - > pb_graph_node - > pb_type - > num_pb ) ;
return ( & ( cur_hardlogic_pb - > child_pbs [ 0 ] [ 0 ] ) ) ;
}
2018-07-26 12:28:21 -05:00
int get_grid_pin_height ( int grid_x , int grid_y , int pin_index ) {
int pin_height ;
t_type_ptr grid_type = NULL ;
/* Get type */
grid_type = grid [ grid_x ] [ grid_y ] . type ;
/* Return if this is an empty type */
if ( ( NULL = = grid_type )
| | ( EMPTY_TYPE = = grid_type ) ) {
pin_height = 0 ;
return pin_height ;
}
/* Check if the pin index is in the range */
assert ( ( ( 0 = = pin_index ) | | ( 0 < pin_index ) )
& & ( pin_index < grid_type - > num_pins ) ) ;
/* Find the pin_height */
pin_height = grid_type - > pin_height [ pin_index ] ;
return pin_height ;
}
2018-08-09 12:27:16 -05:00
int get_grid_pin_side ( int grid_x , int grid_y , int pin_index ) {
int pin_height , side , pin_side ;
t_type_ptr grid_type = NULL ;
/* Get type */
grid_type = grid [ grid_x ] [ grid_y ] . type ;
/* Return if this is an empty type */
if ( ( NULL = = grid_type )
| | ( EMPTY_TYPE = = grid_type ) ) {
return - 1 ;
}
/* Check if the pin index is in the range */
assert ( ( ( 0 = = pin_index ) | | ( 0 < pin_index ) )
& & ( pin_index < grid_type - > num_pins ) ) ;
/* Find the pin_height */
pin_height = get_grid_pin_height ( grid_x , grid_y , pin_index ) ;
pin_side = - 1 ;
for ( side = 0 ; side < 4 ; side + + ) {
/* Bypass corner cases */
/* Pin can only locate on BOTTOM side, when grid is on TOP border */
if ( ( ny = = grid_y ) & & ( 2 ! = side ) ) {
continue ;
}
/* Pin can only locate on LEFT side, when grid is on RIGHT border */
if ( ( nx = = grid_x ) & & ( 3 ! = side ) ) {
continue ;
}
/* Pin can only locate on the TOP side, when grid is on BOTTOM border */
if ( ( 0 = = grid_y ) & & ( 0 ! = side ) ) {
continue ;
}
/* Pin can only locate on the RIGHT side, when grid is on LEFT border */
if ( ( 0 = = grid_x ) & & ( 1 ! = side ) ) {
continue ;
}
if ( 1 = = grid_type - > pinloc [ pin_height ] [ side ] [ pin_index ] ) {
if ( - 1 ! = pin_side ) {
vpr_printf ( TIO_MESSAGE_ERROR , " (%s, [LINE%d]) Duplicated pin(index:%d) on two sides: %s and %s of type (name=%s)! \n " ,
__FILE__ , __LINE__ ,
pin_index ,
convert_side_index_to_string ( pin_side ) ,
convert_side_index_to_string ( side ) ,
grid_type - > name ) ;
exit ( 1 ) ;
}
pin_side = side ;
}
}
return pin_side ;
}
2018-07-26 12:28:21 -05:00
void determine_sb_port_coordinator ( t_sb cur_sb_info , int side ,
int * port_x , int * port_y ) {
/* Check */
assert ( ( - 1 < side ) & & ( side < 4 ) ) ;
/* Initialize */
( * port_x ) = - 1 ;
( * port_y ) = - 1 ;
switch ( side ) {
case TOP :
/* (0 == side) */
/* 1. Channel Y [x][y+1] inputs */
( * port_x ) = cur_sb_info . x ;
( * port_y ) = cur_sb_info . y + 1 ;
break ;
case RIGHT :
/* 1 == side */
/* 2. Channel X [x+1][y] inputs */
( * port_x ) = cur_sb_info . x + 1 ;
( * port_y ) = cur_sb_info . y ;
break ;
case BOTTOM :
/* 2 == side */
/* 3. Channel Y [x][y] inputs */
( * port_x ) = cur_sb_info . x ;
( * port_y ) = cur_sb_info . y ;
break ;
case LEFT :
/* 3 == side */
/* 4. Channel X [x][y] inputs */
( * port_x ) = cur_sb_info . x ;
( * port_y ) = cur_sb_info . y ;
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File: %s [LINE%d]) Invalid side of sb[%d][%d]! \n " ,
__FILE__ , __LINE__ , cur_sb_info . x , cur_sb_info . y , side ) ;
exit ( 1 ) ;
}
return ;
}
void init_spice_models_tb_cnt ( int num_spice_models ,
t_spice_model * spice_model ) {
int imodel ;
for ( imodel = 0 ; imodel < num_spice_models ; imodel + + ) {
spice_model [ imodel ] . tb_cnt = 0 ;
}
return ;
}
void init_spice_models_grid_tb_cnt ( int num_spice_models ,
t_spice_model * spice_model ,
int grid_x , int grid_y ) {
int imodel ;
for ( imodel = 0 ; imodel < num_spice_models ; imodel + + ) {
spice_model [ imodel ] . tb_cnt = spice_model [ imodel ] . grid_index_low [ grid_x ] [ grid_y ] ;
}
return ;
}
void check_spice_models_grid_tb_cnt ( int num_spice_models ,
t_spice_model * spice_model ,
int grid_x , int grid_y ,
enum e_spice_model_type spice_model_type_to_check ) {
int imodel ;
for ( imodel = 0 ; imodel < num_spice_models ; imodel + + ) {
if ( spice_model_type_to_check ! = spice_model [ imodel ] . type ) {
continue ;
}
2018-08-01 15:04:28 -05:00
assert ( spice_model [ imodel ] . tb_cnt = = spice_model [ imodel ] . grid_index_high [ grid_x ] [ grid_y ] ) ;
2018-07-26 12:28:21 -05:00
}
return ;
}
boolean check_negative_variation ( float avg_val ,
t_spice_mc_variation_params variation_params ) {
boolean exist_neg_val = FALSE ;
/* Assume only support gaussian variation now */
if ( avg_val < 0. ) {
exist_neg_val = TRUE ;
}
return exist_neg_val ;
}
2018-08-01 15:04:28 -05:00
/* Check if this cby_info exists, it may be covered by a heterogenous block */
boolean is_cb_exist ( t_rr_type cb_type ,
int cb_x , int cb_y ) {
boolean cb_exist = TRUE ;
/* Check */
assert ( ( ! ( 0 > cb_x ) ) & & ( ! ( cb_x > ( nx + 1 ) ) ) ) ;
assert ( ( ! ( 0 > cb_y ) ) & & ( ! ( cb_y > ( ny + 1 ) ) ) ) ;
switch ( cb_type ) {
case CHANX :
/* Border case */
/* Check the grid under this CB */
if ( ( NULL = = grid [ cb_x ] [ cb_y ] . type )
| | ( EMPTY_TYPE = = grid [ cb_x ] [ cb_y ] . type )
| | ( 1 < grid [ cb_x ] [ cb_y ] . type - > height ) ) {
cb_exist = FALSE ;
}
break ;
case CHANY :
break ;
default :
vpr_printf ( TIO_MESSAGE_ERROR , " (File:%s, [LINE%d])Invalid CB type! Should be CHANX or CHANY. \n " ,
__FILE__ , __LINE__ ) ;
exit ( 1 ) ;
}
return cb_exist ;
}
/* Count the number of IPIN rr_nodes in a CB_info struct */
int count_cb_info_num_ipin_rr_nodes ( t_cb cur_cb_info ) {
int side ;
int cnt = 0 ;
for ( side = 0 ; side < cur_cb_info . num_sides ; side + + ) {
cnt + = cur_cb_info . num_ipin_rr_nodes [ side ] ;
}
return cnt ;
}
2018-08-10 14:46:00 -05:00
/* Add a subckt file name to a linked list */
t_llist * add_one_subckt_file_name_to_llist ( t_llist * cur_head ,
char * subckt_file_path ) {
t_llist * new_head = NULL ;
if ( NULL = = cur_head ) {
new_head = create_llist ( 1 ) ;
new_head - > dptr = ( void * ) my_strdup ( subckt_file_path ) ;
} else {
new_head = insert_llist_node_before_head ( cur_head ) ;
new_head - > dptr = ( void * ) my_strdup ( subckt_file_path ) ;
}
return new_head ;
}
/* Check if SPICE subckt is already created
* ( if they exist in a given linked - list
*/
boolean check_subckt_file_exist_in_llist ( t_llist * subckt_llist_head ,
char * subckt_file_name ) {
t_llist * temp = NULL ;
temp = subckt_llist_head ;
while ( temp ) {
if ( 0 = = strcmp ( subckt_file_name , ( char * ) ( temp - > dptr ) ) ) {
return TRUE ;
}
temp = temp - > next ;
}
return FALSE ;
}
2018-07-26 12:28:21 -05:00