VPR-6.0
|
00001 #include <string.h> 00002 #include <assert.h> 00003 #include "util.h" 00004 #include "arch_types.h" 00005 #include "ReadLine.h" 00006 #include "ezxml.h" 00007 #include "read_xml_arch_file.h" 00008 #include "read_xml_util.h" 00009 00010 /* special type indexes, necessary for initialization initialization, everything afterwards 00011 should use the pointers to these type indices*/ 00012 00013 #define NUM_MODELS_IN_LIBRARY 4 00014 #define EMPTY_TYPE_INDEX 0 00015 #define IO_TYPE_INDEX 1 00016 enum Fc_type 00017 { FC_ABS, FC_FRAC, FC_FULL }; 00018 00019 /** This identifies the t_type_ptr of an IO block */ 00020 static t_type_ptr IO_TYPE = NULL; 00021 00022 /** This identifies the t_type_ptr of an Empty block */ 00023 static t_type_ptr EMPTY_TYPE = NULL; 00024 00025 /*& This identifies the t_type_ptr of the default logic block */ 00026 static t_type_ptr FILL_TYPE = NULL; 00027 00028 /** Describes the different types of CLBs available */ 00029 static struct s_type_descriptor *type_descriptors; 00030 00031 /* Function prototypes */ 00032 /* Populate data */ 00033 static void ParseFc(ezxml_t Node, 00034 enum Fc_type *Fc, 00035 float *Val); 00036 static void SetupEmptyType(); 00037 static void SetupPinLocationsAndPinClasses(ezxml_t Locations, 00038 t_type_descriptor * Type); 00039 static void SetupGridLocations(ezxml_t Locations, 00040 t_type_descriptor * Type); 00041 #if 0 00042 static void SetupTypeTiming(ezxml_t timing, 00043 t_type_descriptor * Type); 00044 #endif 00045 /* Process XML hiearchy */ 00046 static void ProcessPb_Type(INOUTP ezxml_t Parent, 00047 t_pb_type * pb_type, 00048 t_mode * mode); 00049 static void ProcessPb_TypePort(INOUTP ezxml_t Parent, 00050 t_port * port); 00051 static void ProcessPinToPinAnnotations(ezxml_t parent, 00052 t_pin_to_pin_annotation *annotation); 00053 static void ProcessInterconnect(INOUTP ezxml_t Parent, 00054 t_mode * mode); 00055 static void ProcessMode(INOUTP ezxml_t Parent, 00056 t_mode * mode); 00057 static void Process_Fc(ezxml_t Fc_in_node, 00058 ezxml_t Fc_out_node, 00059 t_type_descriptor * Type); 00060 static void ProcessComplexBlockProps(ezxml_t Node, 00061 t_type_descriptor * Type); 00062 static void ProcessChanWidthDistr(INOUTP ezxml_t Node, 00063 OUTP struct s_arch *arch); 00064 static void ProcessChanWidthDistrDir(INOUTP ezxml_t Node, 00065 OUTP t_chan * chan); 00066 static void ProcessModels(INOUTP ezxml_t Node, 00067 OUTP struct s_arch *arch); 00068 static void ProcessLayout(INOUTP ezxml_t Node, 00069 OUTP struct s_arch *arch); 00070 static void ProcessDevice(INOUTP ezxml_t Node, 00071 OUTP struct s_arch *arch, 00072 INP boolean timing_enabled); 00073 static void alloc_and_load_default_child_for_pb_type(INOUTP t_pb_type *pb_type, char *new_name, t_pb_type *copy); 00074 static void ProcessLutClass(INOUTP t_pb_type *lut_pb_type); 00075 static void ProcessMemoryClass(INOUTP t_pb_type *mem_pb_type); 00076 static void ProcessComplexBlocks(INOUTP ezxml_t Node, 00077 OUTP t_type_descriptor ** Types, 00078 OUTP int *NumTypes, 00079 INP boolean timing_enabled); 00080 static void ProcessSwitches(INOUTP ezxml_t Node, 00081 OUTP struct s_switch_inf **Switches, 00082 OUTP int *NumSwitches, 00083 INP boolean timing_enabled); 00084 static void ProcessSegments(INOUTP ezxml_t Parent, 00085 OUTP struct s_segment_inf **Segs, 00086 OUTP int *NumSegs, 00087 INP struct s_switch_inf *Switches, 00088 INP int NumSwitches, 00089 INP boolean timing_enabled); 00090 static void ProcessCB_SB(INOUTP ezxml_t Node, 00091 INOUTP boolean * list, 00092 INP int len); 00093 00094 static void CreateModelLibrary(OUTP struct s_arch *arch); 00095 static void UpdateAndCheckModels(INOUTP struct s_arch *arch); 00096 static void SyncModelsPbTypes(INOUTP struct s_arch *arch, INP t_type_descriptor * Types, INP int NumTypes); 00097 static void AddModelsToPbTypes_rec(INOUTP t_pb_type *pb_type); 00098 static void SyncModelsPbTypes_rec(INOUTP struct s_arch *arch, INP t_pb_type *pb_type); 00099 00100 static void PrintPb_types_rec(INP FILE * Echo, INP const t_pb_type * pb_type, int level); 00101 00102 00103 /** Figures out the Fc type and value for the given node. Unlinks the 00104 * type and value. */ 00105 static void 00106 ParseFc(ezxml_t Node, enum Fc_type *Fc, float *Val) 00107 { 00108 const char *Prop; 00109 00110 Prop = FindProperty(Node, "type", TRUE); 00111 if(0 == strcmp(Prop, "abs")) 00112 { 00113 *Fc = FC_ABS; 00114 } 00115 00116 else if(0 == strcmp(Prop, "frac")) 00117 { 00118 *Fc = FC_FRAC; 00119 } 00120 00121 else if(0 == strcmp(Prop, "full")) 00122 { 00123 *Fc = FC_FULL; 00124 } 00125 00126 else 00127 { 00128 printf(ERRTAG "[LINE %d] Invalid type '%s' for Fc. Only abs, frac " 00129 "and full are allowed.\n", Node->line, Prop); 00130 exit(1); 00131 } 00132 switch (*Fc) 00133 { 00134 case FC_FULL: 00135 *Val = 0.0; 00136 break; 00137 case FC_ABS: 00138 case FC_FRAC: 00139 *Val = atof(Node->txt); 00140 ezxml_set_attr(Node, "type", NULL); 00141 ezxml_set_txt(Node, ""); 00142 break; 00143 default: 00144 assert(0); 00145 } 00146 00147 /* Release the property */ 00148 ezxml_set_attr(Node, "type", NULL); 00149 } 00150 00151 /** Sets up the pinloc map and pin classes for the type. Unlinks the loc nodes 00152 * from the XML tree. 00153 * Pins and pin classses must already be setup by SetupPinClasses 00154 */ 00155 static void 00156 SetupPinLocationsAndPinClasses(ezxml_t Locations, t_type_descriptor * Type) 00157 { 00158 int i, j, k, PinsPerSubtile, Count, Len; 00159 int capacity, pin_count; 00160 int num_class; 00161 const char * Prop; 00162 00163 ezxml_t Cur, Prev; 00164 char **Tokens, **CurTokens; 00165 00166 capacity = Type->capacity; 00167 00168 PinsPerSubtile = Type->num_pins / Type->capacity; 00169 00170 Prop = FindProperty(Locations, "pattern", TRUE); 00171 if(strcmp(Prop, "spread") == 0) { 00172 Type->pin_location_distribution = E_SPREAD_PIN_DISTR; 00173 } else if (strcmp(Prop,"custom") == 0) { 00174 Type->pin_location_distribution = E_CUSTOM_PIN_DISTR; 00175 } else { 00176 printf(ERRTAG "[LINE %d] %s is an invalid pin location pattern.\n", Locations->line, Prop); 00177 exit(1); 00178 } 00179 ezxml_set_attr(Locations, "pattern", NULL); 00180 00181 /* Alloc and clear pin locations */ 00182 Type->pinloc = (int ***)my_malloc(Type->height * sizeof(int **)); 00183 Type->pin_height = (int *)my_calloc(Type->num_pins, sizeof(int)); 00184 for(i = 0; i < Type->height; ++i) 00185 { 00186 Type->pinloc[i] = (int **)my_malloc(4 * sizeof(int *)); 00187 for(j = 0; j < 4; ++j) 00188 { 00189 Type->pinloc[i][j] = 00190 (int *)my_malloc(Type->num_pins * sizeof(int)); 00191 for(k = 0; k < Type->num_pins; ++k) 00192 { 00193 Type->pinloc[i][j][k] = 0; 00194 } 00195 } 00196 } 00197 00198 Type->pin_loc_assignments = (char****) my_malloc(Type->height * sizeof(char***)); 00199 Type->num_pin_loc_assignments = (int**) my_malloc(Type->height * sizeof(int*)); 00200 for(i = 0; i < Type->height; i++) { 00201 Type->pin_loc_assignments[i] = (char***) my_calloc(4, sizeof(char**)); 00202 Type->num_pin_loc_assignments[i] = (int*) my_calloc(4, sizeof(int)); 00203 } 00204 00205 /* Load the pin locations */ 00206 if(Type->pin_location_distribution == E_CUSTOM_PIN_DISTR) { 00207 Cur = Locations->child; 00208 while(Cur) 00209 { 00210 CheckElement(Cur, "loc"); 00211 00212 /* Get offset */ 00213 i = GetIntProperty(Cur, "offset", FALSE, 0); 00214 if((i < 0) || (i >= Type->height)) 00215 { 00216 printf(ERRTAG 00217 "[LINE %d] %d is an invalid offset for type '%s'.\n", Cur->line, 00218 i, Type->name); 00219 exit(1); 00220 } 00221 00222 /* Get side */ 00223 Prop = FindProperty(Cur, "side", TRUE); 00224 if(0 == strcmp(Prop, "left")) 00225 { 00226 j = LEFT; 00227 } 00228 00229 else if(0 == strcmp(Prop, "top")) 00230 { 00231 j = TOP; 00232 } 00233 00234 else if(0 == strcmp(Prop, "right")) 00235 { 00236 j = RIGHT; 00237 } 00238 00239 else if(0 == strcmp(Prop, "bottom")) 00240 { 00241 j = BOTTOM; 00242 } 00243 00244 else 00245 { 00246 printf(ERRTAG "[LINE %d] '%s' is not a valid side.\n", Cur->line, Prop); 00247 exit(1); 00248 } 00249 ezxml_set_attr(Cur, "side", NULL); 00250 00251 /* Check location is on perimeter */ 00252 if((TOP == j) && (i != (Type->height - 1))) 00253 { 00254 printf(ERRTAG 00255 "[LINE %d] Locations are only allowed on large block " 00256 "perimeter. 'top' side should be at offset %d only.\n", Cur->line, 00257 (Type->height - 1)); 00258 exit(1); 00259 } 00260 if((BOTTOM == j) && (i != 0)) 00261 { 00262 printf(ERRTAG 00263 "[LINE %d] Locations are only allowed on large block " 00264 "perimeter. 'bottom' side should be at offset 0 only.\n", Cur->line); 00265 exit(1); 00266 } 00267 00268 /* Go through lists of pins */ 00269 CountTokensInString(Cur->txt, &Count, &Len); 00270 Type->num_pin_loc_assignments[i][j] = Count; 00271 if(Count > 0) 00272 { 00273 Tokens = GetNodeTokens(Cur); 00274 CurTokens = Tokens; 00275 Type->pin_loc_assignments[i][j] = (char**) my_calloc(Count, sizeof(char*)); 00276 for(k = 0; k < Count; k++) { 00277 /* Store location assignment */ 00278 Type->pin_loc_assignments[i][j][k] = my_strdup(*CurTokens); 00279 00280 /* Advance through list of pins in this location */ 00281 ++CurTokens; 00282 } 00283 FreeTokens(&Tokens); 00284 } 00285 Prev = Cur; 00286 Cur = Cur->next; 00287 FreeNode(Prev); 00288 } 00289 } 00290 00291 /* Setup pin classes */ 00292 num_class = 0; 00293 for(i = 0; i < Type->pb_type->num_ports; i++) { 00294 if(Type->pb_type->ports[i].equivalent) { 00295 num_class += capacity; 00296 } else { 00297 num_class += capacity * Type->pb_type->ports[i].num_pins; 00298 } 00299 } 00300 Type->class_inf = my_calloc(num_class, sizeof(struct s_class)); 00301 Type->num_class = num_class; 00302 Type->pin_class = my_malloc(Type->num_pins * sizeof(int) * capacity); 00303 Type->is_global_pin = my_malloc(Type->num_pins * sizeof(boolean) * capacity); 00304 for(i = 0; i < Type->num_pins * capacity; i++) { 00305 Type->pin_class[i] = OPEN; 00306 Type->is_global_pin[i] = OPEN; 00307 } 00308 00309 pin_count = 0; 00310 00311 /* Equivalent pins share the same class, non-equivalent pins belong to different pin classes */ 00312 num_class = 0; 00313 for(i = 0; i < capacity; ++i) 00314 { 00315 for(j = 0; j < Type->pb_type->num_ports; ++j) 00316 { 00317 if(Type->pb_type->ports[j].equivalent) { 00318 Type->class_inf[num_class].num_pins = Type->pb_type->ports[j].num_pins; 00319 Type->class_inf[num_class].pinlist = 00320 (int *)my_malloc(sizeof(int) * Type->pb_type->ports[j].num_pins); 00321 } 00322 00323 for(k = 0; k < Type->pb_type->ports[j].num_pins; ++k) 00324 { 00325 if(!Type->pb_type->ports[j].equivalent) { 00326 Type->class_inf[num_class].num_pins = 1; 00327 Type->class_inf[num_class].pinlist = (int *)my_malloc(sizeof(int) * 1); 00328 Type->class_inf[num_class].pinlist[0] = pin_count; 00329 } else { 00330 Type->class_inf[num_class].pinlist[k] = pin_count; 00331 } 00332 00333 if(Type->pb_type->ports[j].type == IN_PORT) { 00334 Type->class_inf[num_class].type = RECEIVER; 00335 } else { 00336 assert(Type->pb_type->ports[j].type == OUT_PORT); 00337 Type->class_inf[num_class].type = DRIVER; 00338 } 00339 Type->pin_class[pin_count] = num_class; 00340 Type->is_global_pin[pin_count] = Type->pb_type->ports[j].is_clock; 00341 pin_count++; 00342 00343 if(!Type->pb_type->ports[j].equivalent) { 00344 num_class++; 00345 } 00346 } 00347 if(Type->pb_type->ports[j].equivalent) { 00348 num_class++; 00349 } 00350 } 00351 } 00352 assert(num_class == Type->num_class); 00353 assert(pin_count == Type->num_pins); 00354 } 00355 00356 /** Sets up the grid_loc_def for the type. Unlinks the loc nodes 00357 * from the XML tree. 00358 */ 00359 static void 00360 SetupGridLocations(ezxml_t Locations, t_type_descriptor * Type) 00361 { 00362 int i; 00363 00364 ezxml_t Cur, Prev; 00365 const char *Prop; 00366 00367 Type->num_grid_loc_def = CountChildren(Locations, "loc", 1); 00368 Type->grid_loc_def = 00369 (struct s_grid_loc_def *)my_calloc(Type->num_grid_loc_def, 00370 sizeof(struct s_grid_loc_def)); 00371 00372 /* Load the pin locations */ 00373 Cur = Locations->child; 00374 i = 0; 00375 while(Cur) 00376 { 00377 CheckElement(Cur, "loc"); 00378 00379 /* loc index */ 00380 Prop = FindProperty(Cur, "type", TRUE); 00381 if(Prop) 00382 { 00383 if(strcmp(Prop, "perimeter") == 0) 00384 { 00385 if(Type->num_grid_loc_def != 1) 00386 { 00387 printf(ERRTAG 00388 "[LINE %d] Another loc specified for perimeter.\n", Cur->line); 00389 exit(1); 00390 } 00391 Type->grid_loc_def[i].grid_loc_type = BOUNDARY; 00392 assert(IO_TYPE == Type); /* IO goes to boundary */ 00393 } else if(strcmp(Prop, "fill") == 0) 00394 { 00395 if(Type->num_grid_loc_def != 1 || FILL_TYPE != NULL) 00396 { 00397 printf(ERRTAG 00398 "[LINE %d] Another loc specified for fill.\n", Cur->line); 00399 exit(1); 00400 } 00401 Type->grid_loc_def[i].grid_loc_type = FILL; 00402 FILL_TYPE = Type; 00403 } 00404 else if(strcmp(Prop, "col") == 0) 00405 { 00406 Type->grid_loc_def[i].grid_loc_type = COL_REPEAT; 00407 } 00408 else if(strcmp(Prop, "rel") == 0) 00409 { 00410 Type->grid_loc_def[i].grid_loc_type = COL_REL; 00411 } 00412 else 00413 { 00414 printf(ERRTAG 00415 "[LINE %d] Unknown grid location type '%s' for type '%s'.\n", Cur->line, 00416 Prop, Type->name); 00417 exit(1); 00418 } 00419 ezxml_set_attr(Cur, "type", NULL); 00420 } 00421 Prop = FindProperty(Cur, "start", FALSE); 00422 if(Type->grid_loc_def[i].grid_loc_type == COL_REPEAT) 00423 { 00424 if(Prop == NULL) 00425 { 00426 printf(ERRTAG 00427 "[LINE %d] grid location property 'start' must be specified for grid location type 'col'.\n", 00428 Cur->line); 00429 exit(1); 00430 } 00431 Type->grid_loc_def[i].start_col = my_atoi(Prop); 00432 ezxml_set_attr(Cur, "start", NULL); 00433 } 00434 else if(Prop != NULL) 00435 { 00436 printf(ERRTAG 00437 "[LINE %d] grid location property 'start' valid for grid location type 'col' only.\n", 00438 Cur->line); 00439 exit(1); 00440 } 00441 Prop = FindProperty(Cur, "repeat", FALSE); 00442 if(Type->grid_loc_def[i].grid_loc_type == COL_REPEAT) 00443 { 00444 if(Prop != NULL) 00445 { 00446 Type->grid_loc_def[i].repeat = my_atoi(Prop); 00447 ezxml_set_attr(Cur, "repeat", NULL); 00448 } 00449 } 00450 else if(Prop != NULL) 00451 { 00452 printf(ERRTAG 00453 "[LINE %d] grid location property 'repeat' valid for grid location type 'col' only.\n", 00454 Cur->line); 00455 exit(1); 00456 } 00457 Prop = FindProperty(Cur, "pos", FALSE); 00458 if(Type->grid_loc_def[i].grid_loc_type == COL_REL) 00459 { 00460 if(Prop == NULL) 00461 { 00462 printf(ERRTAG 00463 "[LINE %d] grid location property 'pos' must be specified for grid location type 'rel'.\n", 00464 Cur->line); 00465 exit(1); 00466 } 00467 Type->grid_loc_def[i].col_rel = atof(Prop); 00468 ezxml_set_attr(Cur, "pos", NULL); 00469 } 00470 else if(Prop != NULL) 00471 { 00472 printf(ERRTAG 00473 "[LINE %d] grid location property 'pos' valid for grid location type 'rel' only.\n", 00474 Cur->line); 00475 exit(1); 00476 } 00477 00478 Type->grid_loc_def[i].priority = GetIntProperty(Cur, "priority", FALSE, 1); 00479 00480 Prev = Cur; 00481 Cur = Cur->next; 00482 FreeNode(Prev); 00483 i++; 00484 } 00485 } 00486 00487 static void 00488 ProcessPinToPinAnnotations(ezxml_t Parent, t_pin_to_pin_annotation *annotation) 00489 { 00490 int i = 0; 00491 const char *Prop; 00492 00493 if(FindProperty(Parent, "max", FALSE)) { 00494 i++; 00495 } 00496 if(FindProperty(Parent, "min", FALSE)) { 00497 i++; 00498 } 00499 if(FindProperty(Parent, "type", FALSE)) { 00500 i++; 00501 } 00502 if(FindProperty(Parent, "value", FALSE)) { 00503 i++; 00504 } 00505 if(0 == strcmp(Parent->name, "C_constant") || 0 == strcmp(Parent->name, "C_matrix")) { 00506 i = 1; 00507 } 00508 00509 annotation->num_value_prop_pairs = i; 00510 annotation->prop = my_calloc(i, sizeof(int)); 00511 annotation->value = my_calloc(i, sizeof(char *)); 00512 00513 i = 0; 00514 if(0 == strcmp(Parent->name, "delay_constant")) { 00515 annotation->type = (int) E_ANNOT_PIN_TO_PIN_DELAY; 00516 annotation->format = E_ANNOT_PIN_TO_PIN_CONSTANT; 00517 Prop = FindProperty(Parent, "max", FALSE); 00518 if(Prop) { 00519 annotation->prop[i] = (int) E_ANNOT_PIN_TO_PIN_DELAY_MAX; 00520 annotation->value[i] = my_strdup(Prop); 00521 ezxml_set_attr(Parent, "max", NULL); 00522 i++; 00523 } 00524 Prop = FindProperty(Parent, "min", FALSE); 00525 if(Prop) { 00526 annotation->prop[i] = (int) E_ANNOT_PIN_TO_PIN_DELAY_MIN; 00527 annotation->value[i] = my_strdup(Prop); 00528 ezxml_set_attr(Parent, "min", NULL); 00529 i++; 00530 } 00531 Prop = FindProperty(Parent, "in_port", TRUE); 00532 annotation->input_pins = my_strdup(Prop); 00533 ezxml_set_attr(Parent, "in_port", NULL); 00534 Prop = FindProperty(Parent, "out_port", TRUE); 00535 annotation->output_pins = my_strdup(Prop); 00536 ezxml_set_attr(Parent, "out_port", NULL); 00537 } else if (0 == strcmp(Parent->name, "delay_matrix")) { 00538 annotation->type = (int) E_ANNOT_PIN_TO_PIN_DELAY; 00539 annotation->format = E_ANNOT_PIN_TO_PIN_MATRIX; 00540 Prop = FindProperty(Parent, "type", TRUE); 00541 annotation->value[i] = my_strdup(Parent->txt); 00542 ezxml_set_txt(Parent, ""); 00543 if(0 == strcmp(Prop, "max")) { 00544 annotation->prop[i] = (int) E_ANNOT_PIN_TO_PIN_DELAY_MAX; 00545 } else { 00546 assert(0 == strcmp(Prop, "min")); 00547 annotation->prop[i] = (int) E_ANNOT_PIN_TO_PIN_DELAY_MIN; 00548 } 00549 ezxml_set_attr(Parent, "type", NULL); 00550 i++; 00551 Prop = FindProperty(Parent, "in_port", TRUE); 00552 annotation->input_pins = my_strdup(Prop); 00553 ezxml_set_attr(Parent, "in_port", NULL); 00554 Prop = FindProperty(Parent, "out_port", TRUE); 00555 annotation->output_pins = my_strdup(Prop); 00556 ezxml_set_attr(Parent, "out_port", NULL); 00557 } else if (0 == strcmp(Parent->name, "C_constant")) { 00558 annotation->type = (int) E_ANNOT_PIN_TO_PIN_CAPACITANCE; 00559 annotation->format = E_ANNOT_PIN_TO_PIN_CONSTANT; 00560 Prop = FindProperty(Parent, "C", TRUE); 00561 annotation->value[i] = my_strdup(Prop); 00562 ezxml_set_attr(Parent, "C", NULL); 00563 annotation->prop[i] = (int) E_ANNOT_PIN_TO_PIN_CAPACITANCE_C; 00564 i++; 00565 00566 Prop = FindProperty(Parent, "in_port", FALSE); 00567 annotation->input_pins = my_strdup(Prop); 00568 ezxml_set_attr(Parent, "in_port", NULL); 00569 Prop = FindProperty(Parent, "out_port", FALSE); 00570 annotation->output_pins = my_strdup(Prop); 00571 ezxml_set_attr(Parent, "out_port", NULL); 00572 assert(annotation->output_pins != NULL || annotation->input_pins != NULL); 00573 } else if (0 == strcmp(Parent->name, "C_matrix")) { 00574 annotation->type = (int) E_ANNOT_PIN_TO_PIN_CAPACITANCE; 00575 annotation->format = E_ANNOT_PIN_TO_PIN_MATRIX; 00576 annotation->value[i] = my_strdup(Parent->txt); 00577 ezxml_set_txt(Parent, ""); 00578 annotation->prop[i] = (int) E_ANNOT_PIN_TO_PIN_CAPACITANCE_C; 00579 i++; 00580 Prop = FindProperty(Parent, "in_port", FALSE); 00581 annotation->input_pins = my_strdup(Prop); 00582 ezxml_set_attr(Parent, "in_port", NULL); 00583 Prop = FindProperty(Parent, "out_port", FALSE); 00584 annotation->output_pins = my_strdup(Prop); 00585 ezxml_set_attr(Parent, "out_port", NULL); 00586 assert(annotation->output_pins != NULL || annotation->input_pins != NULL); 00587 } else if (0 == strcmp(Parent->name, "T_setup")) { 00588 annotation->type = (int) E_ANNOT_PIN_TO_PIN_DELAY; 00589 annotation->format = E_ANNOT_PIN_TO_PIN_CONSTANT; 00590 Prop = FindProperty(Parent, "value", TRUE); 00591 annotation->prop[i] = (int) E_ANNOT_PIN_TO_PIN_DELAY_TSETUP; 00592 annotation->value[i] = my_strdup(Prop); 00593 ezxml_set_attr(Parent, "value", NULL); 00594 i++; 00595 Prop = FindProperty(Parent, "port", TRUE); 00596 annotation->input_pins = my_strdup(Prop); 00597 ezxml_set_attr(Parent, "port", NULL); 00598 Prop = FindProperty(Parent, "clock", TRUE); 00599 annotation->clock = my_strdup(Prop); 00600 ezxml_set_attr(Parent, "clock", NULL); 00601 } else if (0 == strcmp(Parent->name, "T_clock_to_Q")) { 00602 annotation->type = (int) E_ANNOT_PIN_TO_PIN_DELAY; 00603 annotation->format = E_ANNOT_PIN_TO_PIN_CONSTANT; 00604 Prop = FindProperty(Parent, "max", FALSE); 00605 if(Prop) { 00606 annotation->prop[i] = (int) E_ANNOT_PIN_TO_PIN_DELAY_CLOCK_TO_Q_MAX; 00607 annotation->value[i] = my_strdup(Prop); 00608 ezxml_set_attr(Parent, "max", NULL); 00609 i++; 00610 } 00611 Prop = FindProperty(Parent, "min", FALSE); 00612 if(Prop) { 00613 annotation->prop[i] = (int) E_ANNOT_PIN_TO_PIN_DELAY_CLOCK_TO_Q_MIN; 00614 annotation->value[i] = my_strdup(Prop); 00615 ezxml_set_attr(Parent, "min", NULL); 00616 i++; 00617 } 00618 00619 Prop = FindProperty(Parent, "port", TRUE); 00620 annotation->input_pins = my_strdup(Prop); 00621 ezxml_set_attr(Parent, "port", NULL); 00622 Prop = FindProperty(Parent, "clock", TRUE); 00623 annotation->clock = my_strdup(Prop); 00624 ezxml_set_attr(Parent, "clock", NULL); 00625 } else if (0 == strcmp(Parent->name, "T_hold")) { 00626 annotation->type = (int) E_ANNOT_PIN_TO_PIN_DELAY; 00627 annotation->format = E_ANNOT_PIN_TO_PIN_CONSTANT; 00628 Prop = FindProperty(Parent, "value", TRUE); 00629 annotation->prop[i] = (int) E_ANNOT_PIN_TO_PIN_DELAY_THOLD; 00630 annotation->value[i] = my_strdup(Prop); 00631 ezxml_set_attr(Parent, "value", NULL); 00632 i++; 00633 00634 Prop = FindProperty(Parent, "port", TRUE); 00635 annotation->input_pins = my_strdup(Prop); 00636 ezxml_set_attr(Parent, "port", NULL); 00637 Prop = FindProperty(Parent, "clock", TRUE); 00638 annotation->clock = my_strdup(Prop); 00639 ezxml_set_attr(Parent, "clock", NULL); 00640 } else { 00641 printf(ERRTAG "[LINE %d] Unknown port type %s in %s in %s", Parent->line, 00642 Parent->name, Parent->parent->name, Parent->parent->parent->name); 00643 exit(1); 00644 } 00645 assert (i == annotation->num_value_prop_pairs); 00646 } 00647 00648 /** Takes in a pb_type, allocates and loads data for it and recurses downwards */ 00649 static void ProcessPb_Type(INOUTP ezxml_t Parent, 00650 t_pb_type * pb_type, 00651 t_mode * mode) { 00652 int num_ports, i, j, num_annotations; 00653 const char *Prop; 00654 ezxml_t Cur, Prev; 00655 char* class_name; 00656 00657 pb_type->parent_mode = mode; 00658 if(mode != NULL && mode->parent_pb_type != NULL) { 00659 pb_type->depth = mode->parent_pb_type->depth + 1; 00660 Prop = FindProperty(Parent, "name", TRUE); 00661 pb_type->name = my_strdup(Prop); 00662 ezxml_set_attr(Parent, "name", NULL); 00663 } else { 00664 pb_type->depth = 0; 00665 /* same name as type */ 00666 } 00667 00668 Prop = FindProperty(Parent, "blif_model", FALSE); 00669 pb_type->blif_model = my_strdup(Prop); 00670 ezxml_set_attr(Parent, "blif_model", NULL); 00671 00672 pb_type->class_type = UNKNOWN_CLASS; 00673 Prop = FindProperty(Parent, "class", FALSE); 00674 class_name = my_strdup(Prop); 00675 00676 if(class_name) { 00677 ezxml_set_attr(Parent, "class", NULL); 00678 if(0 == strcmp(class_name, "lut")) { 00679 pb_type->class_type = LUT_CLASS; 00680 } else if(0 == strcmp(class_name, "flipflop")) { 00681 pb_type->class_type = LATCH_CLASS; 00682 } else if(0 == strcmp(class_name, "memory")) { 00683 pb_type->class_type = MEMORY_CLASS; 00684 } else { 00685 printf("[LINE %d] Unknown class %s in pb_type %s\n", Parent->line, class_name, pb_type->name); 00686 exit(1); 00687 } 00688 free(class_name); 00689 } 00690 00691 if(mode == NULL) { 00692 pb_type->num_pb = 1; 00693 } else { 00694 pb_type->num_pb = GetIntProperty(Parent, "num_pb", TRUE, 0); 00695 } 00696 00697 assert(pb_type->num_pb > 0); 00698 num_ports = 0; 00699 num_ports += CountChildren(Parent, "input", 0); 00700 num_ports += CountChildren(Parent, "output", 0); 00701 num_ports += CountChildren(Parent, "clock", 0); 00702 pb_type->ports = my_calloc(num_ports, sizeof(t_port)); 00703 pb_type->num_ports = num_ports; 00704 00705 /* process ports */ 00706 j = 0; 00707 for(i = 0; i < 3; i++) { 00708 if(i == 0) { 00709 Cur = FindFirstElement(Parent, "input", FALSE); 00710 } else if (i ==1) { 00711 Cur = FindFirstElement(Parent, "output", FALSE); 00712 } else { 00713 Cur = FindFirstElement(Parent, "clock", FALSE); 00714 } 00715 while (Cur != NULL) 00716 { 00717 ProcessPb_TypePort(Cur, &pb_type->ports[j]); 00718 pb_type->ports[j].parent_pb_type = pb_type; 00719 00720 /* get next iteration */ 00721 Prev = Cur; 00722 Cur = Cur->next; 00723 j++; 00724 FreeNode(Prev); 00725 } 00726 } 00727 assert(j == num_ports); 00728 00729 /* Count stats on the number of each type of pin */ 00730 pb_type->num_clock_pins = pb_type->num_input_pins = pb_type->num_output_pins = 0; 00731 for(i = 0; i < pb_type->num_ports; i++) { 00732 if(pb_type->ports[i].type == IN_PORT && pb_type->ports[i].is_clock == FALSE) { 00733 pb_type->num_input_pins += pb_type->ports[i].num_pins; 00734 } else if(pb_type->ports[i].type == OUT_PORT) { 00735 assert(pb_type->ports[i].is_clock == FALSE); 00736 pb_type->num_output_pins += pb_type->ports[i].num_pins; 00737 } else { 00738 assert(pb_type->ports[i].is_clock && pb_type->ports[i].type == IN_PORT); 00739 pb_type->num_clock_pins += pb_type->ports[i].num_pins; 00740 } 00741 } 00742 00743 /* set max_internal_delay if exist */ 00744 pb_type->max_internal_delay = UNDEFINED; 00745 Cur = FindElement(Parent, "max_internal_delay", FALSE); 00746 if(Cur) { 00747 pb_type->max_internal_delay = GetFloatProperty(Cur, "value", TRUE, UNDEFINED); 00748 FreeNode(Cur); 00749 } 00750 00751 pb_type->annotations = NULL; 00752 pb_type->num_annotations = 0; 00753 i = 0; 00754 /* Determine if this is a leaf or container pb_type */ 00755 if(pb_type->blif_model != NULL) { 00756 /* Process delay and capacitance annotations */ 00757 num_annotations = 0; 00758 num_annotations += CountChildren(Parent, "delay_constant", 0); 00759 num_annotations += CountChildren(Parent, "delay_matrix", 0); 00760 num_annotations += CountChildren(Parent, "C_constant", 0); 00761 num_annotations += CountChildren(Parent, "C_matrix", 0); 00762 num_annotations += CountChildren(Parent, "T_setup", 0); 00763 num_annotations += CountChildren(Parent, "T_clock_to_Q", 0); 00764 num_annotations += CountChildren(Parent, "T_hold", 0); 00765 00766 pb_type->annotations = my_calloc(num_annotations, sizeof(t_pin_to_pin_annotation)); 00767 pb_type->num_annotations = num_annotations; 00768 00769 j = 0; 00770 Cur = NULL; 00771 for(i = 0; i < 7; i++) { 00772 if(i == 0) { 00773 Cur = FindFirstElement(Parent, "delay_constant", FALSE); 00774 } else if (i == 1) { 00775 Cur = FindFirstElement(Parent, "delay_matrix", FALSE); 00776 } else if (i == 2) { 00777 Cur = FindFirstElement(Parent, "C_constant", FALSE); 00778 } else if (i == 3) { 00779 Cur = FindFirstElement(Parent, "C_matrix", FALSE); 00780 } else if (i == 4) { 00781 Cur = FindFirstElement(Parent, "T_setup", FALSE); 00782 } else if (i == 5) { 00783 Cur = FindFirstElement(Parent, "T_clock_to_Q", FALSE); 00784 } else if (i == 6) { 00785 Cur = FindFirstElement(Parent, "T_hold", FALSE); 00786 } 00787 while (Cur != NULL) 00788 { 00789 ProcessPinToPinAnnotations(Cur, &pb_type->annotations[j]); 00790 00791 /* get next iteration */ 00792 Prev = Cur; 00793 Cur = Cur->next; 00794 j++; 00795 FreeNode(Prev); 00796 } 00797 } 00798 assert(j == num_annotations); 00799 00800 /* leaf pb_type, if special known class, then read class lib otherwise treat as primitive */ 00801 if(pb_type->class_type == LUT_CLASS) { 00802 ProcessLutClass(pb_type); 00803 } else if(pb_type->class_type == MEMORY_CLASS) { 00804 ProcessMemoryClass(pb_type); 00805 } else { 00806 /* other leaf pb_type do not have modes */ 00807 pb_type->num_modes = 0; 00808 assert(CountChildren(Parent, "mode", 0) == 0); 00809 } 00810 } else { 00811 /* container pb_type, process modes */ 00812 assert(pb_type->class_type == UNKNOWN_CLASS); 00813 pb_type->num_modes = CountChildren(Parent, "mode", 0); 00814 00815 if(pb_type->num_modes == 0) { 00816 /* The pb_type operates in an implied one mode */ 00817 pb_type->num_modes = 1; 00818 pb_type->modes = my_calloc(pb_type->num_modes, sizeof(t_mode)); 00819 pb_type->modes[i].parent_pb_type = pb_type; 00820 pb_type->modes[i].index = i; 00821 ProcessMode(Parent, &pb_type->modes[i]); 00822 i++; 00823 } else { 00824 pb_type->modes = my_calloc(pb_type->num_modes, sizeof(t_mode)); 00825 00826 Cur = FindFirstElement(Parent, "mode", TRUE); 00827 while (Cur != NULL) 00828 { 00829 if(0 == strcmp(Cur->name, "mode")) { 00830 pb_type->modes[i].parent_pb_type = pb_type; 00831 ProcessMode(Cur, &pb_type->modes[i]); 00832 00833 /* get next iteration */ 00834 Prev = Cur; 00835 Cur = Cur->next; 00836 i++; 00837 FreeNode(Prev); 00838 } 00839 } 00840 } 00841 assert(i == pb_type->num_modes); 00842 } 00843 } 00844 00845 static void ProcessPb_TypePort(INOUTP ezxml_t Parent, 00846 t_port * port) { 00847 const char *Prop; 00848 Prop = FindProperty(Parent, "name", TRUE); 00849 port->name = my_strdup(Prop); 00850 ezxml_set_attr(Parent, "name", NULL); 00851 00852 Prop = FindProperty(Parent, "port_class", FALSE); 00853 port->port_class = my_strdup(Prop); 00854 ezxml_set_attr(Parent, "port_class", NULL); 00855 00856 port->equivalent = GetBooleanProperty(Parent, "equivalent", FALSE, FALSE); 00857 port->num_pins = GetIntProperty(Parent, "num_pins", TRUE, 0); 00858 00859 if(0 == strcmp(Parent->name, "input")) { 00860 port->type = IN_PORT; 00861 port->is_clock = FALSE; 00862 } else if (0 == strcmp(Parent->name, "output")) { 00863 port->type = OUT_PORT; 00864 port->is_clock = FALSE; 00865 } else if (0 == strcmp(Parent->name, "clock")) { 00866 port->type = IN_PORT; 00867 port->is_clock = TRUE; 00868 } else { 00869 printf(ERRTAG "[LINE %d] Unknown port type %s", Parent->line, Parent->name); 00870 exit(1); 00871 } 00872 } 00873 00874 static void ProcessInterconnect(INOUTP ezxml_t Parent, 00875 t_mode * mode) { 00876 int num_interconnect = 0; 00877 int i, j, k, index, num_annotations; 00878 const char *Prop; 00879 ezxml_t Cur, Prev; 00880 ezxml_t Cur2, Prev2; 00881 00882 num_interconnect += CountChildren(Parent, "complete", 0); 00883 num_interconnect += CountChildren(Parent, "direct", 0); 00884 num_interconnect += CountChildren(Parent, "mux", 0); 00885 00886 mode->num_interconnect = num_interconnect; 00887 mode->interconnect = my_calloc(num_interconnect, sizeof(t_interconnect)); 00888 00889 i = 0; 00890 for(index = 0; index < 3; index++) { 00891 if(index == 0) { 00892 Cur = FindFirstElement(Parent, "complete", FALSE); 00893 } else if (index == 1) { 00894 Cur = FindFirstElement(Parent, "direct", FALSE); 00895 } else { 00896 Cur = FindFirstElement(Parent, "mux", FALSE); 00897 } 00898 while (Cur != NULL) 00899 { 00900 if(0 == strcmp(Cur->name, "complete")) { 00901 mode->interconnect[i].type = COMPLETE_INTERC; 00902 } else if(0 == strcmp(Cur->name, "direct")) { 00903 mode->interconnect[i].type = DIRECT_INTERC; 00904 } else { 00905 assert(0 == strcmp(Cur->name, "mux")); 00906 mode->interconnect[i].type = MUX_INTERC; 00907 } 00908 00909 mode->interconnect[i].parent_mode_index = mode->index; 00910 Prop = FindProperty(Cur, "input", TRUE); 00911 mode->interconnect[i].input_string = my_strdup(Prop); 00912 ezxml_set_attr(Cur, "input", NULL); 00913 00914 Prop = FindProperty(Cur, "output", TRUE); 00915 mode->interconnect[i].output_string = my_strdup(Prop); 00916 ezxml_set_attr(Cur, "output", NULL); 00917 00918 Prop = FindProperty(Cur, "name", TRUE); 00919 mode->interconnect[i].name = my_strdup(Prop); 00920 ezxml_set_attr(Cur, "name", NULL); 00921 00922 /* Process delay and capacitance annotations */ 00923 num_annotations = 0; 00924 num_annotations += CountChildren(Cur, "delay_constant", 0); 00925 num_annotations += CountChildren(Cur, "delay_matrix", 0); 00926 num_annotations += CountChildren(Cur, "C_constant", 0); 00927 num_annotations += CountChildren(Cur, "C_matrix", 0); 00928 00929 mode->interconnect[i].annotations = my_calloc(num_annotations, sizeof(t_pin_to_pin_annotation)); 00930 mode->interconnect[i].num_annotations = num_annotations; 00931 00932 k = 0; 00933 Cur2 = NULL; 00934 for(j = 0; j < 4; j++) { 00935 if(j == 0) { 00936 Cur2 = FindFirstElement(Cur, "delay_constant", FALSE); 00937 } else if (j == 1) { 00938 Cur2 = FindFirstElement(Cur, "delay_matrix", FALSE); 00939 } else if (j == 2) { 00940 Cur2 = FindFirstElement(Cur, "C_constant", FALSE); 00941 } else if (j == 3) { 00942 Cur2 = FindFirstElement(Cur, "C_matrix", FALSE); 00943 } 00944 while (Cur2 != NULL) 00945 { 00946 ProcessPinToPinAnnotations(Cur2, &(mode->interconnect[i].annotations[k])); 00947 00948 /* get next iteration */ 00949 Prev2 = Cur2; 00950 Cur2 = Cur2->next; 00951 k++; 00952 FreeNode(Prev2); 00953 } 00954 } 00955 assert(k == num_annotations); 00956 00957 /* get next iteration */ 00958 Prev = Cur; 00959 Cur = Cur->next; 00960 FreeNode(Prev); 00961 i++; 00962 } 00963 } 00964 00965 assert(i == num_interconnect); 00966 } 00967 00968 static void ProcessMode(INOUTP ezxml_t Parent, 00969 t_mode * mode) { 00970 int i; 00971 const char *Prop; 00972 ezxml_t Cur, Prev; 00973 00974 if(0 == strcmp(Parent->name, "pb_type")) { 00975 /* implied mode */ 00976 mode->name = my_strdup(mode->parent_pb_type->name); 00977 } else { 00978 Prop = FindProperty(Parent, "name", TRUE); 00979 mode->name = my_strdup(Prop); 00980 ezxml_set_attr(Parent, "name", NULL); 00981 } 00982 00983 mode->num_pb_type_children = CountChildren(Parent, "pb_type", 1); 00984 mode->pb_type_children = my_calloc(mode->num_pb_type_children, sizeof(t_pb_type)); 00985 00986 i = 0; 00987 Cur = FindFirstElement(Parent, "pb_type", TRUE); 00988 while (Cur != NULL) 00989 { 00990 if(0 == strcmp(Cur->name, "pb_type")) { 00991 ProcessPb_Type(Cur, &mode->pb_type_children[i], mode); 00992 00993 /* get next iteration */ 00994 Prev = Cur; 00995 Cur = Cur->next; 00996 i++; 00997 FreeNode(Prev); 00998 } 00999 } 01000 01001 Cur = FindElement(Parent, "interconnect", TRUE); 01002 ProcessInterconnect(Cur, mode); 01003 FreeNode(Cur); 01004 } 01005 01006 /** Takes in the node ptr for the 'fc_in' and 'fc_out' elements and initializes 01007 * the appropriate fields of type. Unlinks the contents of the nodes. 01008 */ 01009 static void 01010 Process_Fc(ezxml_t Fc_in_node, ezxml_t Fc_out_node, t_type_descriptor * Type) 01011 { 01012 enum Fc_type Type_in; 01013 enum Fc_type Type_out; 01014 01015 ParseFc(Fc_in_node, &Type_in, &Type->Fc_in); 01016 ParseFc(Fc_out_node, &Type_out, &Type->Fc_out); 01017 if(FC_FULL == Type_in) 01018 { 01019 printf(ERRTAG "[LINE %d] 'full' Fc type isn't allowed for Fc_in.\n", Fc_in_node->line); 01020 exit(1); 01021 } 01022 Type->is_Fc_out_full_flex = FALSE; 01023 Type->is_Fc_frac = FALSE; 01024 if(FC_FULL == Type_out) 01025 { 01026 Type->is_Fc_out_full_flex = TRUE; 01027 } 01028 01029 else if(Type_in != Type_out) 01030 { 01031 printf(ERRTAG 01032 "[LINE %d] Fc_in and Fc_out must have same type unless Fc_out has type 'full'.\n", Fc_in_node->line); 01033 exit(1); 01034 } 01035 if(FC_FRAC == Type_in) 01036 { 01037 Type->is_Fc_frac = TRUE; 01038 } 01039 } 01040 01041 /** This processes attributes of the 'type' tag and then unlinks them */ 01042 static void 01043 ProcessComplexBlockProps(ezxml_t Node, t_type_descriptor * Type) 01044 { 01045 const char *Prop; 01046 01047 /* Load type name */ 01048 Prop = FindProperty(Node, "name", TRUE); 01049 Type->name = my_strdup(Prop); 01050 ezxml_set_attr(Node, "name", NULL); 01051 01052 /* Load properties */ 01053 Type->capacity = GetIntProperty(Node, "capacity", FALSE, 1); /* TODO: Any block with capacity > 1 that is not I/O has not been tested, must test */ 01054 Type->height = GetIntProperty(Node, "height", FALSE, 1); 01055 Type->area = GetFloatProperty(Node, "area", FALSE, UNDEFINED); 01056 01057 01058 if(atof(Prop) < 0) { 01059 printf("[LINE %d] Area for type %s must be non-negative\n", Node->line, Type->name); 01060 exit(1); 01061 } 01062 } 01063 01064 /** Takes in node pointing to <models> and loads all the 01065 * child type objects. Unlinks the entire <models> node 01066 * when complete. 01067 */ 01068 static void 01069 ProcessModels(INOUTP ezxml_t Node, OUTP struct s_arch *arch) 01070 { 01071 const char *Prop; 01072 ezxml_t child; 01073 ezxml_t p; 01074 ezxml_t junk; 01075 ezxml_t junkp; 01076 t_model *temp; 01077 t_model_ports *tp; 01078 int index; 01079 01080 index = NUM_MODELS_IN_LIBRARY; 01081 01082 arch->models = NULL; 01083 child = ezxml_child(Node, "model"); 01084 while (child != NULL) 01085 { 01086 temp = (t_model*)my_calloc(1, sizeof(t_model)); 01087 temp->used = 0; 01088 temp->inputs = temp->outputs = temp->instances = NULL; 01089 Prop = FindProperty(child, "name", TRUE); 01090 temp->name = my_strdup(Prop); 01091 ezxml_set_attr(child, "name", NULL); 01092 temp->pb_types = NULL; 01093 temp->index = index; 01094 index++; 01095 01096 /* Process the inputs */ 01097 p = ezxml_child(child, "input_ports"); 01098 junkp = p; 01099 if (p == NULL) 01100 printf(ERRTAG "Required input ports not found for element '%s'.\n", temp->name); 01101 01102 p = ezxml_child(p, "port"); 01103 if (p != NULL) 01104 { 01105 while (p != NULL) 01106 { 01107 tp = (t_model_ports*)my_calloc(1, sizeof(t_model_ports)); 01108 Prop = FindProperty(p, "name", TRUE); 01109 tp->name = my_strdup(Prop); 01110 ezxml_set_attr(p, "name", NULL); 01111 tp->size = -1; /* determined later by pb_types */ 01112 tp->min_size = -1; /* determined later by pb_types */ 01113 tp->next = temp->inputs; 01114 tp->dir = IN_PORT; 01115 tp->is_clock = FALSE; 01116 Prop = FindProperty(p, "is_clock", FALSE); 01117 if(Prop && my_atoi(Prop) != 0) { 01118 tp->is_clock = TRUE; 01119 } 01120 ezxml_set_attr(p, "is_clock", NULL); 01121 temp->inputs = tp; 01122 junk = p; 01123 p = ezxml_next(p); 01124 FreeNode(junk); 01125 } 01126 } 01127 else /* No input ports? */ 01128 { 01129 printf(ERRTAG "Required input ports not found for element '%s'.\n", temp->name); 01130 } 01131 FreeNode(junkp); 01132 01133 /* Process the outputs */ 01134 p = ezxml_child(child, "output_ports"); 01135 junkp = p; 01136 if (p == NULL) 01137 printf(ERRTAG "Required output ports not found for element '%s'.\n", temp->name); 01138 01139 p = ezxml_child(p, "port"); 01140 if (p != NULL) 01141 { 01142 while (p != NULL) 01143 { 01144 tp = (t_model_ports*)my_calloc(1, sizeof(t_model_ports)); 01145 Prop = FindProperty(p, "name", TRUE); 01146 tp->name = my_strdup(Prop); 01147 ezxml_set_attr(p, "name", NULL); 01148 tp->size = -1; /* determined later by pb_types */ 01149 tp->min_size = -1; /* determined later by pb_types */ 01150 tp->next = temp->outputs; 01151 tp->dir = OUT_PORT; 01152 temp->outputs = tp; 01153 junk = p; 01154 p = ezxml_next(p); 01155 FreeNode(junk); 01156 } 01157 } 01158 else /* No output ports? */ 01159 { 01160 printf(ERRTAG "Required output ports not found for element '%s'.\n", temp->name); 01161 } 01162 FreeNode(junkp); 01163 01164 /* Find the next model */ 01165 temp->next = arch->models; 01166 arch->models = temp; 01167 junk = child; 01168 child = ezxml_next(child); 01169 FreeNode(junk); 01170 } 01171 01172 return; 01173 } 01174 01175 /** Takes in node pointing to <layout> and loads all the 01176 * child type objects. Unlinks the entire <layout> node 01177 * when complete. 01178 */ 01179 static void 01180 ProcessLayout(INOUTP ezxml_t Node, OUTP struct s_arch *arch) 01181 { 01182 const char *Prop; 01183 01184 arch->clb_grid.IsAuto = TRUE; 01185 01186 /* Load width and height if applicable */ 01187 Prop = FindProperty(Node, "width", FALSE); 01188 if(Prop != NULL) 01189 { 01190 arch->clb_grid.IsAuto = FALSE; 01191 arch->clb_grid.W = my_atoi(Prop); 01192 ezxml_set_attr(Node, "width", NULL); 01193 01194 arch->clb_grid.H = GetIntProperty(Node, "height", TRUE, UNDEFINED); 01195 } 01196 01197 /* Load aspect ratio if applicable */ 01198 Prop = FindProperty(Node, "auto", arch->clb_grid.IsAuto); 01199 if(Prop != NULL) 01200 { 01201 if(arch->clb_grid.IsAuto == FALSE) 01202 { 01203 printf(ERRTAG 01204 "Auto-sizing, width and height cannot be specified\n"); 01205 } 01206 arch->clb_grid.Aspect = atof(Prop); 01207 ezxml_set_attr(Node, "auto", NULL); 01208 if(arch->clb_grid.Aspect <= 0) 01209 { 01210 printf(ERRTAG 01211 "Grid aspect ratio is less than or equal to zero %g\n", arch->clb_grid.Aspect); 01212 } 01213 } 01214 } 01215 01216 /** Takes in node pointing to <device> and loads all the 01217 * child type objects. Unlinks the entire <device> node 01218 * when complete. 01219 */ 01220 static void 01221 ProcessDevice(INOUTP ezxml_t Node, OUTP struct s_arch *arch, 01222 INP boolean timing_enabled) 01223 { 01224 const char *Prop; 01225 ezxml_t Cur; 01226 01227 Cur = FindElement(Node, "sizing", TRUE); 01228 arch->R_minW_nmos = GetFloatProperty(Cur, "R_minW_nmos", timing_enabled, 0); 01229 arch->R_minW_pmos = GetFloatProperty(Cur, "R_minW_pmos", timing_enabled, 0); 01230 arch->ipin_mux_trans_size = GetFloatProperty(Cur, "ipin_mux_trans_size", FALSE, 0); 01231 FreeNode(Cur); 01232 01233 Cur = FindElement(Node, "timing", timing_enabled); 01234 if(Cur != NULL) 01235 { 01236 arch->C_ipin_cblock = GetFloatProperty(Cur, "C_ipin_cblock", FALSE, 0); 01237 arch->T_ipin_cblock = GetFloatProperty(Cur, "T_ipin_cblock", FALSE, 0); 01238 FreeNode(Cur); 01239 } 01240 01241 Cur = FindElement(Node, "area", TRUE); 01242 arch->grid_logic_tile_area = GetFloatProperty(Cur, "grid_logic_tile_area", FALSE, 0); 01243 FreeNode(Cur); 01244 01245 Cur = FindElement(Node, "chan_width_distr", FALSE); 01246 if(Cur != NULL) 01247 { 01248 ProcessChanWidthDistr(Cur, arch); 01249 FreeNode(Cur); 01250 } 01251 01252 Cur = FindElement(Node, "switch_block", TRUE); 01253 Prop = FindProperty(Cur, "type", TRUE); 01254 if(strcmp(Prop, "wilton") == 0) 01255 { 01256 arch->SBType = WILTON; 01257 } 01258 else if(strcmp(Prop, "universal") == 0) 01259 { 01260 arch->SBType = UNIVERSAL; 01261 } 01262 else if(strcmp(Prop, "subset") == 0) 01263 { 01264 arch->SBType = SUBSET; 01265 } 01266 else 01267 { 01268 printf(ERRTAG "[LINE %d] Unknown property %s for switch block type x\n", Cur->line, 01269 Prop); 01270 exit(1); 01271 } 01272 ezxml_set_attr(Cur, "type", NULL); 01273 01274 arch->Fs = GetIntProperty(Cur, "fs", TRUE, 3); 01275 01276 FreeNode(Cur); 01277 } 01278 01279 /** Takes in node pointing to <chan_width_distr> and loads all the 01280 * child type objects. Unlinks the entire <chan_width_distr> node 01281 * when complete. 01282 */ 01283 static void 01284 ProcessChanWidthDistr(INOUTP ezxml_t Node, OUTP struct s_arch *arch) 01285 { 01286 ezxml_t Cur; 01287 01288 Cur = FindElement(Node, "io", TRUE); 01289 arch->Chans.chan_width_io = GetFloatProperty(Cur, "width", TRUE, UNDEFINED); 01290 FreeNode(Cur); 01291 Cur = FindElement(Node, "x", TRUE); 01292 ProcessChanWidthDistrDir(Cur, &arch->Chans.chan_x_dist); 01293 FreeNode(Cur); 01294 Cur = FindElement(Node, "y", TRUE); 01295 ProcessChanWidthDistrDir(Cur, &arch->Chans.chan_y_dist); 01296 FreeNode(Cur); 01297 } 01298 01299 /** Takes in node within <chan_width_distr> and loads all the 01300 * child type objects. Unlinks the entire node when complete. 01301 */ 01302 static void 01303 ProcessChanWidthDistrDir(INOUTP ezxml_t Node, OUTP t_chan * chan) 01304 { 01305 const char *Prop; 01306 01307 boolean hasXpeak, hasWidth, hasDc; 01308 hasXpeak = hasWidth = hasDc = FALSE; 01309 Prop = FindProperty(Node, "distr", TRUE); 01310 if(strcmp(Prop, "uniform") == 0) 01311 { 01312 chan->type = UNIFORM; 01313 } 01314 else if(strcmp(Prop, "gaussian") == 0) 01315 { 01316 chan->type = GAUSSIAN; 01317 hasXpeak = hasWidth = hasDc = TRUE; 01318 } 01319 else if(strcmp(Prop, "pulse") == 0) 01320 { 01321 chan->type = PULSE; 01322 hasXpeak = hasWidth = hasDc = TRUE; 01323 } 01324 else if(strcmp(Prop, "delta") == 0) 01325 { 01326 hasXpeak = hasDc = TRUE; 01327 chan->type = DELTA; 01328 } 01329 else 01330 { 01331 printf(ERRTAG "[LINE %d] Unknown property %s for chan_width_distr x\n", Node->line, 01332 Prop); 01333 exit(1); 01334 } 01335 ezxml_set_attr(Node, "distr", NULL); 01336 chan->peak = GetFloatProperty(Node, "peak", TRUE, UNDEFINED); 01337 chan->width = GetFloatProperty(Node, "width", hasWidth, 0); 01338 chan->xpeak = GetFloatProperty(Node, "xpeak", hasXpeak, 0); 01339 chan->dc = GetFloatProperty(Node, "dc", hasDc, 0); 01340 } 01341 01342 static void 01343 SetupEmptyType() 01344 { 01345 t_type_descriptor * type; 01346 type = &type_descriptors[EMPTY_TYPE->index]; 01347 type->name = "<EMPTY>"; 01348 type->num_pins = 0; 01349 type->height = 1; 01350 type->capacity = 0; 01351 type->num_drivers = 0; 01352 type->num_receivers = 0; 01353 type->pinloc = NULL; 01354 type->num_class = 0; 01355 type->class_inf = NULL; 01356 type->pin_class = NULL; 01357 type->is_global_pin = NULL; 01358 type->is_Fc_frac = TRUE; 01359 type->is_Fc_out_full_flex = FALSE; 01360 type->Fc_in = 0; 01361 type->Fc_out = 0; 01362 type->pb_type = NULL; 01363 type->area = UNDEFINED; 01364 01365 /* Used as lost area filler, no definition */ 01366 type->grid_loc_def = NULL; 01367 type->num_grid_loc_def = 0; 01368 } 01369 01370 01371 static void alloc_and_load_default_child_for_pb_type(INOUTP t_pb_type *pb_type, char *new_name, t_pb_type *copy) { 01372 int i, j; 01373 char *dot; 01374 01375 assert(pb_type->blif_model != NULL); 01376 01377 copy->name = my_strdup(new_name); 01378 copy->blif_model = my_strdup(pb_type->blif_model); 01379 copy->class_type = pb_type->class_type; 01380 copy->depth = pb_type->depth; 01381 copy->model = pb_type->model; 01382 copy->models_contained = NULL; 01383 copy->modes = NULL; 01384 copy->num_modes = 0; 01385 copy->num_clock_pins = pb_type->num_clock_pins; 01386 copy->num_input_pins = pb_type->num_input_pins; 01387 copy->num_output_pins = pb_type->num_output_pins; 01388 copy->num_pb = 1; 01389 copy->num_ports = pb_type->num_ports; 01390 copy->ports = my_calloc(pb_type->num_ports, sizeof(t_port)); 01391 for(i = 0; i < pb_type->num_ports; i++) { 01392 copy->ports[i].is_clock = pb_type->ports[i].is_clock; 01393 copy->ports[i].model_port = pb_type->ports[i].model_port; 01394 copy->ports[i].type = pb_type->ports[i].type; 01395 copy->ports[i].num_pins = pb_type->ports[i].num_pins; 01396 copy->ports[i].parent_pb_type = copy; 01397 copy->ports[i].name = my_strdup(pb_type->ports[i].name); 01398 copy->ports[i].port_class = my_strdup(pb_type->ports[i].port_class); 01399 } 01400 01401 copy->max_internal_delay = pb_type->max_internal_delay; 01402 copy->annotations = my_calloc(pb_type->num_annotations, sizeof(t_pin_to_pin_annotation)); 01403 copy->num_annotations = pb_type->num_annotations; 01404 for(i = 0; i < copy->num_annotations; i++) { 01405 copy->annotations[i].clock = my_strdup(pb_type->annotations[i].clock); 01406 dot = strstr(pb_type->annotations[i].input_pins, "."); 01407 copy->annotations[i].input_pins = my_malloc(sizeof(char) * (strlen(new_name) + strlen(dot) + 1)); 01408 copy->annotations[i].input_pins[0] = '\0'; 01409 strcat(copy->annotations[i].input_pins, new_name); 01410 strcat(copy->annotations[i].input_pins, dot); 01411 if(pb_type->annotations[i].output_pins != NULL) { 01412 dot = strstr(pb_type->annotations[i].output_pins, "."); 01413 copy->annotations[i].output_pins = my_malloc(sizeof(char) * (strlen(new_name) + strlen(dot) + 1)); 01414 copy->annotations[i].output_pins[0] = '\0'; 01415 strcat(copy->annotations[i].output_pins, new_name); 01416 strcat(copy->annotations[i].output_pins, dot); 01417 } else { 01418 copy->annotations[i].output_pins = NULL; 01419 } 01420 copy->annotations[i].format = pb_type->annotations[i].format; 01421 copy->annotations[i].type = pb_type->annotations[i].type; 01422 copy->annotations[i].num_value_prop_pairs = pb_type->annotations[i].num_value_prop_pairs; 01423 copy->annotations[i].prop = my_malloc(sizeof(int) * pb_type->annotations[i].num_value_prop_pairs); 01424 copy->annotations[i].value = my_malloc(sizeof(char *) * pb_type->annotations[i].num_value_prop_pairs); 01425 for(j = 0; j < pb_type->annotations[i].num_value_prop_pairs; j++) { 01426 copy->annotations[i].prop[j] = pb_type->annotations[i].prop[j]; 01427 copy->annotations[i].value[j] = my_strdup(pb_type->annotations[i].value[j]); 01428 } 01429 } 01430 } 01431 01432 /** populate special lut class */ 01433 void ProcessLutClass(INOUTP t_pb_type *lut_pb_type) { 01434 char *default_name; 01435 t_port *in_port; 01436 t_port *out_port; 01437 int i, j; 01438 01439 if(strcmp(lut_pb_type->name, "lut") != 0) { 01440 default_name = my_strdup("lut"); 01441 } else { 01442 default_name = my_strdup("lut_child"); 01443 } 01444 01445 lut_pb_type->num_modes = 2; 01446 lut_pb_type->modes = my_calloc(lut_pb_type->num_modes, sizeof(t_mode)); 01447 01448 /* First mode, route_through */ 01449 lut_pb_type->modes[0].name = my_strdup(lut_pb_type->name); 01450 lut_pb_type->modes[0].parent_pb_type = lut_pb_type; 01451 lut_pb_type->modes[0].num_pb_type_children = 0; 01452 01453 /* Process interconnect */ 01454 /* TODO: add timing annotations to route-through */ 01455 assert(lut_pb_type->num_ports == 2); 01456 if(strcmp(lut_pb_type->ports[0].port_class, "lut_in") == 0) { 01457 assert(strcmp(lut_pb_type->ports[1].port_class, "lut_out") == 0); 01458 in_port = &lut_pb_type->ports[0]; 01459 out_port = &lut_pb_type->ports[1]; 01460 } else { 01461 assert(strcmp(lut_pb_type->ports[0].port_class, "lut_out") == 0); 01462 assert(strcmp(lut_pb_type->ports[1].port_class, "lut_in") == 0); 01463 out_port = &lut_pb_type->ports[0]; 01464 in_port = &lut_pb_type->ports[1]; 01465 } 01466 lut_pb_type->modes[0].num_interconnect = 1; 01467 lut_pb_type->modes[0].interconnect = my_calloc(1, sizeof(t_interconnect)); 01468 lut_pb_type->modes[0].interconnect[0].name = my_calloc( 01469 strlen(lut_pb_type->name) + 10, 01470 sizeof(char)); 01471 sprintf(lut_pb_type->modes[0].interconnect[0].name, "complete:%s", lut_pb_type->name); 01472 lut_pb_type->modes[0].interconnect[0].type = COMPLETE_INTERC; 01473 lut_pb_type->modes[0].interconnect[0].input_string = my_calloc( 01474 strlen(lut_pb_type->name) + 01475 strlen(in_port->name) + 2, 01476 sizeof(char)); 01477 sprintf(lut_pb_type->modes[0].interconnect[0].input_string, "%s.%s", 01478 lut_pb_type->name, in_port->name); 01479 lut_pb_type->modes[0].interconnect[0].output_string = my_calloc( 01480 strlen(lut_pb_type->name) + 01481 strlen(out_port->name) + 2, 01482 sizeof(char)); 01483 sprintf(lut_pb_type->modes[0].interconnect[0].output_string, "%s.%s", 01484 lut_pb_type->name, out_port->name); 01485 01486 /* Second mode, LUT */ 01487 01488 lut_pb_type->modes[1].name = my_strdup(lut_pb_type->name); 01489 lut_pb_type->modes[1].parent_pb_type = lut_pb_type; 01490 lut_pb_type->modes[1].num_pb_type_children = 1; 01491 lut_pb_type->modes[1].pb_type_children = my_calloc(1, sizeof(t_pb_type)); 01492 alloc_and_load_default_child_for_pb_type(lut_pb_type, default_name, lut_pb_type->modes[1].pb_type_children); 01493 /* moved annotations to child so delete old annotations */ 01494 for(i = 0; i < lut_pb_type->num_annotations; i++) { 01495 for(j = 0; j < lut_pb_type->annotations[i].num_value_prop_pairs; j++) { 01496 free(lut_pb_type->annotations[i].value[j]); 01497 } 01498 free(lut_pb_type->annotations[i].value); 01499 free(lut_pb_type->annotations[i].prop); 01500 if(lut_pb_type->annotations[i].input_pins) { 01501 free(lut_pb_type->annotations[i].input_pins); 01502 } 01503 if(lut_pb_type->annotations[i].output_pins) { 01504 free(lut_pb_type->annotations[i].output_pins); 01505 } 01506 if(lut_pb_type->annotations[i].clock) { 01507 free(lut_pb_type->annotations[i].clock); 01508 } 01509 } 01510 lut_pb_type->num_annotations = 0; 01511 free(lut_pb_type->annotations); 01512 lut_pb_type->annotations = NULL; 01513 lut_pb_type->modes[1].pb_type_children[0].depth = lut_pb_type->depth + 1; 01514 lut_pb_type->modes[1].pb_type_children[0].parent_mode = &lut_pb_type->modes[1]; 01515 01516 /* Process interconnect */ 01517 lut_pb_type->modes[1].num_interconnect = 2; 01518 lut_pb_type->modes[1].interconnect = my_calloc(2, sizeof(t_interconnect)); 01519 lut_pb_type->modes[1].interconnect[0].name = my_calloc( 01520 strlen(lut_pb_type->name) + 10, 01521 sizeof(char)); 01522 sprintf(lut_pb_type->modes[1].interconnect[0].name, "complete:%s", lut_pb_type->name); 01523 lut_pb_type->modes[1].interconnect[0].type = COMPLETE_INTERC; 01524 lut_pb_type->modes[1].interconnect[0].input_string = my_calloc( 01525 strlen(lut_pb_type->name) + 01526 strlen(in_port->name) + 2, 01527 sizeof(char)); 01528 sprintf(lut_pb_type->modes[1].interconnect[0].input_string, "%s.%s", 01529 lut_pb_type->name, in_port->name); 01530 lut_pb_type->modes[1].interconnect[0].output_string = my_calloc( 01531 strlen(default_name) + 01532 strlen(in_port->name) + 2, 01533 sizeof(char)); 01534 sprintf(lut_pb_type->modes[1].interconnect[0].output_string, "%s.%s", 01535 default_name, in_port->name); 01536 01537 lut_pb_type->modes[1].interconnect[1].name = my_calloc( 01538 strlen(lut_pb_type->name) + 11, 01539 sizeof(char)); 01540 sprintf(lut_pb_type->modes[1].interconnect[1].name, "complete2:%s", lut_pb_type->name); 01541 01542 lut_pb_type->modes[1].interconnect[1].type = COMPLETE_INTERC; 01543 lut_pb_type->modes[1].interconnect[1].input_string = my_calloc( 01544 strlen(default_name) + 01545 strlen(lut_pb_type->name) + 01546 strlen(in_port->name) + 01547 strlen(out_port->name) + 4, 01548 sizeof(char)); 01549 sprintf(lut_pb_type->modes[1].interconnect[1].input_string, "%s.%s %s.%s", default_name, out_port->name, 01550 lut_pb_type->name, in_port->name); 01551 lut_pb_type->modes[1].interconnect[1].output_string = my_calloc( 01552 strlen(lut_pb_type->name) + 01553 strlen(out_port->name) + 01554 strlen(in_port->name) + 2, 01555 sizeof(char)); 01556 sprintf(lut_pb_type->modes[1].interconnect[1].output_string, "%s.%s", 01557 lut_pb_type->name, out_port->name); 01558 01559 free(default_name); 01560 01561 free(lut_pb_type->blif_model); 01562 lut_pb_type->blif_model = NULL; 01563 lut_pb_type->model = NULL; 01564 } 01565 01566 /** populate special memory class */ 01567 static void ProcessMemoryClass(INOUTP t_pb_type *mem_pb_type) { 01568 char *default_name; 01569 char *input_name, *input_port_name, *output_name, *output_port_name; 01570 int i, j, i_inter, num_pb; 01571 01572 01573 if(strcmp(mem_pb_type->name, "memory_slice") != 0) { 01574 default_name = my_strdup("memory_slice"); 01575 } else { 01576 default_name = my_strdup("memory_slice_1bit"); 01577 } 01578 01579 mem_pb_type->modes = my_calloc(1, sizeof(t_mode)); 01580 mem_pb_type->modes[0].name = my_strdup(default_name); 01581 mem_pb_type->modes[0].parent_pb_type = mem_pb_type; 01582 01583 num_pb = OPEN; 01584 for(i = 0; i < mem_pb_type->num_ports; i++) { 01585 if(mem_pb_type->ports[i].port_class != NULL && 01586 strstr(mem_pb_type->ports[i].port_class, "data") == mem_pb_type->ports[i].port_class) { 01587 if(num_pb == OPEN) { 01588 num_pb = mem_pb_type->ports[i].num_pins; 01589 } else if (num_pb != mem_pb_type->ports[i].num_pins) { 01590 printf(ERRTAG "memory %s has inconsistent number of data bits %d and %d\n", mem_pb_type->name, 01591 num_pb, mem_pb_type->ports[i].num_pins); 01592 exit(1); 01593 } 01594 } 01595 } 01596 01597 mem_pb_type->modes[0].num_pb_type_children = 1; 01598 mem_pb_type->modes[0].pb_type_children = my_calloc(1, sizeof(t_pb_type)); 01599 alloc_and_load_default_child_for_pb_type(mem_pb_type, default_name, &mem_pb_type->modes[0].pb_type_children[0]); 01600 mem_pb_type->modes[0].pb_type_children[0].depth = mem_pb_type->depth + 1; 01601 mem_pb_type->modes[0].pb_type_children[0].parent_mode = &mem_pb_type->modes[0]; 01602 mem_pb_type->modes[0].pb_type_children[0].num_pb = num_pb; 01603 01604 mem_pb_type->num_modes = 1; 01605 01606 free(mem_pb_type->blif_model); 01607 mem_pb_type->blif_model = NULL; 01608 mem_pb_type->model = NULL; 01609 01610 mem_pb_type->modes[0].num_interconnect = mem_pb_type->num_ports * num_pb; 01611 mem_pb_type->modes[0].interconnect = my_calloc(mem_pb_type->modes[0].num_interconnect, sizeof(t_interconnect)); 01612 01613 /* Process interconnect */ 01614 i_inter = 0; 01615 for(i = 0; i < mem_pb_type->num_ports; i++) { 01616 mem_pb_type->modes[0].interconnect[i_inter].type = DIRECT_INTERC; 01617 input_port_name = mem_pb_type->ports[i].name; 01618 output_port_name = mem_pb_type->ports[i].name; 01619 01620 if(mem_pb_type->ports[i].type == IN_PORT) { 01621 input_name = mem_pb_type->name; 01622 output_name = default_name; 01623 } else { 01624 input_name = default_name; 01625 output_name = mem_pb_type->name; 01626 } 01627 01628 if(mem_pb_type->ports[i].port_class != NULL && 01629 strstr(mem_pb_type->ports[i].port_class, "data") == mem_pb_type->ports[i].port_class) { 01630 01631 mem_pb_type->modes[0].interconnect[i_inter].name = my_calloc(i_inter/10 + 8, sizeof(char)); 01632 sprintf(mem_pb_type->modes[0].interconnect[i_inter].name, "direct%d", i_inter); 01633 01634 01635 if(mem_pb_type->ports[i].type == IN_PORT) { 01636 /* force data pins to be one bit wide and update stats */ 01637 mem_pb_type->modes[0].pb_type_children[0].ports[i].num_pins = 1; 01638 mem_pb_type->modes[0].pb_type_children[0].num_input_pins -= (mem_pb_type->ports[i].num_pins - 1); 01639 01640 01641 mem_pb_type->modes[0].interconnect[i_inter].input_string = my_calloc( 01642 strlen(input_name) + 01643 strlen(input_port_name) + 2, 01644 sizeof(char)); 01645 sprintf(mem_pb_type->modes[0].interconnect[i_inter].input_string, "%s.%s", 01646 input_name, input_port_name); 01647 mem_pb_type->modes[0].interconnect[i_inter].output_string = my_calloc( 01648 strlen(output_name) + 01649 strlen(output_port_name) + 2*(6 + num_pb/10), 01650 sizeof(char)); 01651 sprintf(mem_pb_type->modes[0].interconnect[i_inter].output_string, "%s[%d:0].%s", 01652 output_name, num_pb - 1, output_port_name); 01653 } else { 01654 /* force data pins to be one bit wide and update stats */ 01655 mem_pb_type->modes[0].pb_type_children[0].ports[i].num_pins = 1; 01656 mem_pb_type->modes[0].pb_type_children[0].num_output_pins -= (mem_pb_type->ports[i].num_pins - 1); 01657 01658 mem_pb_type->modes[0].interconnect[i_inter].input_string = my_calloc( 01659 strlen(input_name) + 01660 strlen(input_port_name) + 2*(6 + num_pb/10), 01661 sizeof(char)); 01662 sprintf(mem_pb_type->modes[0].interconnect[i_inter].input_string, "%s[%d:0].%s", 01663 input_name, num_pb - 1, input_port_name); 01664 mem_pb_type->modes[0].interconnect[i_inter].output_string = my_calloc( 01665 strlen(output_name) + 01666 strlen(output_port_name) + 2, 01667 sizeof(char)); 01668 sprintf(mem_pb_type->modes[0].interconnect[i_inter].output_string, "%s.%s", 01669 output_name, output_port_name); 01670 } 01671 01672 i_inter++; 01673 } else { 01674 for(j = 0; j < num_pb; j++) { 01675 /* Anything that is not data must be an input */ 01676 mem_pb_type->modes[0].interconnect[i_inter].name = my_calloc(i_inter/10 + j/10 + 10, sizeof(char)); 01677 sprintf(mem_pb_type->modes[0].interconnect[i_inter].name, "direct%d_%d", i_inter, j); 01678 01679 if(mem_pb_type->ports[i].type == IN_PORT) { 01680 mem_pb_type->modes[0].interconnect[i_inter].type = DIRECT_INTERC; 01681 mem_pb_type->modes[0].interconnect[i_inter].input_string = my_calloc( 01682 strlen(input_name) + 01683 strlen(input_port_name) + 2, 01684 sizeof(char)); 01685 sprintf(mem_pb_type->modes[0].interconnect[i_inter].input_string, "%s.%s", 01686 input_name, input_port_name); 01687 mem_pb_type->modes[0].interconnect[i_inter].output_string = my_calloc( 01688 strlen(output_name) + 01689 strlen(output_port_name) + 2*(6 + num_pb/10), 01690 sizeof(char)); 01691 sprintf(mem_pb_type->modes[0].interconnect[i_inter].output_string, "%s[%d:%d].%s", 01692 output_name, j, j, output_port_name); 01693 } else { 01694 mem_pb_type->modes[0].interconnect[i_inter].type = DIRECT_INTERC; 01695 mem_pb_type->modes[0].interconnect[i_inter].input_string = my_calloc( 01696 strlen(input_name) + 01697 strlen(input_port_name) + 2*(6 + num_pb/10), 01698 sizeof(char)); 01699 sprintf(mem_pb_type->modes[0].interconnect[i_inter].input_string, "%s[%d:%d].%s", 01700 input_name, j, j, input_port_name); 01701 mem_pb_type->modes[0].interconnect[i_inter].output_string = my_calloc( 01702 strlen(output_name) + 01703 strlen(output_port_name) + 2, 01704 sizeof(char)); 01705 sprintf(mem_pb_type->modes[0].interconnect[i_inter].output_string, "%s.%s", 01706 output_name, output_port_name); 01707 01708 } 01709 i_inter++; 01710 } 01711 } 01712 } 01713 mem_pb_type->modes[0].num_interconnect = i_inter; 01714 01715 free(default_name); 01716 } 01717 01718 /** Takes in node pointing to <typelist> and loads all the 01719 * child type objects. Unlinks the entire <typelist> node 01720 * when complete. 01721 */ 01722 static void 01723 ProcessComplexBlocks(INOUTP ezxml_t Node, OUTP t_type_descriptor ** Types, 01724 OUTP int *NumTypes, boolean timing_enabled) 01725 { 01726 ezxml_t CurType, Prev; 01727 ezxml_t Cur, Cur2; 01728 t_type_descriptor * Type; 01729 int i; 01730 01731 01732 /* Alloc the type list. Need one additional t_type_desctiptors: 01733 * 1: empty psuedo-type 01734 */ 01735 *NumTypes = CountChildren(Node, "pb_type", 1) + 1; 01736 *Types = (t_type_descriptor *) 01737 my_malloc(sizeof(t_type_descriptor) * (*NumTypes)); 01738 01739 type_descriptors = *Types; 01740 01741 EMPTY_TYPE = &type_descriptors[EMPTY_TYPE_INDEX]; 01742 IO_TYPE = &type_descriptors[IO_TYPE_INDEX]; 01743 type_descriptors[EMPTY_TYPE_INDEX].index = EMPTY_TYPE_INDEX; 01744 type_descriptors[IO_TYPE_INDEX].index = IO_TYPE_INDEX; 01745 SetupEmptyType(); 01746 01747 /* Process the types */ 01748 /* TODO: I should make this more flexible but release is soon and I don't have time so assert values for empty and io types*/ 01749 assert(EMPTY_TYPE_INDEX == 0); 01750 assert(IO_TYPE_INDEX == 1); 01751 i = 1; /* Skip over 'empty' type */ 01752 CurType = Node->child; 01753 while(CurType) 01754 { 01755 CheckElement(CurType, "pb_type"); 01756 01757 /* Alias to current type */ 01758 Type = &(*Types)[i]; 01759 01760 /* Parses the properties fields of the type */ 01761 ProcessComplexBlockProps(CurType, Type); 01762 01763 /* Load pb_type info */ 01764 Type->pb_type = my_malloc(sizeof(t_pb_type)); 01765 Type->pb_type->name = my_strdup(Type->name); 01766 if(i == IO_TYPE_INDEX) { 01767 if(strcmp(Type->name, "io") != 0) { 01768 printf("First complex block must be named \"io\" and define the inputs and outputs for the FPGA"); 01769 exit(1); 01770 } 01771 } 01772 ProcessPb_Type(CurType, Type->pb_type, NULL); 01773 Type->num_pins = Type->capacity * (Type->pb_type->num_input_pins + Type->pb_type->num_output_pins + Type->pb_type->num_clock_pins); 01774 Type->num_receivers = Type->capacity * Type->pb_type->num_input_pins; 01775 Type->num_drivers = Type->capacity * Type->pb_type->num_output_pins; 01776 01777 /* Load Fc */ 01778 Cur = FindElement(CurType, "fc_in", TRUE); 01779 Cur2 = FindElement(CurType, "fc_out", TRUE); 01780 Process_Fc(Cur, Cur2, Type); 01781 FreeNode(Cur); 01782 FreeNode(Cur2); 01783 01784 /* Load pin names and classes and locations */ 01785 Cur = FindElement(CurType, "pinlocations", TRUE); 01786 SetupPinLocationsAndPinClasses(Cur, Type); 01787 FreeNode(Cur); 01788 Cur = FindElement(CurType, "gridlocations", TRUE); 01789 SetupGridLocations(Cur, Type); 01790 FreeNode(Cur); 01791 #if 0 01792 Cur = FindElement(CurType, "timing", timing_enabled); 01793 if(Cur) 01794 { 01795 SetupTypeTiming(Cur, Type); 01796 FreeNode(Cur); 01797 } 01798 #endif 01799 Type->index = i; 01800 01801 /* Type fully read */ 01802 ++i; 01803 01804 /* Free this node and get its next sibling node */ 01805 Prev = CurType; 01806 CurType = CurType->next; 01807 FreeNode(Prev); 01808 01809 } 01810 if(FILL_TYPE == NULL) 01811 { 01812 printf(ERRTAG "grid location type 'fill' must be specified.\n"); 01813 exit(1); 01814 } 01815 } 01816 01817 /** Loads the given architecture file. Currently only 01818 * handles type information 01819 */ 01820 void 01821 XmlReadArch(INP const char *ArchFile, INP boolean timing_enabled, 01822 OUTP struct s_arch *arch, OUTP t_type_descriptor ** Types, 01823 OUTP int *NumTypes) 01824 { 01825 ezxml_t Cur, Next; 01826 const char *Prop; 01827 01828 /* Parse the file */ 01829 Cur = ezxml_parse_file(ArchFile); 01830 if(NULL == Cur) 01831 { 01832 printf(ERRTAG "Unable to load architecture file '%s'.\n", 01833 ArchFile); 01834 exit(1); 01835 } 01836 01837 /* Root node should be architecture */ 01838 CheckElement(Cur, "architecture"); 01839 /* TODO: do version processing properly with string delimiting on the . */ 01840 Prop = FindProperty(Cur, "version", FALSE); 01841 if(Prop != NULL) 01842 { 01843 if (atof(Prop) > atof(VPR_VERSION)) { 01844 printf(WARNTAG "This architecture version is for VPR %f while your current VPR version is " VPR_VERSION ", compatability issues may arise\n", 01845 atof(Prop)); 01846 } 01847 ezxml_set_attr(Cur, "version", NULL); 01848 } 01849 01850 /* Process models */ 01851 Next = FindElement(Cur, "models", TRUE); 01852 ProcessModels(Next, arch); 01853 FreeNode(Next); 01854 CreateModelLibrary(arch); 01855 01856 /* Process layout */ 01857 Next = FindElement(Cur, "layout", TRUE); 01858 ProcessLayout(Next, arch); 01859 FreeNode(Next); 01860 01861 /* Process device */ 01862 Next = FindElement(Cur, "device", TRUE); 01863 ProcessDevice(Next, arch, timing_enabled); 01864 FreeNode(Next); 01865 01866 /* Process types */ 01867 Next = FindElement(Cur, "complexblocklist", TRUE); 01868 ProcessComplexBlocks(Next, Types, NumTypes, timing_enabled); 01869 FreeNode(Next); 01870 01871 /* Process switches */ 01872 Next = FindElement(Cur, "switchlist", TRUE); 01873 ProcessSwitches(Next, &(arch->Switches), &(arch->num_switches), 01874 timing_enabled); 01875 FreeNode(Next); 01876 01877 /* Process segments. This depends on switches */ 01878 Next = FindElement(Cur, "segmentlist", TRUE); 01879 ProcessSegments(Next, &(arch->Segments), &(arch->num_segments), 01880 arch->Switches, arch->num_switches, timing_enabled); 01881 FreeNode(Next); 01882 01883 SyncModelsPbTypes(arch, *Types, *NumTypes); 01884 UpdateAndCheckModels(arch); 01885 01886 /* Release the full XML tree */ 01887 FreeNode(Cur); 01888 } 01889 01890 static void 01891 ProcessSegments(INOUTP ezxml_t Parent, OUTP struct s_segment_inf **Segs, 01892 OUTP int *NumSegs, INP struct s_switch_inf *Switches, 01893 INP int NumSwitches, INP boolean timing_enabled) 01894 { 01895 int i, j, length; 01896 const char *tmp; 01897 01898 ezxml_t SubElem; 01899 ezxml_t Node; 01900 01901 /* Count the number of segs and check they are in fact 01902 * of segment elements. */ 01903 *NumSegs = CountChildren(Parent, "segment", 1); 01904 01905 /* Alloc segment list */ 01906 *Segs = NULL; 01907 if(*NumSegs > 0) 01908 { 01909 *Segs = 01910 (struct s_segment_inf *)my_malloc(*NumSegs * 01911 sizeof(struct 01912 s_segment_inf)); 01913 memset(*Segs, 0, (*NumSegs * sizeof(struct s_segment_inf))); 01914 } 01915 01916 /* Load the segments. */ 01917 for(i = 0; i < *NumSegs; ++i) 01918 { 01919 Node = ezxml_child(Parent, "segment"); 01920 01921 /* Get segment length */ 01922 length = 1; /* DEFAULT */ 01923 tmp = FindProperty(Node, "length", FALSE); 01924 if(tmp) 01925 { 01926 if(strcmp(tmp, "longline") == 0) 01927 { 01928 (*Segs)[i].longline = TRUE; 01929 } 01930 else 01931 { 01932 length = my_atoi(tmp); 01933 } 01934 } 01935 (*Segs)[i].length = length; 01936 ezxml_set_attr(Node, "length", NULL); 01937 01938 /* Get the frequency */ 01939 (*Segs)[i].frequency = 1; /* DEFAULT */ 01940 tmp = FindProperty(Node, "freq", FALSE); 01941 if(tmp) 01942 { 01943 (*Segs)[i].frequency = (int) (atof(tmp) * MAX_CHANNEL_WIDTH); 01944 } 01945 ezxml_set_attr(Node, "freq", NULL); 01946 01947 /* Get timing info */ 01948 (*Segs)[i].Rmetal = GetFloatProperty(Node, "Rmetal", timing_enabled, 0); 01949 (*Segs)[i].Cmetal = GetFloatProperty(Node, "Cmetal", timing_enabled, 0); 01950 01951 /* Get the type */ 01952 tmp = FindProperty(Node, "type", TRUE); 01953 if(0 == strcmp(tmp, "bidir")) 01954 { 01955 (*Segs)[i].directionality = BI_DIRECTIONAL; 01956 } 01957 01958 else if(0 == strcmp(tmp, "unidir")) 01959 { 01960 (*Segs)[i].directionality = UNI_DIRECTIONAL; 01961 } 01962 01963 else 01964 { 01965 printf(ERRTAG "[LINE %d] Invalid switch type '%s'.\n", Node->line, tmp); 01966 exit(1); 01967 } 01968 ezxml_set_attr(Node, "type", NULL); 01969 01970 /* Get the wire and opin switches, or mux switch if unidir */ 01971 if(UNI_DIRECTIONAL == (*Segs)[i].directionality) 01972 { 01973 SubElem = FindElement(Node, "mux", TRUE); 01974 tmp = FindProperty(SubElem, "name", TRUE); 01975 01976 /* Match names */ 01977 for(j = 0; j < NumSwitches; ++j) 01978 { 01979 if(0 == strcmp(tmp, Switches[j].name)) 01980 { 01981 break; /* End loop so j is where we want it */ 01982 } 01983 } 01984 if(j >= NumSwitches) 01985 { 01986 printf(ERRTAG "[LINE %d] '%s' is not a valid mux name.\n", SubElem->line, 01987 tmp); 01988 exit(1); 01989 } 01990 ezxml_set_attr(SubElem, "name", NULL); 01991 FreeNode(SubElem); 01992 01993 /* Unidir muxes must have the same switch 01994 * for wire and opin fanin since there is 01995 * really only the mux in unidir. */ 01996 (*Segs)[i].wire_switch = j; 01997 (*Segs)[i].opin_switch = j; 01998 } 01999 02000 else 02001 { 02002 assert(BI_DIRECTIONAL == (*Segs)[i].directionality); 02003 SubElem = FindElement(Node, "wire_switch", TRUE); 02004 tmp = FindProperty(SubElem, "name", TRUE); 02005 02006 /* Match names */ 02007 for(j = 0; j < NumSwitches; ++j) 02008 { 02009 if(0 == strcmp(tmp, Switches[j].name)) 02010 { 02011 break; /* End loop so j is where we want it */ 02012 } 02013 } 02014 if(j >= NumSwitches) 02015 { 02016 printf(ERRTAG 02017 "[LINE %d] '%s' is not a valid wire_switch name.\n", SubElem->line, 02018 tmp); 02019 exit(1); 02020 } 02021 (*Segs)[i].wire_switch = j; 02022 ezxml_set_attr(SubElem, "name", NULL); 02023 FreeNode(SubElem); 02024 SubElem = FindElement(Node, "opin_switch", TRUE); 02025 tmp = FindProperty(SubElem, "name", TRUE); 02026 02027 /* Match names */ 02028 for(j = 0; j < NumSwitches; ++j) 02029 { 02030 if(0 == strcmp(tmp, Switches[j].name)) 02031 { 02032 break; /* End loop so j is where we want it */ 02033 } 02034 } 02035 if(j >= NumSwitches) 02036 { 02037 printf(ERRTAG 02038 "[LINE %d] '%s' is not a valid opin_switch name.\n", SubElem->line, 02039 tmp); 02040 exit(1); 02041 } 02042 (*Segs)[i].opin_switch = j; 02043 ezxml_set_attr(SubElem, "name", NULL); 02044 FreeNode(SubElem); 02045 } 02046 02047 /* Setup the CB list if they give one, otherwise use full */ 02048 (*Segs)[i].cb_len = length; 02049 (*Segs)[i].cb = (boolean *) my_malloc(length * sizeof(boolean)); 02050 for(j = 0; j < length; ++j) 02051 { 02052 (*Segs)[i].cb[j] = TRUE; 02053 } 02054 SubElem = FindElement(Node, "cb", FALSE); 02055 if(SubElem) 02056 { 02057 ProcessCB_SB(SubElem, (*Segs)[i].cb, length); 02058 FreeNode(SubElem); 02059 } 02060 02061 /* Setup the SB list if they give one, otherwise use full */ 02062 (*Segs)[i].sb_len = (length + 1); 02063 (*Segs)[i].sb = 02064 (boolean *) my_malloc((length + 1) * sizeof(boolean)); 02065 for(j = 0; j < (length + 1); ++j) 02066 { 02067 (*Segs)[i].sb[j] = TRUE; 02068 } 02069 SubElem = FindElement(Node, "sb", FALSE); 02070 if(SubElem) 02071 { 02072 ProcessCB_SB(SubElem, (*Segs)[i].sb, (length + 1)); 02073 FreeNode(SubElem); 02074 } 02075 FreeNode(Node); 02076 } 02077 } 02078 02079 static void 02080 ProcessCB_SB(INOUTP ezxml_t Node, INOUTP boolean * list, INP int len) 02081 { 02082 const char *tmp = NULL; 02083 int i; 02084 02085 /* Check the type. We only support 'pattern' for now. 02086 * Should add frac back eventually. */ 02087 tmp = FindProperty(Node, "type", TRUE); 02088 if(0 == strcmp(tmp, "pattern")) 02089 { 02090 i = 0; 02091 02092 /* Get the content string */ 02093 tmp = Node->txt; 02094 while(*tmp) 02095 { 02096 switch (*tmp) 02097 { 02098 case ' ': 02099 break; 02100 case 'T': 02101 case '1': 02102 if(i >= len) 02103 { 02104 printf(ERRTAG 02105 "[LINE %d] CB or SB depopulation is too long. It " 02106 02107 "should be (length) symbols for CBs and (length+1) " 02108 "symbols for SBs.\n", Node->line); 02109 exit(1); 02110 } 02111 list[i] = TRUE; 02112 ++i; 02113 break; 02114 case 'F': 02115 case '0': 02116 if(i >= len) 02117 { 02118 printf(ERRTAG 02119 "[LINE %d] CB or SB depopulation is too long. It " 02120 02121 "should be (length) symbols for CBs and (length+1) " 02122 "symbols for SBs.\n", Node->line); 02123 exit(1); 02124 } 02125 list[i] = FALSE; 02126 ++i; 02127 break; 02128 default: 02129 printf(ERRTAG "[LINE %d] Invalid character %c in CB or " 02130 "SB depopulation list.\n", Node->line, 02131 *tmp); 02132 exit(1); 02133 } 02134 ++tmp; 02135 } 02136 if(i < len) 02137 { 02138 printf(ERRTAG "[LINE %d] CB or SB depopulation is too short. It " 02139 "should be (length) symbols for CBs and (length+1) " 02140 "symbols for SBs.\n", Node->line); 02141 exit(1); 02142 } 02143 02144 /* Free content string */ 02145 ezxml_set_txt(Node, ""); 02146 } 02147 02148 else 02149 { 02150 printf(ERRTAG "[LINE %d] '%s' is not a valid type for specifying " 02151 "cb and sb depopulation.\n", Node->line, tmp); 02152 exit(1); 02153 } 02154 ezxml_set_attr(Node, "type", NULL); 02155 } 02156 02157 static void 02158 ProcessSwitches(INOUTP ezxml_t Parent, OUTP struct s_switch_inf **Switches, 02159 OUTP int *NumSwitches, INP boolean timing_enabled) 02160 { 02161 int i, j; 02162 const char *type_name; 02163 const char *switch_name; 02164 02165 boolean has_buf_size; 02166 ezxml_t Node; 02167 has_buf_size = FALSE; 02168 02169 /* Count the children and check they are switches */ 02170 *NumSwitches = CountChildren(Parent, "switch", 1); 02171 02172 /* Alloc switch list */ 02173 *Switches = NULL; 02174 if(*NumSwitches > 0) 02175 { 02176 *Switches = 02177 (struct s_switch_inf *)my_malloc(*NumSwitches * 02178 sizeof(struct 02179 s_switch_inf)); 02180 memset(*Switches, 0, 02181 (*NumSwitches * sizeof(struct s_switch_inf))); 02182 } 02183 02184 /* Load the switches. */ 02185 for(i = 0; i < *NumSwitches; ++i) 02186 { 02187 Node = ezxml_child(Parent, "switch"); 02188 switch_name = FindProperty(Node, "name", TRUE); 02189 type_name = FindProperty(Node, "type", TRUE); 02190 02191 /* Check for switch name collisions */ 02192 for(j = 0; j < i; ++j) 02193 { 02194 if(0 == strcmp((*Switches)[j].name, switch_name)) 02195 { 02196 printf(ERRTAG 02197 "[LINE %d] Two switches with the same name '%s' were " 02198 "found.\n", Node->line, switch_name); 02199 exit(1); 02200 } 02201 } 02202 (*Switches)[i].name = my_strdup(switch_name); 02203 ezxml_set_attr(Node, "name", NULL); 02204 02205 /* Figure out the type of switch. */ 02206 if(0 == strcmp(type_name, "mux")) 02207 { 02208 (*Switches)[i].buffered = TRUE; 02209 has_buf_size = TRUE; 02210 } 02211 02212 else if(0 == strcmp(type_name, "pass_trans")) 02213 { 02214 (*Switches)[i].buffered = FALSE; 02215 } 02216 02217 else if(0 == strcmp(type_name, "buffer")) 02218 { 02219 (*Switches)[i].buffered = TRUE; 02220 } 02221 02222 else 02223 { 02224 printf(ERRTAG "[LINE %d] Invalid switch type '%s'.\n", Node->line, type_name); 02225 exit(1); 02226 } 02227 ezxml_set_attr(Node, "type", NULL); 02228 (*Switches)[i].R = GetFloatProperty(Node, "R", timing_enabled, 0); 02229 (*Switches)[i].Cin = GetFloatProperty(Node, "Cin", timing_enabled, 0); 02230 (*Switches)[i].Cout = GetFloatProperty(Node, "Cout", timing_enabled, 0); 02231 (*Switches)[i].Tdel = GetFloatProperty(Node, "Tdel", timing_enabled, 0); 02232 (*Switches)[i].buf_size = GetFloatProperty(Node, "buf_size", has_buf_size, 0); 02233 (*Switches)[i].mux_trans_size = GetFloatProperty(Node, "mux_trans_size", FALSE, 1); 02234 02235 /* Remove the switch element from parse tree */ 02236 FreeNode(Node); 02237 } 02238 } 02239 02240 02241 static void CreateModelLibrary(OUTP struct s_arch *arch) { 02242 t_model* model_library; 02243 02244 model_library = my_calloc(4, sizeof(t_model)); 02245 model_library[0].name = my_strdup("input"); 02246 model_library[0].index = 0; 02247 model_library[0].inputs = NULL; 02248 model_library[0].instances = NULL; 02249 model_library[0].next = &model_library[1]; 02250 model_library[0].outputs = my_calloc(1, sizeof(t_model_ports)); 02251 model_library[0].outputs->dir = OUT_PORT; 02252 model_library[0].outputs->name = my_strdup("inpad"); 02253 model_library[0].outputs->next = NULL; 02254 model_library[0].outputs->size = 1; 02255 model_library[0].outputs->min_size = 1; 02256 model_library[0].outputs->index = 0; 02257 model_library[0].outputs->is_clock = FALSE; 02258 02259 model_library[1].name = my_strdup("output"); 02260 model_library[1].index = 1; 02261 model_library[1].inputs = my_calloc(1, sizeof(t_model_ports)); 02262 model_library[1].inputs->dir = IN_PORT; 02263 model_library[1].inputs->name = my_strdup("outpad"); 02264 model_library[1].inputs->next = NULL; 02265 model_library[1].inputs->size = 1; 02266 model_library[1].inputs->min_size = 1; 02267 model_library[1].inputs->index = 0; 02268 model_library[1].inputs->is_clock = FALSE; 02269 model_library[1].instances = NULL; 02270 model_library[1].next = &model_library[2]; 02271 model_library[1].outputs = NULL; 02272 02273 model_library[2].name = my_strdup("latch"); 02274 model_library[2].index = 2; 02275 model_library[2].inputs = my_calloc(2, sizeof(t_model_ports)); 02276 model_library[2].inputs[0].dir = IN_PORT; 02277 model_library[2].inputs[0].name = my_strdup("D"); 02278 model_library[2].inputs[0].next = &model_library[2].inputs[1]; 02279 model_library[2].inputs[0].size = 1; 02280 model_library[2].inputs[0].min_size = 1; 02281 model_library[2].inputs[0].index = 0; 02282 model_library[2].inputs[0].is_clock = FALSE; 02283 model_library[2].inputs[1].dir = IN_PORT; 02284 model_library[2].inputs[1].name = my_strdup("clk"); 02285 model_library[2].inputs[1].next = NULL; 02286 model_library[2].inputs[1].size = 1; 02287 model_library[2].inputs[1].min_size = 1; 02288 model_library[2].inputs[1].index = 0; 02289 model_library[2].inputs[1].is_clock = TRUE; 02290 model_library[2].instances = NULL; 02291 model_library[2].next = &model_library[3]; 02292 model_library[2].outputs = my_calloc(1, sizeof(t_model_ports)); 02293 model_library[2].outputs->dir = OUT_PORT; 02294 model_library[2].outputs->name = my_strdup("Q"); 02295 model_library[2].outputs->next = NULL; 02296 model_library[2].outputs->size = 1; 02297 model_library[2].outputs->min_size = 1; 02298 model_library[2].outputs->index = 0; 02299 model_library[2].outputs->is_clock = FALSE; 02300 02301 model_library[3].name = my_strdup("names"); 02302 model_library[3].index = 3; 02303 model_library[3].inputs = my_calloc(1, sizeof(t_model_ports)); 02304 model_library[3].inputs->dir = IN_PORT; 02305 model_library[3].inputs->name = my_strdup("in"); 02306 model_library[3].inputs->next = NULL; 02307 model_library[3].inputs->size = 1; 02308 model_library[3].inputs->min_size = 1; 02309 model_library[3].inputs->index = 0; 02310 model_library[3].inputs->is_clock = FALSE; 02311 model_library[3].instances = NULL; 02312 model_library[3].next = NULL; 02313 model_library[3].outputs = my_calloc(1, sizeof(t_model_ports)); 02314 model_library[3].outputs->dir = OUT_PORT; 02315 model_library[3].outputs->name = my_strdup("out"); 02316 model_library[3].outputs->next = NULL; 02317 model_library[3].outputs->size = 1; 02318 model_library[3].outputs->min_size = 1; 02319 model_library[3].outputs->index = 0; 02320 model_library[3].outputs->is_clock = FALSE; 02321 02322 arch->model_library = model_library; 02323 } 02324 02325 static void SyncModelsPbTypes(INOUTP struct s_arch *arch, INP t_type_descriptor * Types, INP int NumTypes) { 02326 int i; 02327 for(i = 0; i < NumTypes; i++) { 02328 if(Types[i].pb_type != NULL) { 02329 SyncModelsPbTypes_rec(arch, Types[i].pb_type); 02330 } 02331 } 02332 for(i = 0; i < NumTypes; i++) { 02333 if(Types[i].pb_type != NULL) { 02334 AddModelsToPbTypes_rec(Types[i].pb_type); 02335 } 02336 } 02337 } 02338 02339 02340 static void SyncModelsPbTypes_rec(INOUTP struct s_arch *arch, INOUTP t_pb_type * pb_type) { 02341 int i, j, p; 02342 t_model *model_match_prim, *cur_model; 02343 t_model_ports *model_port; 02344 struct s_linked_vptr *old; 02345 char* blif_model_name; 02346 02347 boolean found; 02348 02349 if(pb_type->blif_model != NULL) { 02350 02351 /* get actual name of subckt */ 02352 if(strstr(pb_type->blif_model, ".subckt ") == pb_type->blif_model) { 02353 blif_model_name = strchr(pb_type->blif_model, ' '); 02354 } else { 02355 blif_model_name = strchr(pb_type->blif_model, '.'); 02356 } 02357 if(blif_model_name) { 02358 blif_model_name++; /* get character after the '.' or ' ' */ 02359 } else { 02360 printf("Unknown blif model %s in pb_type %s\n", pb_type->blif_model, pb_type->name); 02361 } 02362 02363 /* There are two sets of models to consider, the standard library of models and the user defined models */ 02364 if( (strcmp(blif_model_name, "input") == 0) || 02365 (strcmp(blif_model_name, "output") == 0) || 02366 (strcmp(blif_model_name, "names") == 0) || 02367 (strcmp(blif_model_name, "latch") == 0) ) { 02368 cur_model = arch->model_library; 02369 } else { 02370 cur_model = arch->models; 02371 } 02372 02373 /* Determine the logical model to use */ 02374 found = FALSE; 02375 model_match_prim = NULL; 02376 while(cur_model && !found) { 02377 /* blif model always starts with .subckt so need to skip first 8 characters */ 02378 if(strcmp(blif_model_name, cur_model->name) == 0) { 02379 found = TRUE; 02380 model_match_prim = cur_model; 02381 } 02382 cur_model = cur_model->next; 02383 } 02384 if(found != TRUE) { 02385 printf(ERRTAG "No matching model for pb_type %s\n", pb_type->blif_model); 02386 exit(1); 02387 } 02388 02389 02390 pb_type->model = model_match_prim; 02391 old = model_match_prim->pb_types; 02392 model_match_prim->pb_types = (struct s_linked_vptr*) my_malloc(sizeof(struct s_linked_vptr)); 02393 model_match_prim->pb_types->next = old; 02394 model_match_prim->pb_types->data_vptr = pb_type; 02395 02396 for(p = 0; p < pb_type->num_ports; p++) { 02397 found = FALSE; 02398 /* TODO: Parse error checking - check if INPUT matches INPUT and OUTPUT matches OUTPUT (not yet done) */ 02399 model_port = model_match_prim->inputs; 02400 while(model_port && !found) { 02401 if(strcmp(model_port->name, pb_type->ports[p].name) == 0) { 02402 if(model_port->size < pb_type->ports[p].num_pins) { 02403 model_port->size = pb_type->ports[p].num_pins; 02404 } 02405 if(model_port->min_size > pb_type->ports[p].num_pins || model_port->min_size == -1) { 02406 model_port->min_size = pb_type->ports[p].num_pins; 02407 } 02408 pb_type->ports[p].model_port = model_port; 02409 assert(pb_type->ports[p].type == model_port->dir); 02410 assert(pb_type->ports[p].is_clock == model_port->is_clock); 02411 found = TRUE; 02412 } 02413 model_port = model_port->next; 02414 } 02415 model_port = model_match_prim->outputs; 02416 while(model_port && !found) { 02417 if(strcmp(model_port->name, pb_type->ports[p].name) == 0) { 02418 if(model_port->size < pb_type->ports[p].num_pins) { 02419 model_port->size = pb_type->ports[p].num_pins; 02420 } 02421 if(model_port->min_size > pb_type->ports[p].num_pins || model_port->min_size == -1) { 02422 model_port->min_size = pb_type->ports[p].num_pins; 02423 } 02424 pb_type->ports[p].model_port = model_port; 02425 assert(pb_type->ports[p].type == model_port->dir); 02426 found = TRUE; 02427 } 02428 model_port = model_port->next; 02429 } 02430 if(found != TRUE) { 02431 printf(ERRTAG "No matching model port for port %s in pb_type %s\n", pb_type->ports[p].name, pb_type->name); 02432 exit(1); 02433 } 02434 } 02435 } else { 02436 for(i = 0; i < pb_type->num_modes; i++) { 02437 for(j = 0; j < pb_type->modes[i].num_pb_type_children; j++) { 02438 SyncModelsPbTypes_rec(arch, &(pb_type->modes[i].pb_type_children[j])); 02439 } 02440 } 02441 } 02442 } 02443 02444 static void AddModelsToPbTypes_rec(INOUTP t_pb_type *pb_type) { 02445 int i, j; 02446 struct s_linked_vptr *child, *curr; 02447 02448 /* Determine all logical models contained by pb_type */ 02449 if(pb_type->num_modes == 0) { 02450 pb_type->models_contained = my_malloc(sizeof(struct s_linked_vptr)); 02451 pb_type->models_contained->data_vptr = pb_type->model; 02452 pb_type->models_contained->next = NULL; 02453 } else { 02454 pb_type->models_contained = NULL; 02455 for(i = 0; i < pb_type->num_modes; i++) { 02456 for(j = 0; j < pb_type->modes[i].num_pb_type_children; j++) { 02457 AddModelsToPbTypes_rec(&pb_type->modes[i].pb_type_children[j]); 02458 child = pb_type->modes[i].pb_type_children[j].models_contained; 02459 /* find model in parent that matches with that in child, if not, add to parent */ 02460 while(child) { 02461 curr = pb_type->models_contained; 02462 while(curr) { 02463 if(curr->data_vptr == child->data_vptr) { 02464 break; 02465 } 02466 curr = curr->next; 02467 } 02468 if(curr == NULL) { 02469 curr = my_malloc(sizeof(struct s_linked_vptr)); 02470 curr->next = pb_type->models_contained; 02471 curr->data_vptr = child->data_vptr; 02472 pb_type->models_contained = curr; 02473 } 02474 child = child->next; 02475 } 02476 } 02477 } 02478 } 02479 } 02480 02481 static void UpdateAndCheckModels(INOUTP struct s_arch *arch) { 02482 t_model * cur_model; 02483 t_model_ports *port; 02484 int i, j; 02485 cur_model = arch->models; 02486 while(cur_model) { 02487 if(cur_model->pb_types == NULL) { 02488 printf("No pb_type found for model %s\n", cur_model->name); 02489 exit(1); 02490 } 02491 port = cur_model->inputs; 02492 i = 0; 02493 j = 0; 02494 while(port) { 02495 if(port->is_clock) { 02496 port->index = i; 02497 i++; 02498 } else { 02499 port->index = j; 02500 j++; 02501 } 02502 port = port->next; 02503 } 02504 port = cur_model->outputs; 02505 i = 0; 02506 while(port) { 02507 port->index = i; 02508 i++; 02509 port = port->next; 02510 } 02511 cur_model = cur_model->next; 02512 } 02513 } 02514 02515 02516 /** Output the data from architecture data so user can verify it 02517 * was interpretted correctly. 02518 */ 02519 void 02520 EchoArch(INP const char *EchoFile, INP const t_type_descriptor * Types, 02521 INP int NumTypes, struct s_arch *arch) 02522 { 02523 int i, j; 02524 FILE * Echo; 02525 t_model * cur_model; 02526 t_model_ports * model_port; 02527 struct s_linked_vptr *cur_vptr; 02528 02529 02530 Echo = my_fopen(EchoFile, "w", 0); 02531 cur_model = NULL; 02532 02533 for( j = 0; j < 2; j++ ) { 02534 if(j == 0) { 02535 fprintf(Echo, "Printing user models \n"); 02536 cur_model = arch->models; 02537 } else if(j == 1) { 02538 fprintf(Echo, "Printing library models \n"); 02539 cur_model = arch->model_library; 02540 } 02541 while(cur_model) { 02542 fprintf(Echo, "Model: \"%s\"\n", cur_model->name); 02543 model_port = cur_model->inputs; 02544 while(model_port) { 02545 fprintf(Echo, "\tInput Ports: \"%s\" \"%d\" min_size=\"%d\"\n", model_port->name, model_port->size, model_port->min_size); 02546 model_port = model_port->next; 02547 } 02548 model_port = cur_model->outputs; 02549 while(model_port) { 02550 fprintf(Echo, "\tOutput Ports: \"%s\" \"%d\" min_size=\"%d\"\n", model_port->name, model_port->size, model_port->min_size); 02551 model_port = model_port->next; 02552 } 02553 cur_vptr = cur_model->pb_types; 02554 i = 0; 02555 while(cur_vptr != NULL) { 02556 fprintf(Echo, "\tpb_type %d: \"%s\"\n", i, ((t_pb_type*)cur_vptr->data_vptr)->name); 02557 cur_vptr = cur_vptr->next; 02558 i++; 02559 } 02560 02561 cur_model = cur_model->next; 02562 } 02563 } 02564 02565 for(i = 0; i < NumTypes; ++i) 02566 { 02567 fprintf(Echo, "Type: \"%s\"\n", Types[i].name); 02568 fprintf(Echo, "\tcapacity: %d\n", Types[i].capacity); 02569 fprintf(Echo, "\theight: %d\n", Types[i].height); 02570 02571 fprintf(Echo, "\tis_Fc_frac: %s\n", 02572 (Types[i].is_Fc_frac ? "TRUE" : "FALSE")); 02573 fprintf(Echo, "\tis_Fc_out_full_flex: %s\n", 02574 (Types[i].is_Fc_out_full_flex ? "TRUE" : "FALSE")); 02575 fprintf(Echo, "\tFc_in: %f\n", Types[i].Fc_in); 02576 fprintf(Echo, "\tFc_out: %f\n", Types[i].Fc_out); 02577 02578 02579 fprintf(Echo, "\tnum_drivers: %d\n", Types[i].num_drivers); 02580 fprintf(Echo, "\tnum_receivers: %d\n", Types[i].num_receivers); 02581 fprintf(Echo, "\tindex: %d\n", Types[i].index); 02582 if(Types[i].pb_type) { 02583 PrintPb_types_rec(Echo, Types[i].pb_type, 2); 02584 } 02585 fprintf(Echo, "\n"); 02586 } 02587 fclose(Echo); 02588 } 02589 02590 static void 02591 PrintPb_types_rec(INP FILE * Echo, INP const t_pb_type * pb_type, int level) 02592 { 02593 int i, j, k; 02594 char *tabs; 02595 02596 tabs = my_malloc((level + 1) * sizeof(char)); 02597 for(i = 0; i < level; i++) { 02598 tabs[i] = '\t'; 02599 } 02600 tabs[level] = '\0'; 02601 02602 fprintf(Echo, "%spb_type name: %s\n", tabs, pb_type->name); 02603 fprintf(Echo, "%s\tblif_model: %s\n", tabs, pb_type->blif_model); 02604 fprintf(Echo, "%s\tclass_type: %d\n", tabs, pb_type->class_type); 02605 fprintf(Echo, "%s\tnum_modes: %d\n", tabs, pb_type->num_modes); 02606 fprintf(Echo, "%s\tnum_ports: %d\n", tabs, pb_type->num_ports); 02607 for(i = 0; i < pb_type->num_ports; i++) { 02608 fprintf(Echo, "%s\tport %s type %d num_pins %d\n", tabs, 02609 pb_type->ports[i].name, 02610 pb_type->ports[i].type, 02611 pb_type->ports[i].num_pins); 02612 } 02613 for(i = 0; i < pb_type->num_modes; i++) { 02614 fprintf(Echo, "%s\tmode %s:\n", tabs, pb_type->modes[i].name); 02615 for(j = 0; j < pb_type->modes[i].num_pb_type_children; j++) { 02616 PrintPb_types_rec(Echo, &pb_type->modes[i].pb_type_children[j], level + 2); 02617 } 02618 for(j = 0; j < pb_type->modes[i].num_interconnect; j++) { 02619 fprintf(Echo, "%s\t\tinterconnect %d %s %s\n", tabs, pb_type->modes[i].interconnect[j].type, 02620 pb_type->modes[i].interconnect[j].input_string, 02621 pb_type->modes[i].interconnect[j].output_string); 02622 for(k = 0; k < pb_type->modes[i].interconnect[j].num_annotations; k++) { 02623 fprintf(Echo, "%s\t\t\tannotation %s %s %d: %s\n", tabs, pb_type->modes[i].interconnect[j].annotations[k].input_pins, 02624 pb_type->modes[i].interconnect[j].annotations[k].output_pins, pb_type->modes[i].interconnect[j].annotations[k].format, 02625 pb_type->modes[i].interconnect[j].annotations[k].value[0]); 02626 } 02627 } 02628 } 02629 free(tabs); 02630 } 02631 02632 02633