blob: b315fc0f5d27c56906928c2f0a44ab93a45603a3 [file] [log] [blame]
#include <string.h>
#include <assert.h>
#include "util.h"
#include "vpr_types.h"
#include "ReadLine.h"
#include "ezxml.h"
#include "globals.h"
#include "xml_arch.h"
/* special type indexes, necessary for initialization initialization, everything afterwards
should use the pointers to these type indices*/
#define EMPTY_TYPE_INDEX 0
#define IO_TYPE_INDEX 1
enum Fc_type
{ FC_ABS, FC_FRAC, FC_FULL };
/* Function prototypes */
static boolean IsWhitespace(char c);
static void CountTokensInString(IN const char *Str,
OUT int *Num,
OUT int *Len);
static char **GetNodeTokens(IN ezxml_t Node);
static void CheckElement(IN ezxml_t Node,
IN const char *Name);
static void CheckText(IN ezxml_t Node);
static void FreeNode(INOUT ezxml_t Node);
static ezxml_t FindElement(IN ezxml_t Parent,
IN const char *Name,
IN boolean Required);
static const char *FindProperty(IN ezxml_t Parent,
IN const char *Name,
IN boolean Required);
static int CountChildren(IN ezxml_t Node,
IN const char *Name);
static void ParseFc(ezxml_t Node,
enum Fc_type *Fc,
float *Val);
static void SetupEmptyType();
static void SetupClassInf(ezxml_t Classes,
t_type_descriptor * Type);
static void SetupPinClasses(ezxml_t Classes,
t_type_descriptor * Type);
static void SetupPinLocations(ezxml_t Locations,
t_type_descriptor * Type);
static void SetupGridLocations(ezxml_t Locations,
t_type_descriptor * Type);
static void SetupTypeTiming(ezxml_t timing,
t_type_descriptor * Type);
static void SetupSubblocksTcomb(ezxml_t timing,
t_type_descriptor * Type);
static void SetupSubblocksTSeq(ezxml_t timing_seq_in,
ezxml_t timing_seq_out,
t_type_descriptor * Type);
static void Process_Fc(ezxml_t Fc_in_node,
ezxml_t Fc_out_node,
t_type_descriptor * Type);
static void ProcessSubblocks(INOUT ezxml_t Parent,
INOUT t_type_descriptor * Type,
IN boolean timing_enabled);
static void ProcessTypeProps(ezxml_t Node,
t_type_descriptor * Type);
static void ProcessChanWidthDistr(INOUT ezxml_t Node,
OUT struct s_arch *arch);
static void ProcessChanWidthDistrDir(INOUT ezxml_t Node,
OUT t_chan * chan);
static void ProcessLayout(INOUT ezxml_t Node,
OUT struct s_arch *arch);
static void ProcessDevice(INOUT ezxml_t Node,
OUT struct s_arch *arch,
IN boolean timing_enabled);
static void ProcessIO(INOUT ezxml_t Node,
IN boolean timing_enabled);
static void ProcessTypes(INOUT ezxml_t Node,
OUT t_type_descriptor ** Types,
OUT int *NumTypes,
IN boolean timing_enabled);
static void ProcessSwitches(INOUT ezxml_t Node,
OUT struct s_switch_inf **Switches,
OUT int *NumSwitches,
IN boolean timing_enabled);
static void ProcessSegments(INOUT ezxml_t Parent,
OUT struct s_segment_inf **Segs,
OUT int *NumSegs,
IN struct s_switch_inf *Switches,
IN int NumSwitches,
IN boolean timing_enabled);
static void ProcessCB_SB(INOUT ezxml_t Node,
INOUT boolean * list,
IN int len);
/* Returns TRUE if character is whatspace between tokens */
static boolean
IsWhitespace(char c)
{
switch (c)
{
case ' ':
case '\t':
case '\r':
case '\n':
return TRUE;
default:
return FALSE;
}
}
/* Count tokens and length in all the Text children nodes of current node. */
static void
CountTokensInString(IN const char *Str,
OUT int *Num,
OUT int *Len)
{
boolean InToken;
*Num = 0;
*Len = 0;
InToken = FALSE;
while(*Str)
{
if(IsWhitespace(*Str))
{
InToken = FALSE;
}
else
{
if(!InToken)
{
++(*Num);
}
++(*Len);
InToken = TRUE;
}
++Str; /* Advance pointer */
}
}
/* Returns a token list of the text nodes of a given node. This
* unlinks all the text nodes from the document */
static char **
GetNodeTokens(IN ezxml_t Node)
{
int Count, Len;
char *Cur, *Dst;
boolean InToken;
char **Tokens;
/* Count the tokens and find length of token data */
CountTokensInString(Node->txt, &Count, &Len);
/* Error out if no tokens found */
if(Count < 1)
{
printf(ERRTAG "Tag '%s' expected enclosed text data "
"but none was found.\n", Node->name);
exit(1);
}
Len = (sizeof(char) * Len) + /* Length of actual data */
(sizeof(char) * Count); /* Null terminators */
/* Alloc the pointer list and data list. Count the final
* empty string we will use as list terminator */
Tokens = (char **)my_malloc(sizeof(char *) * (Count + 1));
Dst = (char *)my_malloc(sizeof(char) * Len);
Count = 0;
/* Copy data to tokens */
Cur = Node->txt;
InToken = FALSE;
while(*Cur)
{
if(IsWhitespace(*Cur))
{
if(InToken)
{
*Dst = '\0';
++Dst;
}
InToken = FALSE;
}
else
{
if(!InToken)
{
Tokens[Count] = Dst;
++Count;
}
*Dst = *Cur;
++Dst;
InToken = TRUE;
}
++Cur;
}
if(InToken)
{ /* Null term final token */
*Dst = '\0';
++Dst;
}
ezxml_set_txt(Node, "");
Tokens[Count] = NULL; /* End of tokens marker is a NULL */
/* Return the list */
return Tokens;
}
/* Checks the node is an element with name equal to one given */
static void
CheckElement(IN ezxml_t Node,
IN const char *Name)
{
if(0 != strcmp(Node->name, Name))
{
printf(ERRTAG
"Element '%s' within element '%s' does match expected "
"element type of '%s'\n", Node->name, Node->parent->name,
Name);
exit(1);
}
}
/* Checks that the node has no remaining child nodes or property nodes,
* then unlinks the node from the tree which updates pointers and
* frees the memory */
static void
FreeNode(INOUT ezxml_t Node)
{
ezxml_t Cur;
char *Txt;
/* Shouldn't have unprocessed properties */
if(Node->attr[0])
{
printf(ERRTAG "Node '%s' has invalid property %s=\"%s\".\n",
Node->name, Node->attr[0], Node->attr[1]);
exit(1);
}
/* Shouldn't have non-whitespace text */
Txt = Node->txt;
while(*Txt)
{
if(!IsWhitespace(*Txt))
{
printf(ERRTAG
"Node '%s' has unexpected text '%s' within it.\n",
Node->name, Node->txt);
exit(1);
}
++Txt;
}
/* We shouldn't have child items left */
Cur = Node->child;
if(Cur)
{
printf(ERRTAG "Node '%s' on has invalid child node '%s'.\n",
Node->name, Cur->name);
exit(1);
}
/* Now actually unlink and free the node */
ezxml_remove(Node);
}
/* Finds child element with given name and returns it. Errors out if
* more than one instance exists. */
static ezxml_t
FindElement(IN ezxml_t Parent,
IN const char *Name,
IN boolean Required)
{
ezxml_t Cur;
/* Find the first node of correct name */
Cur = ezxml_child(Parent, Name);
/* Error out if node isn't found but they required it */
if(Required)
{
if(NULL == Cur)
{
printf(ERRTAG
"Element '%s' not found within element '%s'.\n",
Name, Parent->name);
exit(1);
}
}
/* Look at next tag with same name and error out if exists */
if(Cur != NULL && Cur->next)
{
printf(ERRTAG "Element '%s' found twice within element '%s'.\n",
Name, Parent->name);
exit(1);
}
return Cur;
}
static const char *
FindProperty(IN ezxml_t Parent,
IN const char *Name,
IN boolean Required)
{
const char *Res;
Res = ezxml_attr(Parent, Name);
if(Required)
{
if(NULL == Res)
{
printf(ERRTAG
"Required property '%s' not found for element '%s'.\n",
Name, Parent->name);
exit(1);
}
}
return Res;
}
/* Counts number of child elements in a container element.
* Name is the name of the child element.
* Errors if no occurances found. */
static int
CountChildren(IN ezxml_t Node,
IN const char *Name)
{
ezxml_t Cur, sibling;
int Count;
Count = 0;
Cur = Node->child;
while(Cur)
{
if(strcmp(Cur->name, Name) == 0)
{
++Count;
}
sibling = Cur->sibling;
Cur = Cur->next;
if(Cur == NULL)
{
Cur = sibling;
}
}
/* Error if no occurances found */
if(Count < 1)
{
printf(ERRTAG "Expected node '%s' to have "
"child elements, but none found.\n", Node->name);
exit(1);
}
return Count;
}
/* Figures out the Fc type and value for the given node. Unlinks the
* type and value. */
static void
ParseFc(ezxml_t Node,
enum Fc_type *Fc,
float *Val)
{
const char *Prop;
Prop = FindProperty(Node, "type", TRUE);
if(0 == strcmp(Prop, "abs"))
{
*Fc = FC_ABS;
}
else if(0 == strcmp(Prop, "frac"))
{
*Fc = FC_FRAC;
}
else if(0 == strcmp(Prop, "full"))
{
*Fc = FC_FULL;
}
else
{
printf(ERRTAG "Invalid type '%s' for Fc. Only abs, frac "
"and full are allowed.\n", Prop);
exit(1);
}
switch (*Fc)
{
case FC_FULL:
*Val = 0.0;
break;
case FC_ABS:
case FC_FRAC:
*Val = atof(Node->txt);
ezxml_set_attr(Node, "type", NULL);
ezxml_set_txt(Node, "");
break;
default:
assert(0);
}
/* Release the property */
ezxml_set_attr(Node, "type", NULL);
}
/* Set's up the classinf data of a type and counts the number of
* pins the type has. If capacity > 1, we need multiple sets of classes.
* This correctly sets num_pins to include all the replicated but
* unique pins that give the capacity. */
static void
SetupClassInf(ezxml_t Classes,
t_type_descriptor * Type)
{
int i, k, CurClass, CurPin, NumClassPins;
ezxml_t Cur;
const char *Prop;
/* Alloc class_inf structs */
Type->num_class = Type->capacity * CountChildren(Classes, "class");
Type->class_inf =
(t_class *) my_malloc(Type->num_class * sizeof(t_class));
/* Make multiple passes to handle capacity with index increased each pass */
CurPin = 0;
CurClass = 0;
Type->num_pins = 0;
Type->num_drivers = 0;
Type->num_receivers = 0;
for(i = 0; i < Type->capacity; ++i)
{
/* Restart the parse tree at each node */
Cur = Classes->child;
while(Cur)
{
CheckElement(Cur, "class");
/* Count the number of pins in this class */
CountTokensInString(Cur->txt, &NumClassPins, &k);
Type->num_pins += NumClassPins;
/* Alloc class structures */
Type->class_inf[CurClass].num_pins = NumClassPins;
Type->class_inf[CurClass].pinlist =
(int *)my_malloc(NumClassPins * sizeof(int));
for(k = 0; k < NumClassPins; ++k)
{
Type->class_inf[CurClass].pinlist[k] = CurPin;
++CurPin;
}
/* Figure out class type */
Prop = FindProperty(Cur, "type", TRUE);
if(0 == strcmp(Prop, "in"))
{
Type->num_receivers += NumClassPins;
Type->class_inf[CurClass].type = RECEIVER;
}
else if(0 == strcmp(Prop, "out"))
{
Type->num_drivers += NumClassPins;
Type->class_inf[CurClass].type = DRIVER;
}
else if(0 == strcmp(Prop, "global"))
{
Type->class_inf[CurClass].type = RECEIVER;
}
else
{
printf(ERRTAG "Invalid pin class type '%s'.\n",
Prop);
exit(1);
}
++CurClass;
Cur = Cur->next;
}
}
}
/* Allocs structures that describe pins and reads pin names. Sets
* pin/class mappings. Unliinks the class descriptor nodes from XML.
* For capacity > 1 pins and pinclasses are replicated because while
* they share the same properties and setup, they are treated as
* being unique. */
static void
SetupPinClasses(ezxml_t Classes,
t_type_descriptor * Type)
{
int CurClass, i, j, CurPin, PinsPerSubtile, ClassesPerSubtile;
ezxml_t Cur, Prev;
const char *Prop;
boolean IsGlobal;
char **Tokens;
int *pin_used = NULL;
/* Allocs and sets up the classinf data and counts pins */
SetupClassInf(Classes, Type);
PinsPerSubtile = Type->num_pins / Type->capacity;
ClassesPerSubtile = Type->num_class / Type->capacity;
/* Alloc num_pin sized lists. Replicated pins don't have new names. */
Type->is_global_pin =
(boolean *) my_malloc(Type->num_pins * sizeof(boolean));
Type->pin_class = (int *)my_malloc(Type->num_pins * sizeof(int));
pin_used = (int *)my_malloc(Type->num_pins * sizeof(int));
for(i = 0; i < Type->num_pins; ++i)
{
pin_used[i] = FALSE;
}
/* Iterate over all pins */
CurClass = 0;
Cur = Classes->child;
while(Cur)
{
CheckElement(Cur, "class");
/* Figure out if global class */
IsGlobal = FALSE;
Prop = FindProperty(Cur, "type", TRUE);
if(0 == strcmp(Prop, "global"))
{
IsGlobal = TRUE;
}
ezxml_set_attr(Cur, "type", NULL);
/* Itterate over pins in the class */
Tokens = GetNodeTokens(Cur);
assert(CountTokens(Tokens) ==
Type->class_inf[CurClass].num_pins);
for(j = 0; j < Type->class_inf[CurClass].num_pins; ++j)
{
CurPin = my_atoi(Tokens[j]);
/* Check for duplicate pin names */
if(pin_used[CurPin])
{
printf(ERRTAG
"Pin %d is defined in two different classes in type '%s'.\n",
CurPin, Type->name);
exit(1);
}
pin_used[CurPin] = TRUE;
/* Set the pin class and is_global status */
for(i = 0; i < Type->capacity; ++i)
{
Type->pin_class[CurPin + (i * PinsPerSubtile)] =
CurClass + (i * ClassesPerSubtile);
Type->is_global_pin[CurPin +
(i * PinsPerSubtile)] =
IsGlobal;
}
}
FreeTokens(&Tokens);
++CurClass;
Prev = Cur;
Cur = Cur->next;
FreeNode(Prev);
}
if(pin_used)
{
free(pin_used);
pin_used = NULL;
}
}
/* Sets up the pinloc map for the type. Unlinks the loc nodes
* from the XML tree.
* Pins and pin classses must already be setup by SetupPinClasses */
static void
SetupPinLocations(ezxml_t Locations,
t_type_descriptor * Type)
{
int i, j, k, l, PinsPerSubtile, Count, Len;
ezxml_t Cur, Prev;
const char *Prop;
char **Tokens, **CurTokens;
PinsPerSubtile = Type->num_pins / Type->capacity;
/* Alloc and clear pin locations */
Type->pinloc = (int ***)my_malloc(Type->height * sizeof(int **));
for(i = 0; i < Type->height; ++i)
{
Type->pinloc[i] = (int **)my_malloc(4 * sizeof(int *));
for(j = 0; j < 4; ++j)
{
Type->pinloc[i][j] =
(int *)my_malloc(Type->num_pins * sizeof(int));
for(k = 0; k < Type->num_pins; ++k)
{
Type->pinloc[i][j][k] = 0;
}
}
}
/* Load the pin locations */
Cur = Locations->child;
while(Cur)
{
CheckElement(Cur, "loc");
/* Get offset */
i = 0;
Prop = FindProperty(Cur, "offset", FALSE);
if(Prop)
{
i = my_atoi(Prop);
if((i < 0) || (i >= Type->height))
{
printf(ERRTAG
"%d is an invalid offset for type '%s'.\n",
i, Type->name);
exit(1);
}
ezxml_set_attr(Cur, "offset", NULL);
}
/* Get side */
Prop = FindProperty(Cur, "side", TRUE);
if(0 == strcmp(Prop, "left"))
{
j = LEFT;
}
else if(0 == strcmp(Prop, "top"))
{
j = TOP;
}
else if(0 == strcmp(Prop, "right"))
{
j = RIGHT;
}
else if(0 == strcmp(Prop, "bottom"))
{
j = BOTTOM;
}
else
{
printf(ERRTAG "'%s' is not a valid side.\n", Prop);
exit(1);
}
ezxml_set_attr(Cur, "side", NULL);
/* Check location is on perimeter */
if((TOP == j) && (i != (Type->height - 1)))
{
printf(ERRTAG
"Locations are only allowed on large block "
"perimeter. 'top' side should be at offset %d only.\n",
(Type->height - 1));
exit(1);
}
if((BOTTOM == j) && (i != 0))
{
printf(ERRTAG
"Locations are only allowed on large block "
"perimeter. 'bottom' side should be at offset 0 only.\n");
exit(1);
}
/* Go through lists of pins */
CountTokensInString(Cur->txt, &Count, &Len);
if(Count > 0)
{
Tokens = GetNodeTokens(Cur);
CurTokens = Tokens;
while(*CurTokens)
{
/* Get pin */
k = my_atoi(*CurTokens);
if(k >= Type->num_pins)
{
printf(ERRTAG
"Pin %d of type '%s' is not a valid pin.\n",
k, Type->name);
exit(1);
}
/* Set pin location */
for(l = 0; l < Type->capacity; ++l)
{
Type->pinloc[i][j][k + (l * PinsPerSubtile)] = 1;
}
/* Advance through list of pins in this location */
++CurTokens;
}
FreeTokens(&Tokens);
}
Prev = Cur;
Cur = Cur->next;
FreeNode(Prev);
}
}
/* Sets up the grid_loc_def for the type. Unlinks the loc nodes
* from the XML tree. */
static void
SetupGridLocations(ezxml_t Locations,
t_type_descriptor * Type)
{
int i;
ezxml_t Cur, Prev;
const char *Prop;
Type->num_grid_loc_def = CountChildren(Locations, "loc");
Type->grid_loc_def =
(struct s_grid_loc_def *)my_calloc(Type->num_grid_loc_def,
sizeof(struct s_grid_loc_def));
/* Load the pin locations */
Cur = Locations->child;
i = 0;
while(Cur)
{
CheckElement(Cur, "loc");
/* loc index */
Prop = FindProperty(Cur, "type", TRUE);
if(Prop)
{
if(strcmp(Prop, "fill") == 0)
{
if(Type->num_grid_loc_def != 1)
{
printf(ERRTAG
"Another loc specified for fill.\n");
exit(1);
}
Type->grid_loc_def[i].grid_loc_type = FILL;
FILL_TYPE = Type;
}
else if(strcmp(Prop, "col") == 0)
{
Type->grid_loc_def[i].grid_loc_type = COL_REPEAT;
}
else if(strcmp(Prop, "rel") == 0)
{
Type->grid_loc_def[i].grid_loc_type = COL_REL;
}
else
{
printf(ERRTAG
"Unknown grid location type '%s' for type '%s'.\n",
Prop, Type->name);
exit(1);
}
ezxml_set_attr(Cur, "type", NULL);
}
Prop = FindProperty(Cur, "start", FALSE);
if(Type->grid_loc_def[i].grid_loc_type == COL_REPEAT)
{
if(Prop == NULL)
{
printf(ERRTAG
"grid location property 'start' must be specified for grid location type 'col'.\n");
exit(1);
}
Type->grid_loc_def[i].start_col = my_atoi(Prop);
ezxml_set_attr(Cur, "start", NULL);
}
else if(Prop != NULL)
{
printf(ERRTAG
"grid location property 'start' valid for grid location type 'col' only.\n");
exit(1);
}
Prop = FindProperty(Cur, "repeat", FALSE);
if(Type->grid_loc_def[i].grid_loc_type == COL_REPEAT)
{
if(Prop != NULL)
{
Type->grid_loc_def[i].repeat = my_atoi(Prop);
ezxml_set_attr(Cur, "repeat", NULL);
}
}
else if(Prop != NULL)
{
printf(ERRTAG
"grid location property 'repeat' valid for grid location type 'col' only.\n");
exit(1);
}
Prop = FindProperty(Cur, "pos", FALSE);
if(Type->grid_loc_def[i].grid_loc_type == COL_REL)
{
if(Prop == NULL)
{
printf(ERRTAG
"grid location property 'pos' must be specified for grid location type 'rel'.\n");
exit(1);
}
Type->grid_loc_def[i].col_rel = atof(Prop);
ezxml_set_attr(Cur, "pos", NULL);
}
else if(Prop != NULL)
{
printf(ERRTAG
"grid location property 'pos' valid for grid location type 'rel' only.\n");
exit(1);
}
Prop = FindProperty(Cur, "priority", FALSE);
if(Prop)
{
Type->grid_loc_def[i].priority = my_atoi(Prop);
ezxml_set_attr(Cur, "priority", NULL);
}
Prev = Cur;
Cur = Cur->next;
FreeNode(Prev);
i++;
}
}
static void
SetupTypeTiming(ezxml_t timing,
t_type_descriptor * Type)
{
ezxml_t Cur, Prev;
const char *Prop;
float value;
char **Tokens;
/* Clear timing info for type */
Type->type_timing_inf.T_fb_ipin_to_sblk_ipin = 0;
Type->type_timing_inf.T_sblk_opin_to_fb_opin = 0;
Type->type_timing_inf.T_sblk_opin_to_sblk_ipin = 0;
/* Load the timing info */
Cur = timing->child;
while(Cur)
{
CheckElement(Cur, "tedge");
/* Get timing type */
Prop = FindProperty(Cur, "type", TRUE);
Tokens = GetNodeTokens(Cur);
if(CountTokens(Tokens) != 1)
{
printf(ERRTAG
"Timing for sequential subblock edges not a number.");
}
value = atof(Tokens[0]);
if(0 == strcmp(Prop, "T_fb_ipin_to_sblk_ipin"))
{
Type->type_timing_inf.T_fb_ipin_to_sblk_ipin = value;
}
else if(0 == strcmp(Prop, "T_sblk_opin_to_fb_opin"))
{
Type->type_timing_inf.T_sblk_opin_to_fb_opin = value;
}
else if(0 == strcmp(Prop, "T_sblk_opin_to_sblk_ipin"))
{
Type->type_timing_inf.T_sblk_opin_to_sblk_ipin = value;
}
else
{
printf(ERRTAG "'%s' is an unrecognized timing edge.\n",
Prop);
exit(1);
}
ezxml_set_attr(Cur, "type", NULL);
Prev = Cur;
Cur = Cur->next;
FreeNode(Prev);
FreeTokens(&Tokens);
}
}
static void
SetupSubblocksTcomb(ezxml_t timing,
t_type_descriptor * Type)
{
ezxml_t Cur, prev;
t_T_subblock ** T_subblock_ptr;
float **t_comb;
int i, j;
char **Tokens;
T_subblock_ptr = &Type->type_timing_inf.T_subblock;
t_comb =
(float **)alloc_matrix(0, Type->max_subblock_inputs - 1, 0,
Type->max_subblock_outputs - 1, sizeof(float));
for(i = 0; i < Type->max_subblock_inputs; i++)
{
for(j = 0; j < Type->max_subblock_outputs; j++)
{
t_comb[i][j] = 0;
}
}
/* Load the timing info */
Cur = timing->child;
i = 0;
while(Cur)
{
CheckElement(Cur, "trow");
Tokens = GetNodeTokens(Cur);
if(CountTokens(Tokens) != Type->max_subblock_outputs)
{
printf(ERRTAG
"Number of tokens %d not equal number of subblock outputs %d.",
CountTokens(Tokens),
Type->max_subblock_outputs);
exit(1);
}
for(j = 0; j < Type->max_subblock_outputs; j++)
{
t_comb[i][j] = atof(Tokens[j]);
}
i++;
prev = Cur;
Cur = Cur->next;
FreeNode(prev);
FreeTokens(&Tokens);
}
if(i != Type->max_subblock_inputs)
{
printf(ERRTAG
"Number of trow %d not equal number of subblock inputs %d.",
i, Type->max_subblock_inputs);
exit(1);
}
for(i = 0; i < Type->max_subblocks; i++)
{
(*T_subblock_ptr)[i].T_comb = t_comb;
}
}
static void
SetupSubblocksTSeq(ezxml_t timing_seq_in,
ezxml_t timing_seq_out,
t_type_descriptor * Type)
{
ezxml_t Cur, prev;
t_T_subblock ** T_subblock_ptr;
int i, j;
float *t_seq[2];
ezxml_t seq_timing[2];
char **Tokens;
T_subblock_ptr = &Type->type_timing_inf.T_subblock;
seq_timing[0] = timing_seq_in;
seq_timing[1] = timing_seq_out;
t_seq[0] = (float *)my_calloc(Type->max_subblock_inputs, sizeof(float));
t_seq[1] = (float *)my_calloc(Type->max_subblock_outputs, sizeof(float));
/* Load the timing info */
for(i = 0; i < 2; i++)
{
Cur = seq_timing[i]->child;
j = 0;
while(Cur)
{
CheckElement(Cur, "trow");
Tokens = GetNodeTokens(Cur);
if(CountTokens(Tokens) != 1)
{
printf(ERRTAG
"Timing for sequential subblock edges not a number.");
}
t_seq[i][j] = atof(Tokens[0]);
j++;
prev = Cur;
Cur = Cur->next;
FreeNode(prev);
FreeTokens(&Tokens);
}
if(j != Type->max_subblock_outputs)
{
printf(ERRTAG
"Number of trow %d not equal number of subblock outputs %d.",
j, Type->max_subblock_outputs);
exit(1);
}
}
for(i = 0; i < Type->max_subblocks; i++)
{
(*T_subblock_ptr)[i].T_seq_in = t_seq[0];
(*T_subblock_ptr)[i].T_seq_out = t_seq[1];
}
}
/* Takes in the node ptr for the 'fc_in' and 'fc_out' elements and initializes
* the appropriate fields of type. Unlinks the contents of the nodes. */
static void
Process_Fc(ezxml_t Fc_in_node,
ezxml_t Fc_out_node,
t_type_descriptor * Type)
{
enum Fc_type Type_in;
enum Fc_type Type_out;
ParseFc(Fc_in_node, &Type_in, &Type->Fc_in);
ParseFc(Fc_out_node, &Type_out, &Type->Fc_out);
if(FC_FULL == Type_in)
{
printf(ERRTAG "'full' Fc type isn't allowed for Fc_in.\n");
exit(1);
}
Type->is_Fc_out_full_flex = FALSE;
Type->is_Fc_frac = FALSE;
if(FC_FULL == Type_out)
{
Type->is_Fc_out_full_flex = TRUE;
}
else if(Type_in != Type_out)
{
printf(ERRTAG
"Fc_in and Fc_out must have same type unless Fc_out has type 'full'.\n");
exit(1);
}
if(FC_FRAC == Type_in)
{
Type->is_Fc_frac = TRUE;
}
}
/* This parses contents of the 'subblocks' element and unlinks from tree */
static void
ProcessSubblocks(INOUT ezxml_t Parent,
INOUT t_type_descriptor * Type,
boolean timing_enabled)
{
const char *Prop;
ezxml_t CurType, Cur, Cur2;
Type->max_subblocks = 1;
Prop = FindProperty(Parent, "max_subblocks", FALSE);
if(Prop)
{
Type->max_subblocks = my_atoi(Prop);
ezxml_set_attr(Parent, "max_subblocks", NULL);
}
Type->max_subblock_inputs = 1;
Prop = FindProperty(Parent, "max_subblock_inputs", FALSE);
if(Prop)
{
Type->max_subblock_inputs = my_atoi(Prop);
ezxml_set_attr(Parent, "max_subblock_inputs", NULL);
}
Type->max_subblock_outputs = 1;
Prop = FindProperty(Parent, "max_subblock_outputs", FALSE);
if(Prop)
{
Type->max_subblock_outputs = my_atoi(Prop);
ezxml_set_attr(Parent, "max_subblock_outputs", NULL);
}
CurType = FindElement(Parent, "timing", timing_enabled);
if(CurType != NULL)
{
Type->type_timing_inf.T_subblock =
(t_T_subblock *) my_malloc(Type->max_subblocks *
sizeof(t_T_subblock));
/* Load T_comb timing for subblock */
Cur = FindElement(CurType, "T_comb", TRUE);
SetupSubblocksTcomb(Cur, Type);
FreeNode(Cur);
/* Load Fc */
Cur = FindElement(CurType, "T_seq_in", TRUE);
Cur2 = FindElement(CurType, "T_seq_out", TRUE);
SetupSubblocksTSeq(Cur, Cur2, Type);
FreeNode(Cur);
FreeNode(Cur2);
FreeNode(CurType);
}
}
/* Thie processes attributes of the 'type' tag and then unlinks them */
static void
ProcessTypeProps(ezxml_t Node,
t_type_descriptor * Type)
{
const char *Prop;
/* Load type name */
Prop = FindProperty(Node, "name", TRUE);
Type->name = my_strdup(Prop);
ezxml_set_attr(Node, "name", NULL);
/* Load capacity */
Type->capacity = 1; /* DEFAULT */
/* Load height */
Type->height = 1; /* DEFAULT */
Prop = FindProperty(Node, "height", FALSE);
if(Prop)
{
Type->height = my_atoi(Prop);
ezxml_set_attr(Node, "height", NULL);
}
}
/* Takes in node pointing to <layout> and loads all the
* child type objects. Unlinks the entire <layout> node
* when complete. */
static void
ProcessLayout(INOUT ezxml_t Node,
OUT struct s_arch *arch)
{
const char *Prop;
arch->clb_grid.IsAuto = TRUE;
/* Load width and height if applicable */
Prop = FindProperty(Node, "width", FALSE);
if(Prop != NULL)
{
arch->clb_grid.IsAuto = FALSE;
arch->clb_grid.W = my_atoi(Prop);
ezxml_set_attr(Node, "width", NULL);
Prop = FindProperty(Node, "height", TRUE);
if(Prop != NULL)
{
arch->clb_grid.H = my_atoi(Prop);
ezxml_set_attr(Node, "height", NULL);
}
}
/* Load aspect ratio if applicable */
Prop = FindProperty(Node, "auto", arch->clb_grid.IsAuto);
if(Prop != NULL)
{
if(arch->clb_grid.IsAuto == FALSE)
{
printf(ERRTAG
"Auto-sizing, width and height cannot be specified\n");
}
arch->clb_grid.Aspect = atof(Prop);
ezxml_set_attr(Node, "auto", NULL);
}
}
/* Takes in node pointing to <device> and loads all the
* child type objects. Unlinks the entire <device> node
* when complete. */
static void
ProcessDevice(INOUT ezxml_t Node,
OUT struct s_arch *arch,
IN boolean timing_enabled)
{
const char *Prop;
ezxml_t Cur;
Cur = FindElement(Node, "sizing", TRUE);
arch->R_minW_nmos = 0;
Prop = FindProperty(Cur, "R_minW_nmos", timing_enabled);
if(Prop != NULL)
{
arch->R_minW_nmos = atof(Prop);
ezxml_set_attr(Cur, "R_minW_nmos", NULL);
}
arch->R_minW_pmos = 0;
Prop = FindProperty(Cur, "R_minW_pmos", timing_enabled);
if(Prop != NULL)
{
arch->R_minW_pmos = atof(Prop);
ezxml_set_attr(Cur, "R_minW_pmos", NULL);
}
arch->ipin_mux_trans_size = 0;
Prop = FindProperty(Cur, "ipin_mux_trans_size", FALSE);
if(Prop != NULL)
{
arch->ipin_mux_trans_size = atof(Prop);
ezxml_set_attr(Cur, "ipin_mux_trans_size", NULL);
}
FreeNode(Cur);
Cur = FindElement(Node, "timing", timing_enabled);
if(Cur != NULL)
{
arch->C_ipin_cblock = 0;
Prop = FindProperty(Cur, "C_ipin_cblock", FALSE);
if(Prop != NULL)
{
arch->C_ipin_cblock = atof(Prop);
ezxml_set_attr(Cur, "C_ipin_cblock", NULL);
}
arch->T_ipin_cblock = 0;
Prop = FindProperty(Cur, "T_ipin_cblock", FALSE);
if(Prop != NULL)
{
arch->T_ipin_cblock = atof(Prop);
ezxml_set_attr(Cur, "T_ipin_cblock", NULL);
}
FreeNode(Cur);
}
Cur = FindElement(Node, "area", TRUE);
Prop = FindProperty(Cur, "grid_logic_tile_area", FALSE);
arch->grid_logic_tile_area = 0;
if(Prop != NULL)
{
arch->grid_logic_tile_area = atof(Prop);
ezxml_set_attr(Cur, "grid_logic_tile_area", NULL);
}
FreeNode(Cur);
Cur = FindElement(Node, "chan_width_distr", FALSE);
if(Cur != NULL)
{
ProcessChanWidthDistr(Cur, arch);
FreeNode(Cur);
}
Cur = FindElement(Node, "switch_block", TRUE);
Prop = FindProperty(Cur, "type", TRUE);
if(strcmp(Prop, "wilton") == 0)
{
arch->SBType = WILTON;
}
else if(strcmp(Prop, "universal") == 0)
{
arch->SBType = UNIVERSAL;
}
else if(strcmp(Prop, "subset") == 0)
{
arch->SBType = SUBSET;
}
else
{
printf(ERRTAG "Unknown property %s for switch block type x\n",
Prop);
exit(1);
}
ezxml_set_attr(Cur, "type", NULL);
Prop = FindProperty(Cur, "fs", TRUE);
arch->Fs = my_atoi(Prop);
ezxml_set_attr(Cur, "fs", NULL);
FreeNode(Cur);
}
/* Takes in node pointing to <chan_width_distr> and loads all the
* child type objects. Unlinks the entire <chan_width_distr> node
* when complete. */
static void
ProcessChanWidthDistr(INOUT ezxml_t Node,
OUT struct s_arch *arch)
{
const char *Prop;
ezxml_t Cur;
Cur = FindElement(Node, "io", TRUE);
Prop = FindProperty(Cur, "width", TRUE);
arch->Chans.chan_width_io = atof(Prop);
ezxml_set_attr(Cur, "width", NULL);
FreeNode(Cur);
Cur = FindElement(Node, "x", TRUE);
ProcessChanWidthDistrDir(Cur, &arch->Chans.chan_x_dist);
FreeNode(Cur);
Cur = FindElement(Node, "y", TRUE);
ProcessChanWidthDistrDir(Cur, &arch->Chans.chan_y_dist);
FreeNode(Cur);
}
/* Takes in node within <chan_width_distr> and loads all the
* child type objects. Unlinks the entire node when complete. */
static void
ProcessChanWidthDistrDir(INOUT ezxml_t Node,
OUT t_chan * chan)
{
const char *Prop;
boolean hasXpeak, hasWidth, hasDc;
hasXpeak = hasWidth = hasDc = FALSE;
Prop = FindProperty(Node, "distr", TRUE);
if(strcmp(Prop, "uniform") == 0)
{
chan->type = UNIFORM;
}
else if(strcmp(Prop, "gaussian") == 0)
{
chan->type = GAUSSIAN;
hasXpeak = hasWidth = hasDc = TRUE;
}
else if(strcmp(Prop, "pulse") == 0)
{
chan->type = PULSE;
hasXpeak = hasWidth = hasDc = TRUE;
}
else if(strcmp(Prop, "delta") == 0)
{
hasXpeak = hasDc = TRUE;
chan->type = DELTA;
}
else
{
printf(ERRTAG "Unknown property %s for chan_width_distr x\n",
Prop);
exit(1);
}
ezxml_set_attr(Node, "distr", NULL);
Prop = FindProperty(Node, "peak", TRUE);
chan->peak = atof(Prop);
ezxml_set_attr(Node, "peak", NULL);
Prop = FindProperty(Node, "width", hasWidth);
if(hasWidth)
{
chan->width = atof(Prop);
ezxml_set_attr(Node, "width", NULL);
}
Prop = FindProperty(Node, "xpeak", hasXpeak);
if(hasXpeak)
{
chan->xpeak = atof(Prop);
ezxml_set_attr(Node, "xpeak", NULL);
}
Prop = FindProperty(Node, "dc", hasDc);
if(hasDc)
{
chan->dc = atof(Prop);
ezxml_set_attr(Node, "dc", NULL);
}
}
static void
SetupEmptyType()
{
t_type_descriptor * type;
type = &type_descriptors[EMPTY_TYPE->index];
type->name = "<EMPTY>";
type->num_pins = 0;
type->height = 1;
type->capacity = 0;
type->num_drivers = 0;
type->num_receivers = 0;
type->pinloc = NULL;
type->num_class = 0;
type->class_inf = NULL;
type->pin_class = NULL;
type->is_global_pin = NULL;
type->is_Fc_frac = TRUE;
type->is_Fc_out_full_flex = FALSE;
type->Fc_in = 0;
type->Fc_out = 0;
type->max_subblocks = 0;
type->max_subblock_inputs = 0;
type->max_subblock_outputs = 0;
/* Used as lost area filler, no definition */
type->grid_loc_def = NULL;
type->num_grid_loc_def = 0;
}
/* Takes in node pointing to <io> and loads all the
* child type objects. Unlinks the entire <io> node
* when complete. */
static void
ProcessIO(INOUT ezxml_t Node,
IN boolean timing_enabled)
{
const char *Prop;
ezxml_t Cur, Cur2;
int i, j;
t_type_descriptor * type;
int num_inputs, num_outputs, num_clocks, num_pins, capacity, t_in, t_out;
enum
{ INCLASS = 0, OUTCLASS = 1, CLKCLASS = 2 };
type = &type_descriptors[IO_TYPE->index];
num_inputs = 1;
num_outputs = 1;
num_clocks = 1;
CheckElement(Node, "io");
type->name = ".io";
type->height = 1;
/* Load capacity */
Prop = FindProperty(Node, "capacity", TRUE);
capacity = my_atoi(Prop);
type->capacity = capacity;
ezxml_set_attr(Node, "capacity", NULL);
/* Load Fc */
Cur = FindElement(Node, "fc_in", TRUE);
Cur2 = FindElement(Node, "fc_out", TRUE);
Process_Fc(Cur, Cur2, type);
FreeNode(Cur);
FreeNode(Cur2);
/* Initialize and setup type */
num_pins = 3 * capacity;
type->num_pins = num_pins;
type->num_drivers = num_outputs * capacity;
type->num_receivers = num_inputs * capacity;
type->pinloc =
(int ***)alloc_matrix3(0, 0, 0, 3, 0, num_pins - 1, sizeof(int));
/* Jason Luu - September 5, 2007
* To treat IOs as any other block in routing, need to blackbox
* as having physical pins on all sides. This is a hack. */
for(i = 0; i < num_pins; ++i)
{
for(j = 0; j < 4; ++j)
{
type->pinloc[0][j][i] = 1;
}
}
/* Three fixed classes. In, Out, Clock */
type->num_class = 3 * capacity;
type->class_inf =
(struct s_class *)my_malloc(sizeof(struct s_class) * 3 * capacity);
type->pin_class = (int *)my_malloc(sizeof(int) * num_pins);
type->is_global_pin = (boolean *) my_malloc(sizeof(boolean) * num_pins);
for(j = 0; j < capacity; ++j)
{
/* Three fixed classes. In, Out, Clock */
type->class_inf[3 * j + INCLASS].num_pins = num_inputs;
type->class_inf[3 * j + INCLASS].type = RECEIVER;
type->class_inf[3 * j + INCLASS].pinlist =
(int *)my_malloc(sizeof(int) * num_inputs);
for(i = 0; i < num_inputs; ++i)
{
type->class_inf[3 * j + INCLASS].pinlist[i] =
num_pins * j / capacity + i;
type->pin_class[num_pins * j / capacity + i] =
3 * j + INCLASS;
type->is_global_pin[num_pins * j / capacity + i] = FALSE;
}
type->class_inf[3 * j + OUTCLASS].num_pins = num_outputs;
type->class_inf[3 * j + OUTCLASS].type = DRIVER;
type->class_inf[3 * j + OUTCLASS].pinlist =
(int *)my_malloc(sizeof(int) * num_outputs);
for(i = 0; i < num_outputs; ++i)
{
type->class_inf[3 * j + OUTCLASS].pinlist[i] =
num_pins * j / capacity + i + num_inputs;
type->pin_class[num_pins * j / capacity + i +
num_inputs] = 3 * j + OUTCLASS;
type->is_global_pin[num_pins * j / capacity + i +
num_inputs] = FALSE;
}
type->class_inf[3 * j + CLKCLASS].num_pins = num_clocks;
type->class_inf[3 * j + CLKCLASS].type = RECEIVER;
type->class_inf[3 * j + CLKCLASS].pinlist =
(int *)my_malloc(sizeof(int) * num_clocks);
for(i = 0; i < num_clocks; ++i)
{
type->class_inf[3 * j + CLKCLASS].pinlist[i] =
num_pins * j / capacity + i + num_inputs +
num_outputs;
type->pin_class[num_pins * j / capacity + i +
num_inputs + num_outputs] =
3 * j + CLKCLASS;
type->is_global_pin[num_pins * j / capacity + i +
num_inputs + num_outputs] = TRUE;
}
}
type->max_subblocks = 1;
type->max_subblock_inputs = 1;
type->max_subblock_outputs = 1;
/* Always at boundary */
type->num_grid_loc_def = 1;
type->grid_loc_def =
(struct s_grid_loc_def *)my_calloc(1, sizeof(struct s_grid_loc_def));
type->grid_loc_def[0].grid_loc_type = BOUNDARY;
type->grid_loc_def[0].priority = 0;
t_in = -1;
t_out = -1;
Prop = FindProperty(Node, "t_inpad", timing_enabled);
if(Prop != NULL)
{
t_in = atof(Prop);
ezxml_set_attr(Node, "t_inpad", NULL);
}
Prop = FindProperty(Node, "t_outpad", timing_enabled);
if(Prop != NULL)
{
t_out = atof(Prop);
ezxml_set_attr(Node, "t_outpad", NULL);
}
if(timing_enabled)
{
type->type_timing_inf.T_fb_ipin_to_sblk_ipin = 0;
type->type_timing_inf.T_sblk_opin_to_fb_opin = 0;
type->type_timing_inf.T_sblk_opin_to_sblk_ipin = 0;
type->type_timing_inf.T_subblock =
(t_T_subblock *) my_malloc(sizeof(t_T_subblock));
type->type_timing_inf.T_subblock[0].T_comb =
(float **)my_malloc(sizeof(float *));
type->type_timing_inf.T_subblock[0].T_comb[0] =
(float *)my_malloc(sizeof(float));
type->type_timing_inf.T_subblock[0].T_comb[0][0] = t_out;
type->type_timing_inf.T_subblock[0].T_seq_in =
(float *)my_malloc(sizeof(float));
type->type_timing_inf.T_subblock[0].T_seq_in[0] = 0;
type->type_timing_inf.T_subblock[0].T_seq_out =
(float *)my_malloc(sizeof(float));
type->type_timing_inf.T_subblock[0].T_seq_out[0] = t_in;
}
}
/* Takes in node pointing to <typelist> and loads all the
* child type objects. Unlinks the entire <typelist> node
* when complete. */
static void
ProcessTypes(INOUT ezxml_t Node,
OUT t_type_descriptor ** Types,
OUT int *NumTypes,
boolean timing_enabled)
{
ezxml_t CurType, Prev;
ezxml_t Cur, Cur2;
t_type_descriptor * Type;
int i;
/* Alloc the type list. Need two additional t_type_desctiptors:
* 1: empty psuedo-type
* 2: IO type
*/
*NumTypes = CountChildren(Node, "type") + 2;
*Types = (t_type_descriptor *)
my_malloc(sizeof(t_type_descriptor) * (*NumTypes));
EMPTY_TYPE = &type_descriptors[EMPTY_TYPE_INDEX];
IO_TYPE = &type_descriptors[IO_TYPE_INDEX];
type_descriptors[EMPTY_TYPE_INDEX].index = EMPTY_TYPE_INDEX;
type_descriptors[IO_TYPE_INDEX].index = IO_TYPE_INDEX;
SetupEmptyType();
Cur = FindElement(Node, "io", TRUE);
ProcessIO(Cur, timing_enabled);
FreeNode(Cur);
/* Process the types */
i = 2; /* Skip over 'empty' and 'io' type */
CurType = Node->child;
while(CurType)
{
CheckElement(CurType, "type");
/* Alias to current type */
Type = &(*Types)[i];
/* Parses the properties fields of the type */
ProcessTypeProps(CurType, Type);
/* Load subblock info */
Cur = FindElement(CurType, "subblocks", TRUE);
ProcessSubblocks(Cur, Type, timing_enabled);
FreeNode(Cur);
/* Load Fc */
Cur = FindElement(CurType, "fc_in", TRUE);
Cur2 = FindElement(CurType, "fc_out", TRUE);
Process_Fc(Cur, Cur2, Type);
FreeNode(Cur);
FreeNode(Cur2);
/* Load pin names and classes and locations */
Cur = FindElement(CurType, "pinclasses", TRUE);
SetupPinClasses(Cur, Type);
FreeNode(Cur);
Cur = FindElement(CurType, "pinlocations", TRUE);
SetupPinLocations(Cur, Type);
FreeNode(Cur);
Cur = FindElement(CurType, "gridlocations", TRUE);
SetupGridLocations(Cur, Type);
FreeNode(Cur);
Cur = FindElement(CurType, "timing", timing_enabled);
if(Cur)
{
SetupTypeTiming(Cur, Type);
FreeNode(Cur);
}
Type->index = i;
/* Type fully read */
++i;
/* Free this node and get its next sibling node */
Prev = CurType;
CurType = CurType->next;
FreeNode(Prev);
}
if(FILL_TYPE == NULL)
{
printf(ERRTAG "grid location type 'fill' must be specified.\n");
exit(1);
}
}
/* Loads the given architecture file. Currently only
* handles type information */
void
XmlReadArch(IN const char *ArchFile,
IN boolean timing_enabled,
OUT struct s_arch *arch,
OUT t_type_descriptor ** Types,
OUT int *NumTypes)
{
ezxml_t Cur, Next;
/* Parse the file */
Cur = ezxml_parse_file(ArchFile);
if(NULL == Cur)
{
printf(ERRTAG "Unable to load architecture file '%s'.\n",
ArchFile);
}
/* Root node should be architecture */
CheckElement(Cur, "architecture");
/* Process layout */
Next = FindElement(Cur, "layout", TRUE);
ProcessLayout(Next, arch);
FreeNode(Next);
/* Process device */
Next = FindElement(Cur, "device", TRUE);
ProcessDevice(Next, arch, timing_enabled);
FreeNode(Next);
/* Process types */
Next = FindElement(Cur, "typelist", TRUE);
ProcessTypes(Next, Types, NumTypes, timing_enabled);
FreeNode(Next);
/* Process switches */
Next = FindElement(Cur, "switchlist", TRUE);
ProcessSwitches(Next, &(arch->Switches), &(arch->num_switches),
timing_enabled);
FreeNode(Next);
/* Process segments. This depends on switches */
Next = FindElement(Cur, "segmentlist", TRUE);
ProcessSegments(Next, &(arch->Segments), &(arch->num_segments),
arch->Switches, arch->num_switches, timing_enabled);
FreeNode(Next);
/* Release the full XML tree */
FreeNode(Cur);
}
static void
ProcessSegments(INOUT ezxml_t Parent,
OUT struct s_segment_inf **Segs,
OUT int *NumSegs,
IN struct s_switch_inf *Switches,
IN int NumSwitches,
IN boolean timing_enabled)
{
int i, j, length;
const char *tmp;
ezxml_t SubElem;
ezxml_t Node;
/* Count the number of segs and check they are in fact
* of segment elements. */
*NumSegs = CountChildren(Parent, "segment");
/* Alloc segment list */
*Segs = NULL;
if(*NumSegs > 0)
{
*Segs =
(struct s_segment_inf *)my_malloc(*NumSegs *
sizeof(struct
s_segment_inf));
memset(*Segs, 0, (*NumSegs * sizeof(struct s_segment_inf)));
}
/* Load the segments. */
for(i = 0; i < *NumSegs; ++i)
{
Node = ezxml_child(Parent, "segment");
/* Get segment length */
length = 1; /* DEFAULT */
tmp = FindProperty(Node, "length", FALSE);
if(tmp)
{
if(strcmp(tmp, "longline") == 0)
{
(*Segs)[i].longline = TRUE;
}
else
{
length = my_atoi(tmp);
}
}
(*Segs)[i].length = length;
ezxml_set_attr(Node, "length", NULL);
/* Get the frequency */
(*Segs)[i].frequency = 1; /* DEFAULT */
tmp = FindProperty(Node, "freq", FALSE);
if(tmp)
{
(*Segs)[i].frequency = (int) (atof(tmp) * MAX_CHANNEL_WIDTH);
}
ezxml_set_attr(Node, "freq", NULL);
/* Get timing info */
(*Segs)[i].Rmetal = 0; /* DEFAULT */
tmp = FindProperty(Node, "Rmetal", timing_enabled);
if(tmp)
{
(*Segs)[i].Rmetal = atof(tmp);
}
ezxml_set_attr(Node, "Rmetal", NULL);
(*Segs)[i].Cmetal = 0; /* DEFAULT */
tmp = FindProperty(Node, "Cmetal", timing_enabled);
if(tmp)
{
(*Segs)[i].Cmetal = atof(tmp);
}
ezxml_set_attr(Node, "Cmetal", NULL);
/* Get the type */
tmp = FindProperty(Node, "type", TRUE);
if(0 == strcmp(tmp, "bidir"))
{
(*Segs)[i].directionality = BI_DIRECTIONAL;
}
else if(0 == strcmp(tmp, "unidir"))
{
(*Segs)[i].directionality = UNI_DIRECTIONAL;
}
else
{
printf(ERRTAG "Invalid switch type '%s'.\n", tmp);
exit(1);
}
ezxml_set_attr(Node, "type", NULL);
/* Get the wire and opin switches, or mux switch if unidir */
if(UNI_DIRECTIONAL == (*Segs)[i].directionality)
{
SubElem = FindElement(Node, "mux", TRUE);
tmp = FindProperty(SubElem, "name", TRUE);
/* Match names */
for(j = 0; j < NumSwitches; ++j)
{
if(0 == strcmp(tmp, Switches[j].name))
{
break; /* End loop so j is where we want it */
}
}
if(j >= NumSwitches)
{
printf(ERRTAG "'%s' is not a valid mux name.\n",
tmp);
exit(1);
}
ezxml_set_attr(SubElem, "name", NULL);
FreeNode(SubElem);
/* Unidir muxes must have the same switch
* for wire and opin fanin since there is
* really only the mux in unidir. */
(*Segs)[i].wire_switch = j;
(*Segs)[i].opin_switch = j;
}
else
{
assert(BI_DIRECTIONAL == (*Segs)[i].directionality);
SubElem = FindElement(Node, "wire_switch", TRUE);
tmp = FindProperty(SubElem, "name", TRUE);
/* Match names */
for(j = 0; j < NumSwitches; ++j)
{
if(0 == strcmp(tmp, Switches[j].name))
{
break; /* End loop so j is where we want it */
}
}
if(j >= NumSwitches)
{
printf(ERRTAG
"'%s' is not a valid wire_switch name.\n",
tmp);
exit(1);
}
(*Segs)[i].wire_switch = j;
ezxml_set_attr(SubElem, "name", NULL);
FreeNode(SubElem);
SubElem = FindElement(Node, "opin_switch", TRUE);
tmp = FindProperty(SubElem, "name", TRUE);
/* Match names */
for(j = 0; j < NumSwitches; ++j)
{
if(0 == strcmp(tmp, Switches[j].name))
{
break; /* End loop so j is where we want it */
}
}
if(j >= NumSwitches)
{
printf(ERRTAG
"'%s' is not a valid opin_switch name.\n",
tmp);
exit(1);
}
(*Segs)[i].opin_switch = j;
ezxml_set_attr(SubElem, "name", NULL);
FreeNode(SubElem);
}
/* Setup the CB list if they give one, otherwise use full */
(*Segs)[i].cb_len = length;
(*Segs)[i].cb = (boolean *) my_malloc(length * sizeof(boolean));
for(j = 0; j < length; ++j)
{
(*Segs)[i].cb[j] = TRUE;
}
SubElem = FindElement(Node, "cb", FALSE);
if(SubElem)
{
ProcessCB_SB(SubElem, (*Segs)[i].cb, length);
FreeNode(SubElem);
}
/* Setup the SB list if they give one, otherwise use full */
(*Segs)[i].sb_len = (length + 1);
(*Segs)[i].sb =
(boolean *) my_malloc((length + 1) * sizeof(boolean));
for(j = 0; j < (length + 1); ++j)
{
(*Segs)[i].sb[j] = TRUE;
}
SubElem = FindElement(Node, "sb", FALSE);
if(SubElem)
{
ProcessCB_SB(SubElem, (*Segs)[i].sb, (length + 1));
FreeNode(SubElem);
}
FreeNode(Node);
}
}
static void
ProcessCB_SB(INOUT ezxml_t Node,
INOUT boolean * list,
IN int len)
{
const char *tmp = NULL;
int i;
/* Check the type. We only support 'pattern' for now.
* Should add frac back eventually. */
tmp = FindProperty(Node, "type", TRUE);
if(0 == strcmp(tmp, "pattern"))
{
i = 0;
/* Get the content string */
tmp = Node->txt;
while(*tmp)
{
switch (*tmp)
{
case ' ':
break;
case 'T':
case '1':
if(i >= len)
{
printf(ERRTAG
"CB or SB depopulation is too long. It "
"should be (length) symbols for CBs and (length+1) "
"symbols for SBs.\n");
exit(1);
}
list[i] = TRUE;
++i;
break;
case 'F':
case '0':
if(i >= len)
{
printf(ERRTAG
"CB or SB depopulation is too long. It "
"should be (length) symbols for CBs and (length+1) "
"symbols for SBs.\n");
exit(1);
}
list[i] = FALSE;
++i;
break;
default:
printf(ERRTAG "Invalid character %c in CB or "
"SB depopulation list.\n", *tmp);
exit(1);
}
++tmp;
}
if(i < len)
{
printf(ERRTAG "CB or SB depopulation is too short. It "
"should be (length) symbols for CBs and (length+1) "
"symbols for SBs.\n");
exit(1);
}
/* Free content string */
ezxml_set_txt(Node, "");
}
else
{
printf(ERRTAG "'%s' is not a valid type for specifying "
"cb and sb depopulation.\n", tmp);
exit(1);
}
ezxml_set_attr(Node, "type", NULL);
}
static void
ProcessSwitches(INOUT ezxml_t Parent,
OUT struct s_switch_inf **Switches,
OUT int *NumSwitches,
IN boolean timing_enabled)
{
int i, j;
const char *type_name;
const char *switch_name;
const char *Prop;
boolean has_buf_size;
ezxml_t Node;
has_buf_size = FALSE;
/* Count the children and check they are switches */
*NumSwitches = CountChildren(Parent, "switch");
/* Alloc switch list */
*Switches = NULL;
if(*NumSwitches > 0)
{
*Switches =
(struct s_switch_inf *)my_malloc(*NumSwitches *
sizeof(struct
s_switch_inf));
memset(*Switches, 0,
(*NumSwitches * sizeof(struct s_switch_inf)));
}
/* Load the switches. */
for(i = 0; i < *NumSwitches; ++i)
{
Node = ezxml_child(Parent, "switch");
switch_name = FindProperty(Node, "name", TRUE);
type_name = FindProperty(Node, "type", TRUE);
/* Check for switch name collisions */
for(j = 0; j < i; ++j)
{
if(0 == strcmp((*Switches)[j].name, switch_name))
{
printf(ERRTAG
"Two switches with the same name '%s' were "
"found.\n", switch_name);
exit(1);
}
}
(*Switches)[i].name = my_strdup(switch_name);
ezxml_set_attr(Node, "name", NULL);
/* Figure out the type of switch. */
if(0 == strcmp(type_name, "mux"))
{
(*Switches)[i].buffered = TRUE;
has_buf_size = TRUE;
}
else if(0 == strcmp(type_name, "pass_trans"))
{
(*Switches)[i].buffered = FALSE;
}
else if(0 == strcmp(type_name, "buffer"))
{
(*Switches)[i].buffered = TRUE;
}
else
{
printf(ERRTAG "Invalid switch type '%s'.\n", type_name);
exit(1);
}
ezxml_set_attr(Node, "type", NULL);
Prop = FindProperty(Node, "R", timing_enabled);
if(Prop != NULL)
{
(*Switches)[i].R = atof(Prop);
ezxml_set_attr(Node, "R", NULL);
}
Prop = FindProperty(Node, "Cin", timing_enabled);
if(Prop != NULL)
{
(*Switches)[i].Cin = atof(Prop);
ezxml_set_attr(Node, "Cin", NULL);
}
Prop = FindProperty(Node, "Cout", timing_enabled);
if(Prop != NULL)
{
(*Switches)[i].Cout = atof(Prop);
ezxml_set_attr(Node, "Cout", NULL);
}
Prop = FindProperty(Node, "Tdel", timing_enabled);
if(Prop != NULL)
{
(*Switches)[i].Tdel = atof(Prop);
ezxml_set_attr(Node, "Tdel", NULL);
}
Prop = FindProperty(Node, "buf_size", has_buf_size);
if(has_buf_size)
{
(*Switches)[i].buf_size = atof(Prop);
ezxml_set_attr(Node, "buf_size", NULL);
}
Prop = FindProperty(Node, "mux_trans_size", FALSE);
if(Prop != NULL)
{
(*Switches)[i].mux_trans_size = atof(Prop);
ezxml_set_attr(Node, "mux_trans_size", NULL);
}
/* Remove the switch element from parse tree */
FreeNode(Node);
}
}
/* Output the data from architecture data so user can verify it
* was interpretted correctly. */
void
EchoArch(IN const char *EchoFile,
IN const t_type_descriptor * Types,
IN int NumTypes)
{
int i, j, k;
FILE * Echo;
Echo = my_fopen(EchoFile, "w");
for(i = 0; i < NumTypes; ++i)
{
fprintf(Echo, "Type: \"%s\"\n", Types[i].name);
fprintf(Echo, "\tcapacity: %d\n", Types[i].capacity);
fprintf(Echo, "\theight: %d\n", Types[i].height);
if(Types[i].num_pins > 0)
{
for(j = 0; j < Types[i].height; ++j)
{
fprintf(Echo,
"\tpinloc[%d] TOP LEFT BOTTOM RIGHT:\n",
j);
for(k = 0; k < Types[i].num_pins; ++k)
{
fprintf(Echo, "\t\t%d %d %d %d\n",
Types[i].pinloc[j][TOP][k],
Types[i].pinloc[j][LEFT][k],
Types[i].pinloc[j][BOTTOM][k],
Types[i].pinloc[j][RIGHT][k]);
}
}
}
fprintf(Echo, "\tnum_pins (scaled for capacity): %d\n",
Types[i].num_pins);
if(Types[i].num_pins > 0)
{
fprintf(Echo, "\tPins: NAME CLASS IS_GLOBAL\n");
for(j = 0; j < Types[i].num_pins; ++j)
{
fprintf(Echo, "\t\t%d %d %s\n", j,
Types[i].pin_class[j],
(Types[i].
is_global_pin[j] ? "TRUE" : "FALSE"));
}
}
fprintf(Echo, "\tnum_class: %d\n", Types[i].num_class);
if(Types[i].num_class > 0)
{
for(j = 0; j < Types[i].num_class; ++j)
{
switch (Types[i].class_inf[j].type)
{
case RECEIVER:
fprintf(Echo, "\t\tType: RECEIVER\n");
break;
case DRIVER:
fprintf(Echo, "\t\tType: DRIVER\n");
break;
case OPEN:
fprintf(Echo, "\t\tType: OPEN\n");
break;
default:
fprintf(Echo, "\t\tType: UNKNOWN\n");
break;
}
fprintf(Echo, "\t\t\tnum_pins: %d\n",
Types[i].class_inf[j].num_pins);
fprintf(Echo, "\t\t\tpins: "); /* No \n */
for(k = 0; k < Types[i].class_inf[j].num_pins;
++k)
{
fprintf(Echo, "%d ", Types[i].class_inf[j].pinlist[k]); /* No \n */
}
fprintf(Echo, "\n"); /* End current line */
}
}
fprintf(Echo, "\tis_Fc_frac: %s\n",
(Types[i].is_Fc_frac ? "TRUE" : "FALSE"));
fprintf(Echo, "\tis_Fc_out_full_flex: %s\n",
(Types[i].is_Fc_out_full_flex ? "TRUE" : "FALSE"));
fprintf(Echo, "\tFc_in: %f\n", Types[i].Fc_in);
fprintf(Echo, "\tFc_out: %f\n", Types[i].Fc_out);
fprintf(Echo, "\tmax_subblocks: %d\n", Types[i].max_subblocks);
fprintf(Echo, "\tmax_subblock_inputs: %d\n",
Types[i].max_subblock_inputs);
fprintf(Echo, "\tmax_subblock_outputs: %d\n",
Types[i].max_subblock_outputs);
fprintf(Echo, "\tnum_drivers: %d\n", Types[i].num_drivers);
fprintf(Echo, "\tnum_receivers: %d\n", Types[i].num_receivers);
fprintf(Echo, "\tindex: %d\n", Types[i].index);
fprintf(Echo, "\n");
}
fclose(Echo);
}