⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cluster.c

📁 fpga设计评估软件
💻 C
📖 第 1 页 / 共 4 页
字号:
/* This routine returns a block which has not been clustered, has  * * no connection to the current cluster, satisfies the cluster     * * clock constraints, and has ext_inps external inputs.  If        * * there is no such block it returns NO_CLUSTER.  Remove_flag      * * controls whether or not blocks that have already been clustered * * are removed from the unclustered_list data structures.  NB:     * * to get a block regardless of clock constraints just set clocks_ * * avail > 0.                                                      */ struct s_ilink *ptr, *prev_ptr; int iblk;  prev_ptr = &unclustered_list_head[ext_inps]; ptr = unclustered_list_head[ext_inps].next; while (ptr != NULL) {    iblk = ptr->iblk;    if (cluster_of_block[iblk] == NO_CLUSTER) {       if (clocks_feasible (iblk, 0, clocks_avail, lut_size, NULL))           return (iblk);       prev_ptr = ptr;    }    else if (remove_flag == REMOVE_CLUSTERED) {       prev_ptr->next = ptr->next;    }    ptr = ptr->next; }  return (NO_CLUSTER);}/*****************************************/static int get_free_block_with_most_ext_inputs (int lut_size, int inputs_avail,        int clocks_avail) {/* This routine is used to find the first seed block for the clustering   * * and to find new blocks for clustering when there are no feasible       * * blocks with any attraction to the current cluster (i.e. it finds       * * blocks which are unconnected from the current cluster).  It returns    * * the block with the largest number of used inputs that satisfies the    * * clocking and number of inputs constraints.  If no suitable block is    * * found, the routine returns NO_CLUSTER.                                 */ int iblk, ext_inps, istart; istart = min (lut_size, inputs_avail); for (ext_inps=istart;ext_inps>=0;ext_inps--) {    iblk = get_block_by_num_ext_inputs (ext_inps, lut_size, clocks_avail,                     REMOVE_CLUSTERED);    if (iblk != NO_CLUSTER)        return (iblk); } return (NO_CLUSTER);   /* No suitable block found. */}/*****************************************/static void reset_cluster (int *inputs_used, int *luts_used,        int *clocks_used, int* next_empty_location_in_cluster,        int *block_in_cluster, int cluster_size) {/* Call this routine when starting to fill up a new cluster.  It resets * * the gain vector, etc.                                                */ int i;/* If statement below is for speed.  If nets are reasonably low-fanout,  * * only a relatively small number of blocks will be marked, and updating * * only those block structures will be fastest.  If almost all blocks    * * have been touched it should be faster to just run through them all    * * in order (less addressing and better cache locality).                 */ *inputs_used = 0; *luts_used = 0; *clocks_used = 0; *next_empty_location_in_cluster=0; for (i=0;i<num_marked_blocks;i++){    gain[marked_blocks[i]] = 0.0;   lengthgain[marked_blocks[i]]=0.0;   sharinggain[marked_blocks[i]]=NOT_VALID;   hillgain[marked_blocks[i]]=NOT_VALID;   connectiongain[marked_blocks[i]]=0; } num_marked_blocks = 0;                                                           for (i=0;i<num_marked_nets;i++) {   num_pins_of_net_in_cluster[marked_nets[i]] = 0;   net_output_in_cluster[marked_nets[i]] = FALSE; } for (i=0; i<cluster_size;i++)   block_in_cluster[i]=NO_CLUSTER; num_marked_nets = 0;}/*****************************************/static void update_connection_gain_values (int inet, int clustered_block, 					   int pin_on_clustered_block,					   boolean *is_clock) {  /*This function is called when the connectiongain values on the net*   *inet require updating.   */  enum e_net_relation_to_clustered_block net_relation_to_clustered_block;  int iblk, ipin;  if (pin_on_clustered_block==0){      /*these designations are only valid for non-clock nets*/    net_relation_to_clustered_block=OUTPUT;  }  else{    net_relation_to_clustered_block=INPUT;  }      if (net_relation_to_clustered_block==OUTPUT && !is_clock[inet]){    for (ipin=1;ipin<net[inet].num_pins;ipin++) {      iblk = net[inet].pins[ipin];      if (cluster_of_block[iblk] == NO_CLUSTER) {	connectiongain[iblk] ++;      }    }  }  if(net_relation_to_clustered_block==INPUT && !is_clock[inet]){     /*Calculate the connectiongain for the block which is driving *     *the net that is an input to a block in the cluster */    iblk=net[inet].pins[0];    if (cluster_of_block[iblk] == NO_CLUSTER) {      connectiongain[iblk] ++;    }  }}/*****************************************/static void update_length_gain_values (int inet, int clustered_block, 				       int pin_on_clustered_block,				       boolean *is_clock) {  /*This function is called when the length_gain values on the net*   *inet requires updating.   */  enum e_net_relation_to_clustered_block net_relation_to_clustered_block;  float lengain;  int newblk, netpin, ifirst;  int iblk, ipin;/* Check if this net lists its driving block twice.  If so, avoid  * * double counting this block by skipping the first (driving) pin. */   if (net_output_feeds_driving_block_input[inet] == FALSE)     ifirst = 0;  else    ifirst = 1;  if (pin_on_clustered_block==0){      /*these designations are only valid for non-clock nets*/    net_relation_to_clustered_block=OUTPUT;  }  else{    net_relation_to_clustered_block=INPUT;  }      if (net_relation_to_clustered_block==OUTPUT && !is_clock[inet]){    for (ipin=ifirst;ipin<net[inet].num_pins;ipin++) {      iblk = net[inet].pins[ipin];      if (cluster_of_block[iblk] == NO_CLUSTER) {	lengain=get_net_pin_backward_criticality(inet, ipin);	if (lengain>lengthgain[iblk])	  lengthgain[iblk]=lengain;      }    }  }  if(net_relation_to_clustered_block==INPUT && !is_clock[inet]){     /*Calculate the length gain for the block which is driving *     *the net that is an input to a block in the cluster */    newblk=net[inet].pins[0];    if (cluster_of_block[newblk] == NO_CLUSTER) {      netpin= get_net_pin_number(clustered_block, pin_on_clustered_block);      lengain=get_net_pin_forward_criticality(inet, netpin);      if (lengain>lengthgain[newblk])	lengthgain[newblk]=lengain;    }  }}/*****************************************/static void mark_and_update_partial_gain (int inet,        enum e_gain_update gain_flag,       int lut_size, int clustered_block, int pin_on_clustered_block,       boolean* is_clock, boolean timing_driven, boolean connection_driven) {/* Updates the marked data structures, and if gain_flag is GAIN,  * * the gain when a logic block is added to a cluster.  The        * * sharinggain is the number of inputs that a block shares with   * * blocks that are already in the cluster. Hillgain is the        * * reduction in number of pins-required by adding a block to the  * * cluster. The lengthgain is the criticality of the most critical* * net between this block and a block in the cluster.             */ int iblk, ipin, ifirst;/* Mark net as being visited, if necessary. */ if (num_pins_of_net_in_cluster[inet] == 0) {    marked_nets[num_marked_nets] = inet;    num_marked_nets++; }/* Update gains of affected blocks. */ if (gain_flag == GAIN) {/* Check if this net lists its driving block twice.  If so, avoid  * * double counting this block by skipping the first (driving) pin. */      if (net_output_feeds_driving_block_input[inet] == FALSE)        ifirst = 0;    else       ifirst = 1;          if (num_pins_of_net_in_cluster[inet]==0) {     for (ipin=ifirst;ipin<net[inet].num_pins;ipin++) {       iblk = net[inet].pins[ipin];       if (cluster_of_block[iblk] == NO_CLUSTER) {	 if (sharinggain[iblk] == NOT_VALID) {	   marked_blocks[num_marked_blocks] = iblk;	   num_marked_blocks++;	   sharinggain[iblk]=1;	   hillgain[iblk] = 1 - num_ext_inputs (iblk, lut_size);	 }	 else {	   sharinggain[iblk]++;	   hillgain[iblk]++;	 }       }     }   }   if (connection_driven) {     update_connection_gain_values(inet, clustered_block, pin_on_clustered_block, 				   is_clock);   }   else if (timing_driven) {     update_length_gain_values(inet, clustered_block, pin_on_clustered_block,			       is_clock);   }	        }     num_pins_of_net_in_cluster[inet]++;}/*****************************************/static void  recompute_length_gain_values(int *block_in_cluster, 					  int next_empty_location_in_cluster,					  int lut_size,					  boolean global_clocks, 					  boolean *is_clock) {  /*This function recomputes all of the length_gain values for any *   *nets that are affected by blocks that have been added to       *   *current cluster.                                               */  int ipin, inet, iblk;  int i,idx;  for (i=0;i<num_marked_blocks;i++){     iblk=marked_blocks[i];    lengthgain[iblk] = 0.0;  }    for (idx=0; idx < next_empty_location_in_cluster; idx++) {    iblk=block_in_cluster[idx];        inet = block[iblk].nets[0];  /*output pin first */    if (inet != OPEN) {      if (!is_clock[inet] || !global_clocks) 	update_length_gain_values(inet, iblk, 0, is_clock);    }    for (ipin=1;ipin<=lut_size;ipin++) {   /*  LUT input pins. */      inet = block[iblk].nets[ipin];      if (inet != OPEN)      	update_length_gain_values(inet, iblk, ipin, is_clock);    }  }}/*****************************************/static void update_total_gain(float alpha, boolean timing_driven, boolean 			      connection_driven){  /*Updates the total  gain array to reflect the desired tradeoff between*   *input sharing (sharinggain) and path_length minimization (lengthgain)*/  int i, iblk;    if (connection_driven) {    /*try to absorb as many connections as possible*/    for (i=0;i<num_marked_blocks;i++){       iblk=marked_blocks[i];          gain[iblk] = (1-alpha)*(float)sharinggain[iblk] + alpha*(float)connectiongain[iblk];    }  }  else if (timing_driven) {    for (i=0;i<num_marked_blocks;i++){       iblk=marked_blocks[i];      gain[iblk] = alpha*lengthgain[iblk]+	gain_for_each_net_shared*(float)sharinggain[iblk]; /*1-alpha term is accounted*							    *for in gain_for_each...  *							    *this saves overhead of   *							    *dividing every time      */    }  }  else { /*non timing_driven, minimize number of inputs used*/    for (i=0;i<num_marked_blocks;i++){       iblk=marked_blocks[i];      gain[iblk] = (float)sharinggain[iblk];    }  }}/*****************************************/static void add_to_cluster (int new_blk, int cluster_index, int lut_size,       boolean *is_clock, boolean global_clocks, int *inputs_used,      int *luts_used, int *clocks_used, float alpha, boolean timing_driven,       boolean connection_driven) {/* Marks new_blk as belonging to cluster cluster_index and updates  * * all the gain, etc. structures.  Cluster_index should always      * * be the index of the currently open cluster.                      */ int ipin, inet; cluster_of_block[new_blk] = cluster_index; (*luts_used)++;  inet = block[new_blk].nets[0];    /* Output pin first. *//* Output should never be open but I check anyway.  I don't change  * * the gain for clock outputs when clocks are globally distributed  * * because I assume there is no real need to pack similarly clocked * * FFs together then.  Note that by updating the gain when the      * * clock driver is placed in a cluster implies that the output of   * * LUTs can be connected to clock inputs internally.  Probably not  * * true, but it doesn't make much difference, since it will still   * * make local routing of this clock very short, and none of my      * * benchmarks actually generate local clocks (all come from pads).  */ if (inet != OPEN) {    if (!is_clock[inet] || !global_clocks)       mark_and_update_partial_gain (inet, GAIN, lut_size, new_blk, 0, is_clock,				    timing_driven, connection_driven);    else       mark_and_update_partial_gain (inet, NO_GAIN, lut_size, new_blk, 0, 				     is_clock, timing_driven, connection_driven);    net_output_in_cluster[inet] = TRUE;    if (num_pins_of_net_in_cluster[inet] > 1 && !is_clock[inet])       (*inputs_used)--; } for (ipin=1;ipin<=lut_size;ipin++) {   /*  LUT input pins. */    inet = block[new_blk].nets[ipin];    if (inet != OPEN) {       mark_and_update_partial_gain (inet, GAIN, lut_size, new_blk, ipin, 				     is_clock, timing_driven, connection_driven);/* If num_pins_of_net_in_cluster != 1, then either the output is * * in the cluster or an input for this net is already in the     * * cluster.  In either case we don't need a new pin.             */       if (num_pins_of_net_in_cluster[inet] == 1)           (*inputs_used)++;    } }/* Note:  The code below ONLY WORKS when nets that go to clock inputs * * NEVER go to the input of a LUT.  It doesn't really make electrical * * sense for that to happen, and I check this in the check_clocks     * * function.  Don't disable that sanity check.                        */ inet = block[new_blk].nets[lut_size+1];    /* Clock input pin. */ if (inet != OPEN) {    if (global_clocks)        mark_and_update_partial_gain (inet, NO_GAIN, lut_size, new_blk, 				     lut_size+1, is_clock, timing_driven,				     connection_driven);    else       mark_and_update_partial_gain (inet, GAIN, lut_size, new_blk, 				     lut_size+1, is_clock, timing_driven,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -