VPR-6.0
|
00001 #include <stdio.h> 00002 #include <string.h> 00003 00004 #include "util.h" 00005 #include "vpr_types.h" 00006 #include "globals.h" 00007 #include "hash.h" 00008 #include "vpr_utils.h" 00009 #include "check_netlist.h" 00010 #include "assert.h" 00011 #include "read_xml_arch_file.h" 00012 00013 #define ERROR_THRESHOLD 100 00014 00015 /**************** Subroutines local to this module **************************/ 00016 00017 static int check_connections_to_global_clb_pins(int inet); 00018 00019 static int check_for_duplicated_names(void); 00020 00021 static int check_clb_conn(int iblk, 00022 int num_conn); 00023 00024 static int check_clb_internal_nets(int iblk); 00025 00026 static int check_subblock_internal_nets(int iblk, int isub); 00027 00028 static void check_for_multiple_sink_connections(void); 00029 00030 static int get_num_conn(int bnum); 00031 00032 static int check_subblocks(int iblk); 00033 00034 static int check_primitives(int iblk, int isub); 00035 00036 00037 /*********************** Subroutine definitions *****************************/ 00038 00039 /** This routine checks that the netlist makes sense. */ 00040 void 00041 check_netlist() 00042 { 00043 int i, error, num_conn; 00044 int net_count; 00045 struct s_hash **net_hash_table, *h_net_ptr; 00046 00047 net_hash_table = alloc_hash_table(); 00048 00049 net_count = 0; 00050 00051 error = 0; 00052 00053 /* Check that nets fanout and have a driver. */ 00054 for(i = 0; i < num_nets; i++) 00055 { 00056 h_net_ptr = insert_in_hash_table(net_hash_table, clb_net[i].name, i); 00057 if(h_net_ptr->count != 1) { 00058 printf(ERRTAG "net %s has multiple drivers.\n", clb_net[i].name); 00059 error++; 00060 } 00061 error += check_connections_to_global_clb_pins(i); 00062 if(error >= ERROR_THRESHOLD) { 00063 printf("Too many errors in netlist, exiting\n"); 00064 exit(1); 00065 } 00066 } 00067 free_hash_table(net_hash_table); 00068 00069 /* Check that each block makes sense. */ 00070 for(i = 0; i < num_blocks; i++) 00071 { 00072 num_conn = get_num_conn(i); 00073 error += check_clb_conn(i, num_conn); 00074 error += check_clb_internal_nets(i); 00075 error += check_subblocks(i); 00076 if(error >= ERROR_THRESHOLD) { 00077 printf("Too many errors in netlist, exiting\n"); 00078 exit(1); 00079 } 00080 } 00081 00082 error += check_for_duplicated_names(); 00083 00084 if(error != 0) 00085 { 00086 printf("Found %d fatal Errors in the input netlist.\n", error); 00087 exit(1); 00088 } 00089 00090 /* HACK: Jason Luu January 17, 2011 Do not route common constants gnd and vcc 00091 Todo: Need to make architecture driven. 00092 */ 00093 for(i = 0; i < num_nets; i++) 00094 { 00095 if(strcmp(clb_net[i].name, "vcc") == 0) { 00096 clb_net[i].is_global = TRUE; 00097 } else if(strcmp(clb_net[i].name, "gnd") == 0) { 00098 clb_net[i].is_global = TRUE; 00099 } 00100 } 00101 } 00102 00103 00104 00105 /** Checks that a global net (inet) connects only to global CLB input pins 00106 * and that non-global nets never connects to a global CLB pin. Either 00107 * global or non-global nets are allowed to connect to pads. 00108 */ 00109 static int 00110 check_connections_to_global_clb_pins(int inet) 00111 { 00112 int ipin, num_pins, iblk, node_block_pin, error; 00113 00114 num_pins = (clb_net[inet].num_sinks + 1); 00115 error = 0; 00116 00117 /* For now global signals can be driven by an I/O pad or any CLB output * 00118 * although a CLB output generates a warning. I could make a global CLB * 00119 * output pin type to allow people to make architectures that didn't have * 00120 * this warning. */ 00121 00122 for(ipin = 0; ipin < num_pins; ipin++) 00123 { 00124 iblk = clb_net[inet].node_block[ipin]; 00125 00126 node_block_pin = clb_net[inet].node_block_pin[ipin]; 00127 00128 if(block[iblk].type->is_global_pin[node_block_pin] != 00129 clb_net[inet].is_global && block[iblk].type != IO_TYPE) 00130 { 00131 00132 /* Allow a CLB output pin to drive a global net (warning only). */ 00133 00134 if(ipin == 0 && clb_net[inet].is_global) 00135 { 00136 printf 00137 (WARNTAG "in check_connections_to_global_clb_pins:\n" 00138 "\tnet #%d (%s) is driven by CLB output pin (#%d)\n" 00139 "\ton block #%d (%s).\n", inet, 00140 clb_net[inet].name, node_block_pin, iblk, 00141 block[iblk].name); 00142 } 00143 else 00144 { /* Otherwise -> Error */ 00145 printf 00146 (ERRTAG "in check_connections_to_global_clb_pins:\n" 00147 "\tpin %d on net #%d (%s) connects to CLB input pin (#%d)\n" 00148 "\ton block #%d (%s).\n", ipin, inet, 00149 clb_net[inet].name, node_block_pin, iblk, 00150 block[iblk].name); 00151 error++; 00152 } 00153 00154 if(clb_net[inet].is_global) 00155 printf("\tNet is global, but CLB pin is not.\n\n"); 00156 else 00157 printf("\tCLB pin is global, but net is not.\n\n"); 00158 } 00159 } /* End for all pins */ 00160 00161 return (error); 00162 } 00163 00164 00165 /** Checks that the connections into and out of the clb make sense. */ 00166 static int 00167 check_clb_conn(int iblk, 00168 int num_conn) 00169 { 00170 int iclass, ipin, error; 00171 t_type_ptr type; 00172 00173 error = 0; 00174 type = block[iblk].type; 00175 00176 if(type == IO_TYPE) 00177 { 00178 if(num_conn != 1) 00179 { 00180 printf(ERRTAG "io blk #%d (%s) has %d pins.\n", 00181 iblk, block[iblk].name, num_conn); 00182 error++; 00183 } 00184 } 00185 else if(num_conn < 2) 00186 { 00187 printf(WARNTAG "logic block #%d (%s) has only %d pin.\n", 00188 iblk, block[iblk].name, num_conn); 00189 00190 /* Allow the case where we have only one OUTPUT pin connected to continue. * 00191 * This is used sometimes as a constant generator for a primary output, * 00192 * but I will still warn the user. If the only pin connected is an input, * 00193 * abort. */ 00194 00195 if(num_conn == 1) 00196 { 00197 for(ipin = 0; ipin < type->num_pins; ipin++) 00198 { 00199 if(block[iblk].nets[ipin] != OPEN) 00200 { 00201 iclass = type->pin_class[ipin]; 00202 00203 if(type->class_inf[iclass].type != DRIVER) 00204 { 00205 error++; 00206 } 00207 else 00208 { 00209 printf 00210 ("\tPin is an output -- may be a constant generator.\n" 00211 "\tNon-fatal, but check this.\n"); 00212 } 00213 00214 break; 00215 } 00216 } 00217 } 00218 else 00219 { 00220 error++; 00221 } 00222 } 00223 00224 /* This case should already have been flagged as an error -- this is * 00225 * just a redundant double check. */ 00226 00227 if(num_conn > type->num_pins) 00228 { 00229 printf(ERRTAG "logic block #%d with output %s has %d pins.\n", 00230 iblk, block[iblk].name, num_conn); 00231 error++; 00232 } 00233 00234 return (error); 00235 } 00236 00237 static int check_clb_internal_nets(int iblk) { 00238 /* TODO: 00239 * Check if the internal CLB nets makes sense and are connected properly 00240 * Consists of 3 main loops 00241 * 1. a) Check name uniqueness 00242 b) Check all net connections are to CLB pins or subblock pins and that they match the net examined 00243 * 2. Check all connected CLB pins are connected to valid internal nets 00244 * 3. Check all connected subblock pins are connected to valid internal nets and that these match the net indexes 00245 */ 00246 return 0; 00247 } 00248 00249 00250 static int check_subblock_internal_nets(int iblk, int isub) { 00251 /* 00252 * TODO 00253 * Check if the internal CLB nets makes sense and are connected properly 00254 * Consists of 3 main checks 00255 * 1. a) Check name uniqueness 00256 b) Check all net connections are to CLB pins or subblock pins and that they match the net examined 00257 * 2. Check all connected CLB pins are connected to valid internal nets 00258 * 3. Check all connected subblock pins are connected to valid internal nets and that these match the net indexes 00259 */ 00260 return 0; 00261 } 00262 00263 static int 00264 check_subblocks(int iblk) 00265 { 00266 /* TODO */ 00267 /* This routine checks the subblocks of iblk (which must be a CLB). It * 00268 * returns the number of errors found. */ 00269 return 0; 00270 } 00271 00272 00273 static int 00274 check_primitives(int iblk, int isub) 00275 { 00276 00277 /* TODO: 00278 This routine checks the subblocks of iblk (which must be a CLB). It * 00279 * returns the number of errors found. */ 00280 return 0; 00281 00282 } 00283 00284 00285 static int 00286 check_for_duplicated_names(void) 00287 { 00288 #if 0 00289 int iblk, isub, iprim, error; 00290 int clb_count, sub_count, prim_count; 00291 struct s_hash **clb_hash_table, *clb_h_ptr; 00292 struct s_hash **sub_hash_table, *sub_h_ptr; 00293 struct s_hash **prim_hash_table, *prim_h_ptr; 00294 00295 clb_hash_table = alloc_hash_table(); 00296 sub_hash_table = alloc_hash_table(); 00297 prim_hash_table = alloc_hash_table(); 00298 00299 error = clb_count = sub_count = prim_count = 0; 00300 00301 for(iblk = 0; iblk < num_blocks; iblk++) 00302 { 00303 clb_h_ptr = insert_in_hash_table(clb_hash_table, block[iblk].name, clb_count); 00304 if(clb_h_ptr->count > 1) { 00305 printf(ERRTAG "block %s has duplicated name\n", block[iblk].name); 00306 error++; 00307 } else { 00308 clb_count++; 00309 } 00310 for(isub = 0; isub < block[iblk].num_subblocks; isub++) 00311 { 00312 sub_h_ptr = insert_in_hash_table(sub_hash_table, block[iblk].subblocks[isub].name, sub_count); 00313 if(sub_h_ptr->count > 1) { 00314 printf(ERRTAG "subblock %s has duplicated name\n", block[iblk].subblocks[isub].name); 00315 error++; 00316 } else { 00317 sub_count++; 00318 } 00319 for(iprim = 0; iprim < block[iblk].subblocks[isub].num_primitives; iprim++) 00320 { 00321 prim_h_ptr = insert_in_hash_table(prim_hash_table, block[iblk].subblocks[isub].primitives[iprim].name, prim_count); 00322 if(prim_h_ptr->count > 1) { 00323 printf(ERRTAG "primitive %s has duplicated name\n", block[iblk].subblocks[isub].primitives[iprim].name); 00324 error++; 00325 } else { 00326 prim_count++; 00327 } 00328 } 00329 } 00330 } 00331 return error; 00332 #endif 00333 return 0; 00334 } 00335 00336 00337 /** This routine returns the number of connections to a block. */ 00338 static int 00339 get_num_conn(int bnum) 00340 { 00341 int i, num_conn; 00342 t_type_ptr type; 00343 00344 type = block[bnum].type; 00345 00346 num_conn = 0; 00347 00348 for(i = 0; i < type->num_pins; i++) 00349 { 00350 if(block[bnum].nets[i] != OPEN) 00351 num_conn++; 00352 } 00353 00354 return (num_conn); 00355 } 00356 00357