Exemplo n.º 1
0
static void load_subblock_array (int doall, FILE *fp_net,
           char *temp_buf, int num_subblocks, int bnum) {

/* Parses one subblock line and, if doall is 1, loads the proper   *
 * arrays.  Each subblock line is of the format:                   *
 * subblock: <name> <ipin0> <ipin1> .. <ipin[subblock_lut_size-1]> *
 *          <opin> <clockpin>                                      */
 
 int ipin, len, connect_to;
 char *ptr;

 ipin = 0;
 ptr = my_strtok(NULL,TOKENS,fp_net,temp_buf);

 if (ptr == NULL) {
    printf("Error in load_subblock_array on line %d of netlist file.\n",
             linenum);
    printf("Subblock name is missing.\nAborting.\n\n");
    exit (1);
 }
    
/* Load subblock name if this is the load pass. */
 if (doall == 1) {
    len = strlen (ptr);
    subblock_inf[bnum][num_subblocks-1].name = my_chunk_malloc ((len+1) *
             sizeof(char), &ch_subblock_head_ptr, &ch_subblock_bytes_avail,
             &ch_subblock_next_avail_mem);
    strcpy (subblock_inf[bnum][num_subblocks-1].name, ptr);
 }

 ptr = my_strtok(NULL,TOKENS,fp_net,temp_buf);

 while (ptr != NULL) {    /* For each subblock pin. */
    if (doall == 1) {
       connect_to = get_pin_number (ptr);
       if (ipin < subblock_lut_size) {      /* LUT input. */
          subblock_inf[bnum][num_subblocks-1].inputs[ipin] = connect_to;
       }
       else if (ipin == subblock_lut_size) {   /* LUT output. */
          subblock_inf[bnum][num_subblocks-1].output = connect_to;
       }
       else if (ipin == subblock_lut_size+1) {   /* Clock input. */
          subblock_inf[bnum][num_subblocks-1].clock = connect_to;
       }
    }
    ipin++;
    ptr = my_strtok(NULL,TOKENS,fp_net,temp_buf);
 }

 if (ipin != subblock_lut_size + 2) {
    printf("Error in load_subblock_array at line %d of netlist file.\n",
            linenum); 
    printf("Subblock had %d pins, expected %d.\n", ipin, 
            subblock_lut_size+2);
    printf("Aborting.\n\n");
    exit (1);
 }
}
void alloc_and_load_edges_and_switches (int inode, int num_edges, 
        t_linked_edge *edge_list_head) {
 
/* Sets up all the edge related information for rr_node inode (num_edges,  * 
 * the edges array and the switches array).  The edge_list_head points to  *
 * a list of the num_edges edges and switches to put in the arrays.  This  *
 * linked list is freed by this routine. This routine also resets the      *
 * rr_edge_done array for the next rr_node (i.e. set it so that no edges   *
 * are marked as having been seen before).                                 */
 
 t_linked_edge *list_ptr, *next_ptr;
 int i, to_node;


 rr_node[inode].num_edges = num_edges; 
 
 rr_node[inode].edges = (int *) my_chunk_malloc (num_edges * sizeof(int), 
       &rr_mem_chunk_list_head, &chunk_bytes_avail, &chunk_next_avail_mem); 
 
 rr_node[inode].switches = (short *) my_chunk_malloc (num_edges * 
       sizeof(short), &rr_mem_chunk_list_head, &chunk_bytes_avail, 
       &chunk_next_avail_mem); 
     
/* Load the edge and switch arrays, deallocate the linked list and reset   *
 * the rr_edge_done flags.                                                 */ 
  
 list_ptr = edge_list_head;
 i = 0;

 while (list_ptr != NULL) {
    to_node = list_ptr->edge;
    rr_node[inode].edges[i] = to_node;
    rr_edge_done[to_node] = FALSE;
    rr_node[inode].switches[i] = list_ptr->iswitch;
    next_ptr = list_ptr->next;

    /* Add to free list */
    free_linked_edge_soft (list_ptr, &free_edge_list_head); 

    list_ptr = next_ptr;
    i++;
 }
}
static void alloc_and_load_net_rr_terminals (int **rr_node_indices, 
        int nodes_per_chan) {

/* Allocates and loads the net_rr_terminals data structure.  For each net   *
 * it stores the rr_node index of the SOURCE of the net and all the SINKs   *
 * of the net.  [0..num_nets-1][0..num_pins-1].  Entry [inet][pnum] stores  *
 * the rr index corresponding to the SOURCE (opin) or SINK (ipin) of pnum.  */

 int inet, ipin, inode, iblk, i, j, iclass;
 t_rr_type rr_type;

 net_rr_terminals = (int **) my_malloc (num_nets * sizeof(int *));

 for (inet=0;inet<num_nets;inet++) {
    net_rr_terminals[inet] = (int *) my_chunk_malloc (net[inet].num_pins * 
              sizeof (int), &rr_mem_chunk_list_head, &chunk_bytes_avail,
              &chunk_next_avail_mem);
    
    rr_type = SOURCE;     /* First pin only */
    for (ipin=0;ipin<net[inet].num_pins;ipin++) {
       iblk = net[inet].pins[ipin];
       i = block[iblk].x;
       j = block[iblk].y;

       if (clb[i][j].type == CLB) 
          iclass = net_pin_class[inet][ipin];
       else 
          iclass = which_io_block (iblk);

       inode = get_rr_node_index (i, j, rr_type, iclass, nodes_per_chan, 
                  rr_node_indices);
       net_rr_terminals[inet][ipin] = inode;
 
       rr_type = SINK;    /* All pins after first are SINKs. */
    }
 }
}
static void build_rr_pads (int **rr_node_indices, int Fc_pad, int 
        **pads_to_tracks, int nodes_per_chan, int i, int j, int 
        delayless_switch, t_seg_details *seg_details_x, t_seg_details 
        *seg_details_y) {

/* Load up the rr_node structures for the pads at location (i,j).  I both *
 * fill in fields that shouldn't change during the entire routing and     *
 * initialize fields that will change to the proper starting value.       *
 * Empty pad locations have their type set to EMPTY.                      */

 int s_node, p_node, ipad, iloop;
 int inode, num_edges;
 t_linked_edge *edge_list_head;


/* Each pad contains both a SOURCE + OPIN, and a SINK + IPIN, since each  *
 * pad is bidirectional.  The fact that it will only be used as either an *
 * input or an output makes no difference.                                */

 for (ipad=0;ipad<io_rat;ipad++) {   /* For each pad at this (i,j) */

   /* Do SOURCE first.   */

    s_node = get_rr_node_index (i, j, SOURCE, ipad, nodes_per_chan,
             rr_node_indices);
       
    rr_node[s_node].num_edges = 1;
    p_node = get_rr_node_index (i, j, OPIN, ipad, nodes_per_chan, 
              rr_node_indices);

    rr_node[s_node].edges = (int *) my_chunk_malloc (sizeof(int), 
          &rr_mem_chunk_list_head, &chunk_bytes_avail, &chunk_next_avail_mem);
    rr_node[s_node].edges[0] = p_node;

    rr_node[s_node].switches = (short *) my_chunk_malloc (sizeof(short),
          &rr_mem_chunk_list_head, &chunk_bytes_avail, &chunk_next_avail_mem);
    rr_node[s_node].switches[0] = delayless_switch;
    
    rr_node_cost_inf[s_node].base_cost = 1.;
    rr_node[s_node].type = SOURCE;


   /* Now do OPIN */
       
    edge_list_head = NULL;
    num_edges = get_pad_opin_connections (pads_to_tracks, ipad, i, j, 
              Fc_pad, seg_details_x, seg_details_y, &edge_list_head, 
              nodes_per_chan, rr_node_indices);

    alloc_and_load_edges_and_switches (p_node, num_edges, edge_list_head);
 
    rr_node_cost_inf[p_node].base_cost = 1.;
    rr_node[p_node].type = OPIN;

   /* Code common to both SOURCE and OPIN. */

    inode = s_node;
    for (iloop=1;iloop<=2;iloop++) {    /* for both SOURCE or SINK and pin */
       rr_node_cost_inf[inode].acc_cost = 0.;
       rr_node_cost_inf[inode].occ = 0;
       rr_node_cost_inf[inode].capacity = 1;

       rr_node[inode].xlow = i;
       rr_node[inode].xhigh = i;
       rr_node[inode].ylow = j;
       rr_node[inode].yhigh = j;
       rr_node[inode].R = 0.;
       rr_node[inode].C = 0.;

       rr_node[inode].ptc_num = ipad;

       inode = p_node;
    }


   /* Now do SINK */

    s_node = get_rr_node_index (i, j, SINK, ipad, nodes_per_chan,
             rr_node_indices);

    rr_node[s_node].num_edges = 0;
    rr_node[s_node].edges = NULL;
    rr_node[s_node].switches = NULL;

    rr_node_cost_inf[s_node].base_cost = 0.;
    rr_node[s_node].type = SINK;


    /* Now do IPIN */
    
    p_node = get_rr_node_index (i, j, IPIN, ipad, nodes_per_chan,
             rr_node_indices);

    rr_node[p_node].num_edges = 1;
    rr_node[p_node].edges = (int *) my_chunk_malloc (sizeof(int), 
          &rr_mem_chunk_list_head, &chunk_bytes_avail, &chunk_next_avail_mem);
    rr_node[p_node].edges[0] = s_node;

    rr_node[p_node].switches = (short *) my_chunk_malloc (sizeof(short), 
          &rr_mem_chunk_list_head, &chunk_bytes_avail, &chunk_next_avail_mem);
    rr_node[p_node].switches[0] = delayless_switch;

#ifndef SPEC_CPU2000
    rr_node_cost_inf[p_node].base_cost = 0.95;
#else
    rr_node_cost_inf[p_node].base_cost = 1.;  /* Avoid roundoff for SPEC */
#endif

    rr_node[p_node].type = IPIN;

  /* Code common to both SINK and IPIN. */

    inode = s_node;
    for (iloop=1;iloop<=2;iloop++) {    /* for both SOURCE or SINK and pin */
       rr_node_cost_inf[inode].acc_cost = 0.;
       rr_node_cost_inf[inode].occ = 0;
       rr_node_cost_inf[inode].capacity = 1;

       rr_node[inode].xlow = i;
       rr_node[inode].xhigh = i;
       rr_node[inode].ylow = j;
       rr_node[inode].yhigh = j;
       rr_node[inode].R = 0.;
       rr_node[inode].C = 0.;

       rr_node[inode].ptc_num = ipad;

       inode = p_node;
    }

 }   /* End for each pad. */
}
static void build_rr_clb (int **rr_node_indices, int Fc_output, int ***
       clb_opin_to_tracks, int nodes_per_chan, int i, int j, int 
       delayless_switch, t_seg_details *seg_details_x, t_seg_details 
       *seg_details_y) {

/* Load up the rr_node structures for the clb at location (i,j).  I both  *
 * fill in fields that shouldn't change during the entire routing and     *
 * initialize fields that will change to the proper starting value.       */

 int ipin, iclass, inode, pin_num, to_node, num_edges;
 t_linked_edge *edge_list_head;

/* SOURCES and SINKS first.   */

 for (iclass=0;iclass<num_class;iclass++) {
    if (class_inf[iclass].type == DRIVER) {    /* SOURCE */
       inode = get_rr_node_index (i, j, SOURCE, iclass, nodes_per_chan,
                 rr_node_indices);

       num_edges = class_inf[iclass].num_pins;
       rr_node[inode].num_edges = num_edges;
       rr_node[inode].edges = (int *) my_chunk_malloc (num_edges * 
              sizeof (int), &rr_mem_chunk_list_head, &chunk_bytes_avail, 
              &chunk_next_avail_mem);

       rr_node[inode].switches = (short *) my_chunk_malloc (num_edges *
              sizeof (short), &rr_mem_chunk_list_head, &chunk_bytes_avail,
              &chunk_next_avail_mem);

       for (ipin=0;ipin<class_inf[iclass].num_pins;ipin++) {
          pin_num = class_inf[iclass].pinlist[ipin];
          to_node = get_rr_node_index (i, j, OPIN, pin_num, nodes_per_chan,
                  rr_node_indices);
          rr_node[inode].edges[ipin] = to_node;
          rr_node[inode].switches[ipin] = delayless_switch;
       }

       rr_node_cost_inf[inode].capacity = class_inf[iclass].num_pins;
       rr_node_cost_inf[inode].base_cost = 1.;
       rr_node[inode].type = SOURCE;
    }

    else {    /* SINK */
       inode = get_rr_node_index (i, j, SINK, iclass, nodes_per_chan,
                 rr_node_indices);

/* Note:  To allow route throughs through clbs, change the lines below to  *
 * make an edge from the input SINK to the output SOURCE.  Do for just the *
 * special case of INPUTS = class 0 and OUTPUTS = class 1 and see what it  *
 * leads to.  If route throughs are allowed, you may want to increase the  *
 * base cost of OPINs and/or SOURCES so they aren't used excessively.      */

       rr_node[inode].num_edges = 0; 
       rr_node[inode].edges = NULL;
       rr_node[inode].switches = NULL;
       rr_node_cost_inf[inode].capacity = class_inf[iclass].num_pins;
       rr_node_cost_inf[inode].base_cost = 0.;
       rr_node[inode].type = SINK;
    }

/* Things common to both SOURCEs and SINKs.   */

    rr_node_cost_inf[inode].acc_cost = 0.;
    rr_node_cost_inf[inode].occ = 0;

    rr_node[inode].xlow = i;
    rr_node[inode].xhigh = i;
    rr_node[inode].ylow = j;
    rr_node[inode].yhigh = j;
    rr_node[inode].R = 0;
    rr_node[inode].C = 0;

    rr_node[inode].ptc_num = iclass;
 }

/* Now do the pins.  */

 for (ipin=0;ipin<pins_per_clb;ipin++) {
    iclass = clb_pin_class[ipin];
    if (class_inf[iclass].type == DRIVER) {  /* OPIN */
       inode = get_rr_node_index (i, j, OPIN, ipin, nodes_per_chan,
                 rr_node_indices);

       edge_list_head = NULL;
       num_edges = get_clb_opin_connections (clb_opin_to_tracks, ipin, i, j,
                   Fc_output, seg_details_x, seg_details_y, &edge_list_head, 
                   nodes_per_chan, rr_node_indices);

       alloc_and_load_edges_and_switches (inode, num_edges, edge_list_head);

       rr_node_cost_inf[inode].base_cost = 1.;
       rr_node[inode].type = OPIN;
    }
    else {                                   /* IPIN */
       inode = get_rr_node_index (i, j, IPIN, ipin, nodes_per_chan,
                 rr_node_indices);

       rr_node[inode].num_edges = 1;
       rr_node[inode].edges = (int *) my_chunk_malloc (sizeof(int), 
          &rr_mem_chunk_list_head, &chunk_bytes_avail, &chunk_next_avail_mem);

       rr_node[inode].switches = (short *) my_chunk_malloc (sizeof(short), 
          &rr_mem_chunk_list_head, &chunk_bytes_avail, &chunk_next_avail_mem);

       to_node = get_rr_node_index (i, j, SINK, iclass, nodes_per_chan,
                  rr_node_indices);
       rr_node[inode].edges[0] = to_node;
       rr_node[inode].switches[0] = delayless_switch;

#ifndef SPEC_CPU2000
       rr_node_cost_inf[inode].base_cost = 0.95;
#else
       rr_node_cost_inf[inode].base_cost = 1.;  /* Avoid roundoff for SPEC */
#endif

       rr_node[inode].type = IPIN;
    }

/* Things that are common to both OPINs and IPINs.  */

    rr_node_cost_inf[inode].capacity = 1;
    rr_node_cost_inf[inode].acc_cost = 0.;
    rr_node_cost_inf[inode].occ = 0;
 
    rr_node[inode].xlow = i;
    rr_node[inode].xhigh = i;
    rr_node[inode].ylow = j;
    rr_node[inode].yhigh = j;
    rr_node[inode].C = 0;
    rr_node[inode].R = 0;
 
    rr_node[inode].ptc_num = ipin;
 }
}
Exemplo n.º 6
0
static void parse_name_and_pinlist (int doall, FILE *fp_net, char *buf) {

/* This routine does the first part of the parsing of a block.  It is *
 * called whenever any type of block (.clb, .input or .output) is to  *
 * be parsed.  It increments the block count (num_blocks), and checks *
 * that the block has a name.  If doall is 1, this is the loading     *
 * pass and it copies the name to the block data structure.  Finally  *
 * it checks that the pinlist: keyword exists.  On return, my_strtok  *
 * is set so that the next call will get the first net connected to   *
 * this block.                                                        */

 char *ptr;
 int len;
 
/* Get block name. */
 
 ptr = my_strtok(NULL,TOKENS,fp_net,buf);
 if (ptr == NULL) {
    printf("Error in parse_name_and_pinlist on line %d of netlist file.\n",
       linenum);
    printf(".clb, .input or .output line has no associated name.\n");
    exit (1);
 }
 
 if (doall == 1) {    /* Second (loading) pass, store block name */
    len = strlen (ptr);
    block[num_blocks-1].name = my_chunk_malloc ((len + 1) * sizeof(char),
                  NULL, &chunk_bytes_avail, &chunk_next_avail_mem);
    strcpy (block[num_blocks-1].name, ptr);
 }
 
 ptr = my_strtok (NULL,TOKENS,fp_net,buf);
 if (ptr != NULL) {
    printf("Error in parse_name_and_pinlist on line %d of netlist file.\n",
       linenum);
    printf("Extra characters at end of line.\n");
    exit (1);
 }
 
/* Now get pinlist from the next line.  Note that a NULL return value *
 * from my_gets means EOF, while a NULL return from my_strtok just    *
 * means we had a blank or comment line.                              */
 
 do {
    ptr = my_fgets (buf, BUFSIZE, fp_net);
    if (ptr == NULL) {
       printf("Error in parse_name_and_pinlist on line %d of netlist file.\n",
          linenum);
       printf("Missing pinlist: keyword.\n");
       exit (1);
    }

    ptr = my_strtok(buf,TOKENS,fp_net,buf);
 } while (ptr == NULL);
 
 if (strcmp (ptr, "pinlist:") != 0) {
    printf("Error in parse_name_and_pinlist on line %d of netlist file.\n",
       linenum);
    printf("Expected pinlist: keyword, got %s.\n",ptr);
    exit (1);
 }
}
Exemplo n.º 7
0
static void init_parse(int doall) {

/* Allocates and initializes the data structures needed for the parse. */

 int i, j, len, nindex, pin_count;
 int *tmp_ptr;
 struct s_hash_iterator hash_iterator;
 struct s_hash *h_ptr;


 if (!doall) {  /* Initialization before first (counting) pass */
    num_nets = 0;  
    hash_table = alloc_hash_table ();

#define INITIAL_BLOCK_STORAGE 2000
    temp_block_storage = INITIAL_BLOCK_STORAGE;
    num_subblocks_per_block = my_malloc (INITIAL_BLOCK_STORAGE *
             sizeof(int));

    ch_subblock_bytes_avail = 0;
    ch_subblock_next_avail_mem = NULL;
    ch_subblock_head_ptr = NULL;
 }

/* Allocate memory for second (load) pass */ 

 else {   
    net = (struct s_net *) my_malloc (num_nets*sizeof(struct s_net));
    block = (struct s_block *) my_malloc (num_blocks*
        sizeof(struct s_block));   
    is_global = (boolean *) my_calloc (num_nets, sizeof(boolean));
    num_driver = (int *) my_malloc (num_nets * sizeof(int));
    temp_num_pins = (int *) my_malloc (num_nets * sizeof(int));

    for (i=0;i<num_nets;i++) {
       num_driver[i] = 0;
       net[i].num_pins = 0;
    }

/* Allocate block pin connection storage.  Some is wasted for io blocks. *
 * Method used below "chunks" the malloc of a bunch of small things to   *
 * reduce the memory housekeeping overhead of malloc.                    */

    tmp_ptr = (int *) my_malloc (pins_per_clb * num_blocks * sizeof(int));
    for (i=0;i<num_blocks;i++) 
       block[i].nets = tmp_ptr + i * pins_per_clb;

/* I use my_chunk_malloc for some storage locations below.  my_chunk_malloc  *
 * avoids the 12 byte or so overhead incurred by malloc, but since I call it *
 * with a NULL head_ptr, it will not keep around enough information to ever  *
 * free these data arrays.  If you ever have compatibility problems on a     *
 * non-SPARC architecture, just change all the my_chunk_malloc calls to      *
 * my_malloc calls.                                                          */

    hash_iterator = start_hash_table_iterator ();
    h_ptr = get_next_hash (hash_table, &hash_iterator);
    
    while (h_ptr != NULL) {
       nindex = h_ptr->index;
       pin_count = h_ptr->count;
       net[nindex].blocks = (int *) my_chunk_malloc(pin_count *
               sizeof(int), NULL, &chunk_bytes_avail, &chunk_next_avail_mem);

       net[nindex].blk_pin = (int *) my_chunk_malloc (pin_count * 
               sizeof(int), NULL, &chunk_bytes_avail, &chunk_next_avail_mem);

/* For avoiding assigning values beyond end of pins array. */

       temp_num_pins[nindex] = pin_count;

       len = strlen (h_ptr->name);
       net[nindex].name = (char *) my_chunk_malloc ((len + 1) *
            sizeof(char), NULL, &chunk_bytes_avail, &chunk_next_avail_mem);
       strcpy (net[nindex].name, h_ptr->name);
       h_ptr = get_next_hash (hash_table, &hash_iterator);
    }

/* Allocate storage for subblock info. (what's in each logic block) */

   num_subblocks_per_block = (int *) my_realloc (num_subblocks_per_block,
                  num_blocks * sizeof (int));
   subblock_inf = (t_subblock **) my_malloc (num_blocks * 
                        sizeof(t_subblock *));

   for (i=0;i<num_blocks;i++) {
      if (num_subblocks_per_block[i] == 0) 
         subblock_inf[i] = NULL;
      else {
         subblock_inf[i] = (t_subblock *) my_chunk_malloc (
              num_subblocks_per_block[i] * sizeof (t_subblock), 
              &ch_subblock_head_ptr, &ch_subblock_bytes_avail, 
              &ch_subblock_next_avail_mem);
         for (j=0;j<num_subblocks_per_block[i];j++) 
            subblock_inf[i][j].inputs = (int *) my_chunk_malloc
                 (subblock_lut_size * sizeof(int), &ch_subblock_head_ptr, 
                 &ch_subblock_bytes_avail, &ch_subblock_next_avail_mem);
      }
   }
 }

/* Initializations for both passes. */

 linenum = 0;
 num_p_inputs = 0;
 num_p_outputs = 0;
 num_clbs = 0;
 num_blocks = 0;
 num_globals = 0;
}