VPR-7.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
cluster_placement.c
Go to the documentation of this file.
1 /*
2  Given a group of logical blocks and a partially-packed complex block, find placement for group of logical blocks in complex block
3  To use, keep "cluster_placement_stats" data structure throughout packing
4  cluster_placement_stats undergoes these major states:
5  Initialization - performed once at beginning of packing
6  Reset - reset state in between packing of clusters
7  In flight - Speculatively place
8  Finalized - Commit or revert placements
9  Freed - performed once at end of packing
10 
11  Author: Jason Luu
12  March 12, 2012
13  */
14 #include <stdio.h>
15 #include <assert.h>
16 #include <string.h>
17 
18 #include "read_xml_arch_file.h"
19 #include "util.h"
20 #include "vpr_types.h"
21 #include "globals.h"
22 #include "vpr_utils.h"
23 #include "hash.h"
24 #include "cluster_placement.h"
25 
26 /****************************************/
27 /*Local Function Declaration */
28 /****************************************/
30  INOUTP t_cluster_placement_stats *cluster_placement_stats,
31  INOUTP t_pb_graph_node *pb_graph_node);
32 static void requeue_primitive(
33  INOUTP t_cluster_placement_stats *cluster_placement_stats,
34  t_cluster_placement_primitive *cluster_placement_primitive);
35 static void update_primitive_cost_or_status(INP t_pb_graph_node *pb_graph_node,
36  INP float incremental_cost, INP boolean valid);
37 static float try_place_molecule(INP t_pack_molecule *molecule,
38  INP t_pb_graph_node *root, INOUTP t_pb_graph_node **primitives_list, INP int clb_index);
40  INP t_pack_molecule *molecule,
41  INP t_pack_pattern_block *pack_pattern_block,
42  INOUTP t_pb_graph_node **primitives_list, INOUTP float *cost);
43 static t_pb_graph_pin *expand_pack_molecule_pin_edge(INP int pattern_id,
44  INP t_pb_graph_pin *cur_pin, INP boolean forward);
45 static void flush_intermediate_queues(
46  INOUTP t_cluster_placement_stats *cluster_placement_stats);
47 static boolean root_passes_early_filter(INP t_pb_graph_node *root, INP t_pack_molecule *molecule, INP int clb_index);
48 
49 /****************************************/
50 /*Function Definitions */
51 /****************************************/
52 
53 /**
54  * [0..num_pb_types-1] array of cluster placement stats, one for each type_descriptors
55  */
57  t_cluster_placement_stats *cluster_placement_stats_list;
58  int i;
59 
60  cluster_placement_stats_list = (t_cluster_placement_stats *) my_calloc(num_types,
62  for (i = 0; i < num_types; i++) {
63  if (EMPTY_TYPE != &type_descriptors[i]) {
64  cluster_placement_stats_list[i].valid_primitives = (t_cluster_placement_primitive **) my_calloc(
66  + 1, sizeof(t_cluster_placement_primitive*)); /* too much memory allocated but shouldn't be a problem */
67  cluster_placement_stats_list[i].curr_molecule = NULL;
69  &cluster_placement_stats_list[i],
70  type_descriptors[i].pb_graph_head);
71  }
72  }
73  return cluster_placement_stats_list;
74 }
75 
76 /**
77  * get next list of primitives for list of logical blocks
78  * primitives is the list of ptrs to primitives that matches with the list of logical_blocks (by index), assumes memory is preallocated
79  * - if this is a new block, requeue tried primitives and return a in-flight primitive list to try
80  * - if this is an old block, put root primitive to tried queue, requeue rest of primitives. try another set of primitives
81  *
82  * return TRUE if can find next primitive, FALSE otherwise
83  *
84  * cluster_placement_stats - ptr to the current cluster_placement_stats of open complex block
85  * molecule - molecule to pack into open complex block
86  * primitives_list - a list of primitives indexed to match logical_block_ptrs of molecule. Expects an allocated array of primitives ptrs as inputs. This function loads the array with the lowest cost primitives that implement molecule
87  */
89  INOUTP t_cluster_placement_stats *cluster_placement_stats,
90  INP t_pack_molecule *molecule, INOUTP t_pb_graph_node **primitives_list, INP int clb_index) {
91  t_cluster_placement_primitive *cur, *next, *best, *before_best, *prev;
92  int i;
93  float cost, lowest_cost;
94  best = NULL;
95  before_best = NULL;
96 
97  if (cluster_placement_stats->curr_molecule != molecule) {
98  /* New block, requeue tried primitives and in-flight primitives */
99  flush_intermediate_queues(cluster_placement_stats);
100 
101  cluster_placement_stats->curr_molecule = molecule;
102  } else {
103  /* Hack! Same failed molecule may re-enter if upper stream functions suck, I'm going to make the molecule selector more intelligent, TODO: Remove later */
104  if (cluster_placement_stats->in_flight != NULL) {
105  /* Hack end */
106 
107  /* old block, put root primitive currently inflight to tried queue */
108  cur = cluster_placement_stats->in_flight;
109  next = cur->next_primitive;
110  cur->next_primitive = cluster_placement_stats->tried;
111  cluster_placement_stats->tried = cur;
112  /* should have only one block in flight at any point in time */
113  assert(next == NULL);
114  cluster_placement_stats->in_flight = NULL;
115  }
116  }
117 
118  /* find next set of blocks
119  1. Remove invalid blocks to invalid queue
120  2. Find lowest cost array of primitives that implements blocks
121  3. When found, move current blocks to in-flight, return lowest cost array of primitives
122  4. Return NULL if not found
123  */
124  lowest_cost = HUGE_POSITIVE_FLOAT;
125  for (i = 0; i < cluster_placement_stats->num_pb_types; i++) {
126  if (cluster_placement_stats->valid_primitives[i]->next_primitive == NULL) {
127  continue; /* no more primitives of this type available */
128  }
130  molecule->logical_block_ptrs[molecule->root]->index,
131  cluster_placement_stats->valid_primitives[i]->next_primitive->pb_graph_node->pb_type)) {
132  prev = cluster_placement_stats->valid_primitives[i];
133  cur = cluster_placement_stats->valid_primitives[i]->next_primitive;
134  while (cur) {
135  /* remove invalid nodes lazily when encountered */
136  while (cur && cur->valid == FALSE) {
137  prev->next_primitive = cur->next_primitive;
138  cur->next_primitive = cluster_placement_stats->invalid;
139  cluster_placement_stats->invalid = cur;
140  cur = prev->next_primitive;
141  }
142  if (cur == NULL) {
143  break;
144  }
145  /* try place molecule at root location cur */
146  cost = try_place_molecule(molecule, cur->pb_graph_node,
147  primitives_list, clb_index);
148  if (cost < lowest_cost) {
149  lowest_cost = cost;
150  best = cur;
151  before_best = prev;
152  }
153  prev = cur;
154  cur = cur->next_primitive;
155  }
156  }
157  }
158  if (best == NULL) {
159  /* failed to find a placement */
160  for (i = 0; i < molecule->num_blocks; i++) {
161  primitives_list[i] = NULL;
162  }
163  } else {
164  /* populate primitive list with best */
165  cost = try_place_molecule(molecule, best->pb_graph_node, primitives_list, clb_index);
166  assert(cost == lowest_cost);
167 
168  /* take out best node and put it in flight */
169  cluster_placement_stats->in_flight = best;
170  before_best->next_primitive = best->next_primitive;
171  best->next_primitive = NULL;
172  }
173 
174  if (best == NULL) {
175  return FALSE;
176  }
177  return TRUE;
178 }
179 
180 /**
181  * Resets one cluster placement stats by clearing incremental costs and returning all primitives to valid queue
182  */
184  INOUTP t_cluster_placement_stats *cluster_placement_stats) {
186  int i;
187 
188  /* Requeue primitives */
189  flush_intermediate_queues(cluster_placement_stats);
190  cur = cluster_placement_stats->invalid;
191  while (cur != NULL) {
192  next = cur->next_primitive;
193  requeue_primitive(cluster_placement_stats, cur);
194  cur = next;
195  }
196  cur = cluster_placement_stats->invalid = NULL;
197  /* reset flags and cost */
198  for (i = 0; i < cluster_placement_stats->num_pb_types; i++) {
199  assert(
200  cluster_placement_stats->valid_primitives[i] != NULL && cluster_placement_stats->valid_primitives[i]->next_primitive != NULL);
201  cur = cluster_placement_stats->valid_primitives[i]->next_primitive;
202  while (cur != NULL) {
203  cur->incremental_cost = 0;
204  cur->valid = TRUE;
205  cur = cur->next_primitive;
206  }
207  }
208  cluster_placement_stats->curr_molecule = NULL;
209 }
210 
211 /**
212  * Free linked lists found in cluster_placement_stats_list
213  */
215  INOUTP t_cluster_placement_stats *cluster_placement_stats_list) {
217  int i, j;
218  for (i = 0; i < num_types; i++) {
219  cur = cluster_placement_stats_list[i].tried;
220  while (cur != NULL) {
221  next = cur->next_primitive;
222  free(cur);
223  cur = next;
224  }
225  cur = cluster_placement_stats_list[i].in_flight;
226  while (cur != NULL) {
227  next = cur->next_primitive;
228  free(cur);
229  cur = next;
230  }
231  cur = cluster_placement_stats_list[i].invalid;
232  while (cur != NULL) {
233  next = cur->next_primitive;
234  free(cur);
235  cur = next;
236  }
237  for (j = 0; j < cluster_placement_stats_list[i].num_pb_types; j++) {
238  cur =
239  cluster_placement_stats_list[i].valid_primitives[j]->next_primitive;
240  while (cur != NULL) {
241  next = cur->next_primitive;
242  free(cur);
243  cur = next;
244  }
245  free(cluster_placement_stats_list[i].valid_primitives[j]);
246  }
247  free(cluster_placement_stats_list[i].valid_primitives);
248  }
249  free(cluster_placement_stats_list);
250 }
251 
252 /**
253  * Put primitive back on queue of valid primitives
254  * Note that valid status is not changed because if the primitive is not valid, it will get properly collected later
255  */
256 static void requeue_primitive(
257  INOUTP t_cluster_placement_stats *cluster_placement_stats,
258  t_cluster_placement_primitive *cluster_placement_primitive) {
259  int i;
260  int null_index;
261  boolean success;
262  null_index = OPEN;
263 
264  success = FALSE;
265  for (i = 0; i < cluster_placement_stats->num_pb_types; i++) {
266  if (cluster_placement_stats->valid_primitives[i]->next_primitive == NULL) {
267  null_index = i;
268  continue;
269  }
270  if (cluster_placement_primitive->pb_graph_node->pb_type
271  == cluster_placement_stats->valid_primitives[i]->next_primitive->pb_graph_node->pb_type) {
272  success = TRUE;
273  cluster_placement_primitive->next_primitive =
274  cluster_placement_stats->valid_primitives[i]->next_primitive;
275  cluster_placement_stats->valid_primitives[i]->next_primitive =
276  cluster_placement_primitive;
277  }
278  }
279  if (success == FALSE) {
280  assert(null_index != OPEN);
281  cluster_placement_primitive->next_primitive =
282  cluster_placement_stats->valid_primitives[null_index]->next_primitive;
283  cluster_placement_stats->valid_primitives[null_index]->next_primitive =
284  cluster_placement_primitive;
285  }
286 }
287 
288 /**
289  * Add any primitives found in pb_graph_nodes to cluster_placement_stats
290  * Adds backward link from pb_graph_node to cluster_placement_primitive
291  */
293  INOUTP t_cluster_placement_stats *cluster_placement_stats,
294  INOUTP t_pb_graph_node *pb_graph_node) {
295  int i, j, k;
296  t_cluster_placement_primitive *placement_primitive;
297  const t_pb_type *pb_type = pb_graph_node->pb_type;
298  boolean success;
299  if (pb_type->modes == 0) {
300  placement_primitive = (t_cluster_placement_primitive *) my_calloc(1,
302  placement_primitive->pb_graph_node = pb_graph_node;
303  placement_primitive->valid = TRUE;
304  pb_graph_node->cluster_placement_primitive = placement_primitive;
305  placement_primitive->base_cost = compute_primitive_base_cost(
306  pb_graph_node);
307  success = FALSE;
308  i = 0;
309  while (success == FALSE) {
310  if (cluster_placement_stats->valid_primitives[i] == NULL
311  || cluster_placement_stats->valid_primitives[i]->next_primitive->pb_graph_node->pb_type
312  == pb_graph_node->pb_type) {
313  if (cluster_placement_stats->valid_primitives[i] == NULL) {
314  cluster_placement_stats->valid_primitives[i] = (t_cluster_placement_primitive *) my_calloc(1,
315  sizeof(t_cluster_placement_primitive)); /* head of linked list is empty, makes it easier to remove nodes later */
316  cluster_placement_stats->num_pb_types++;
317  }
318  success = TRUE;
319  placement_primitive->next_primitive =
320  cluster_placement_stats->valid_primitives[i]->next_primitive;
321  cluster_placement_stats->valid_primitives[i]->next_primitive =
322  placement_primitive;
323  }
324  i++;
325  }
326  } else {
327  for (i = 0; i < pb_type->num_modes; i++) {
328  for (j = 0; j < pb_type->modes[i].num_pb_type_children; j++) {
329  for (k = 0; k < pb_type->modes[i].pb_type_children[j].num_pb;
330  k++) {
332  cluster_placement_stats,
333  &pb_graph_node->child_pb_graph_nodes[i][j][k]);
334  }
335  }
336  }
337  }
338 }
339 
340 /**
341  * Commit primitive, invalidate primitives blocked by mode assignment and update costs for primitives in same cluster as current
342  * Costing is done to try to pack blocks closer to existing primitives
343  * actual value based on closest common ancestor to committed placement, the farther the ancestor, the less reduction in cost there is
344  * Side effects: All cluster_placement_primitives may be invalidated/costed in this algorithm
345  * Al intermediate queues are requeued
346  */
347 void commit_primitive(INOUTP t_cluster_placement_stats *cluster_placement_stats,
348  INP t_pb_graph_node *primitive) {
349  t_pb_graph_node *pb_graph_node, *skip;
350  float incr_cost;
351  int i, j, k;
352  int valid_mode;
354 
355  /* Clear out intermediate queues */
356  flush_intermediate_queues(cluster_placement_stats);
357 
358  /* commit primitive as used, invalidate it */
359  cur = primitive->cluster_placement_primitive;
360  assert(cur->valid == TRUE);
361 
362  cur->valid = FALSE;
363  incr_cost = -0.01; /* cost of using a node drops as its neighbours are used, this drop should be small compared to scarcity values */
364 
365  pb_graph_node = cur->pb_graph_node;
366  /* walk up pb_graph_node and update primitives of children */
367  while (pb_graph_node->parent_pb_graph_node != NULL) {
368  skip = pb_graph_node; /* do not traverse stuff that's already traversed */
369  valid_mode = pb_graph_node->pb_type->parent_mode->index;
370  pb_graph_node = pb_graph_node->parent_pb_graph_node;
371  for (i = 0; i < pb_graph_node->pb_type->num_modes; i++) {
372  for (j = 0;
373  j < pb_graph_node->pb_type->modes[i].num_pb_type_children;
374  j++) {
375  for (k = 0;
376  k
377  < pb_graph_node->pb_type->modes[i].pb_type_children[j].num_pb;
378  k++) {
379  if (&pb_graph_node->child_pb_graph_nodes[i][j][k] != skip) {
381  &pb_graph_node->child_pb_graph_nodes[i][j][k],
382  incr_cost, (boolean)(i == valid_mode));
383  }
384  }
385  }
386  }
387  incr_cost /= 10; /* blocks whose ancestor is further away in tree should be affected less than blocks closer in tree */
388  }
389 }
390 
391 /**
392  * Set mode of cluster
393  */
395  int mode) {
396  int i, j, k;
397  for (i = 0; i < pb_graph_node->pb_type->num_modes; i++) {
398  if (i != mode) {
399  for (j = 0;
400  j < pb_graph_node->pb_type->modes[i].num_pb_type_children;
401  j++) {
402  for (k = 0;
403  k
404  < pb_graph_node->pb_type->modes[i].pb_type_children[j].num_pb;
405  k++) {
407  &pb_graph_node->child_pb_graph_nodes[i][j][k], 0,
408  FALSE);
409  }
410  }
411  }
412  }
413 }
414 
415 /**
416  * For sibling primitives of pb_graph node, decrease cost
417  * For modes invalidated by pb_graph_node, invalidate primitive
418  * int distance is the distance of current pb_graph_node from original
419  */
421  INP float incremental_cost, INP boolean valid) {
422  int i, j, k;
423  t_cluster_placement_primitive *placement_primitive;
424  if (pb_graph_node->pb_type->num_modes == 0) {
425  /* is primitive */
426  placement_primitive =
427  (t_cluster_placement_primitive*) pb_graph_node->cluster_placement_primitive;
428  if (valid) {
429  placement_primitive->incremental_cost += incremental_cost;
430  } else {
431  placement_primitive->valid = FALSE;
432  }
433  } else {
434  for (i = 0; i < pb_graph_node->pb_type->num_modes; i++) {
435  for (j = 0;
436  j < pb_graph_node->pb_type->modes[i].num_pb_type_children;
437  j++) {
438  for (k = 0;
439  k
440  < pb_graph_node->pb_type->modes[i].pb_type_children[j].num_pb;
441  k++) {
443  &pb_graph_node->child_pb_graph_nodes[i][j][k],
444  incremental_cost, valid);
445  }
446  }
447  }
448  }
449 }
450 
451 /**
452  * Try place molecule at root location, populate primitives list with locations of placement if successful
453  */
454 static float try_place_molecule(INP t_pack_molecule *molecule,
455  INP t_pb_graph_node *root, INOUTP t_pb_graph_node **primitives_list, INP int clb_index) {
456  int list_size, i;
457  float cost = HUGE_POSITIVE_FLOAT;
458  list_size = get_array_size_of_molecule(molecule);
459 
461  molecule->logical_block_ptrs[molecule->root]->index,
462  root->pb_type)) {
463  if (root->cluster_placement_primitive->valid == TRUE) {
464  if(root_passes_early_filter(root, molecule, clb_index)) {
465  for (i = 0; i < list_size; i++) {
466  primitives_list[i] = NULL;
467  }
468  cost = root->cluster_placement_primitive->base_cost
469  + root->cluster_placement_primitive->incremental_cost;
470  primitives_list[molecule->root] = root;
471  if (molecule->type == MOLECULE_FORCED_PACK) {
473  molecule->pack_pattern->root_block, primitives_list,
474  &cost)) {
475  return HUGE_POSITIVE_FLOAT;
476  }
477  }
478  for (i = 0; i < list_size; i++) {
479  assert(
480  (primitives_list[i] == NULL) == (molecule->logical_block_ptrs[i] == NULL));
481  }
482  }
483  }
484  }
485  return cost;
486 }
487 
488 /**
489  * Expand molecule at pb_graph_node
490  * Assumes molecule and pack pattern connections have fan-out 1
491  */
493  INP t_pack_molecule *molecule,
494  INP t_pack_pattern_block *pack_pattern_block,
495  INOUTP t_pb_graph_node **primitives_list, INOUTP float *cost) {
496  t_pb_graph_node *pb_graph_node =
497  primitives_list[pack_pattern_block->block_id];
498  t_pb_graph_node *next_primitive;
500  int from_pin, from_port;
501  t_pb_graph_pin *cur_pin, *next_pin;
502  t_pack_pattern_block *next_block;
503 
504  cur = pack_pattern_block->connections;
505  while (cur) {
506  if (cur->from_block == pack_pattern_block) {
507  next_block = cur->to_block;
508  } else {
509  next_block = cur->from_block;
510  }
511  if (primitives_list[next_block->block_id] == NULL && molecule->logical_block_ptrs[next_block->block_id] != NULL) {
512  /* first time visiting location */
513 
514  /* find next primitive based on pattern connections, expand next primitive if not visited */
515  from_pin = cur->from_pin->pin_number;
516  from_port = cur->from_pin->port->port_index_by_type;
517  if (cur->from_block == pack_pattern_block) {
518  /* forward expand to find next block */
519  cur_pin = &pb_graph_node->output_pins[from_port][from_pin];
521  pack_pattern_block->pattern_index, cur_pin, TRUE);
522  } else {
523  /* backward expand to find next block */
524  assert(cur->to_block == pack_pattern_block);
525  if (cur->from_pin->port->is_clock) {
526  cur_pin = &pb_graph_node->clock_pins[from_port][from_pin];
527  } else {
528  cur_pin = &pb_graph_node->input_pins[from_port][from_pin];
529  }
531  pack_pattern_block->pattern_index, cur_pin, FALSE);
532  }
533  /* found next primitive */
534  if (next_pin != NULL) {
535  next_primitive = next_pin->parent_node;
536  /* Check for legality of placement, if legal, expand from legal placement, if not, return FALSE */
537  if (molecule->logical_block_ptrs[next_block->block_id] != NULL
538  && primitives_list[next_block->block_id] == NULL) {
539  if (next_primitive->cluster_placement_primitive->valid
540  == TRUE
542  molecule->logical_block_ptrs[next_block->block_id]->index,
543  next_primitive->pb_type)) {
544  primitives_list[next_block->block_id] = next_primitive;
545  *cost +=
546  next_primitive->cluster_placement_primitive->base_cost
549  next_block, primitives_list, cost)) {
550  return FALSE;
551  }
552  } else {
553  return FALSE;
554  }
555  }
556  } else {
557  return FALSE;
558  }
559  }
560  cur = cur->next;
561  }
562 
563  return TRUE;
564 }
565 
566 /**
567  * Find next primitive pb_graph_pin
568  */
570  INP t_pb_graph_pin *cur_pin, INP boolean forward) {
571  int i, j, k;
572  t_pb_graph_pin *temp_pin, *dest_pin;
573  temp_pin = NULL;
574  dest_pin = NULL;
575  if (forward) {
576  for (i = 0; i < cur_pin->num_output_edges; i++) {
577  /* one fanout assumption */
578  if (cur_pin->output_edges[i]->infer_pattern) {
579  for (k = 0; k < cur_pin->output_edges[i]->num_output_pins;
580  k++) {
581  if (cur_pin->output_edges[i]->output_pins[k]->parent_node->pb_type->num_modes
582  == 0) {
583  temp_pin = cur_pin->output_edges[i]->output_pins[k];
584  } else {
585  temp_pin = expand_pack_molecule_pin_edge(pattern_id,
586  cur_pin->output_edges[i]->output_pins[k],
587  forward);
588  }
589  }
590  if (temp_pin != NULL) {
591  assert(dest_pin == NULL || dest_pin == temp_pin);
592  dest_pin = temp_pin;
593  }
594  } else {
595  for (j = 0; j < cur_pin->output_edges[i]->num_pack_patterns;
596  j++) {
597  if (cur_pin->output_edges[i]->pack_pattern_indices[j]
598  == pattern_id) {
599  for (k = 0;
600  k < cur_pin->output_edges[i]->num_output_pins;
601  k++) {
602  if (cur_pin->output_edges[i]->output_pins[k]->parent_node->pb_type->num_modes
603  == 0) {
604  temp_pin =
605  cur_pin->output_edges[i]->output_pins[k];
606  } else {
607  temp_pin =
609  pattern_id,
610  cur_pin->output_edges[i]->output_pins[k],
611  forward);
612  }
613  }
614  if (temp_pin != NULL) {
615  assert(dest_pin == NULL || dest_pin == temp_pin);
616  dest_pin = temp_pin;
617  }
618  }
619  }
620  }
621  }
622  } else {
623  for (i = 0; i < cur_pin->num_input_edges; i++) {
624  /* one fanout assumption */
625  if (cur_pin->input_edges[i]->infer_pattern) {
626  for (k = 0; k < cur_pin->input_edges[i]->num_input_pins; k++) {
627  if (cur_pin->input_edges[i]->input_pins[k]->parent_node->pb_type->num_modes
628  == 0) {
629  temp_pin = cur_pin->input_edges[i]->input_pins[k];
630  } else {
631  temp_pin = expand_pack_molecule_pin_edge(pattern_id,
632  cur_pin->input_edges[i]->input_pins[k],
633  forward);
634  }
635  }
636  if (temp_pin != NULL) {
637  assert(dest_pin == NULL || dest_pin == temp_pin);
638  dest_pin = temp_pin;
639  }
640  } else {
641  for (j = 0; j < cur_pin->input_edges[i]->num_pack_patterns;
642  j++) {
643  if (cur_pin->input_edges[i]->pack_pattern_indices[j]
644  == pattern_id) {
645  for (k = 0; k < cur_pin->input_edges[i]->num_input_pins;
646  k++) {
647  if (cur_pin->input_edges[i]->input_pins[k]->parent_node->pb_type->num_modes
648  == 0) {
649  temp_pin =
650  cur_pin->input_edges[i]->input_pins[k];
651  } else {
653  pattern_id,
654  cur_pin->input_edges[i]->input_pins[k],
655  forward);
656  }
657  }
658  if (temp_pin != NULL) {
659  assert(dest_pin == NULL || dest_pin == temp_pin);
660  dest_pin = temp_pin;
661  }
662  }
663  }
664  }
665  }
666  }
667  return dest_pin;
668 }
669 
671  INOUTP t_cluster_placement_stats *cluster_placement_stats) {
673  cur = cluster_placement_stats->tried;
674  while (cur != NULL) {
675  next = cur->next_primitive;
676  requeue_primitive(cluster_placement_stats, cur);
677  cur = next;
678  }
679  cluster_placement_stats->tried = NULL;
680 
681  cur = cluster_placement_stats->in_flight;
682  if (cur != NULL) {
683  next = cur->next_primitive;
684  requeue_primitive(cluster_placement_stats, cur);
685  /* should have at most one block in flight at any point in time */
686  assert(next == NULL);
687  }
688  cluster_placement_stats->in_flight = NULL;
689 }
690 
691 /* Determine max index + 1 of molecule */
693  if (molecule->type == MOLECULE_FORCED_PACK) {
694  return molecule->pack_pattern->num_blocks;
695  } else {
696  return molecule->num_blocks;
697  }
698 }
699 
700 /* Given logical block, determines if a free primitive exists for it */
702  INOUTP t_cluster_placement_stats *cluster_placement_stats,
703  INP int ilogical_block) {
704  int i;
705  t_cluster_placement_primitive *cur, *prev;
706 
707  /* might have a primitive in flight that's still valid */
708  if (cluster_placement_stats->in_flight) {
709  if (primitive_type_feasible(ilogical_block,
710  cluster_placement_stats->in_flight->pb_graph_node->pb_type)) {
711  return TRUE;
712  }
713  }
714 
715  /* Look through list of available primitives to see if any valid */
716  for (i = 0; i < cluster_placement_stats->num_pb_types; i++) {
717  if (cluster_placement_stats->valid_primitives[i]->next_primitive == NULL) {
718  continue; /* no more primitives of this type available */
719  }
720  if (primitive_type_feasible(ilogical_block,
721  cluster_placement_stats->valid_primitives[i]->next_primitive->pb_graph_node->pb_type)) {
722  prev = cluster_placement_stats->valid_primitives[i];
723  cur = cluster_placement_stats->valid_primitives[i]->next_primitive;
724  while (cur) {
725  /* remove invalid nodes lazily when encountered */
726  while (cur && cur->valid == FALSE) {
727  prev->next_primitive = cur->next_primitive;
728  cur->next_primitive = cluster_placement_stats->invalid;
729  cluster_placement_stats->invalid = cur;
730  cur = prev->next_primitive;
731  }
732  if (cur == NULL) {
733  break;
734  }
735  return TRUE;
736  }
737  }
738  }
739 
740  return FALSE;
741 }
742 
743 
745  INOUTP t_cluster_placement_stats *cluster_placement_stats) {
746  flush_intermediate_queues(cluster_placement_stats);
747 }
748 
749 
750 /* Quick, additional filter to see if root is feasible for molecule
751 
752  Limitation: This code can absorb a single atom by a "forced connection". A forced connection is one where there is no interconnect flexibility connecting
753  two primitives so if one primitive is used, then the other must also be used.
754 
755  TODO: jluu - Many ways to make this either more efficient or more robust.
756  1. For forced connections, I can get the packer to try forced connections first thus avoid trying out other locations that
757  I know are bad thus saving runtime and potentially improving robustness because the placement cost function is not always 100%.
758  2. I need to extend this so that molecules can be pulled in instead of just atoms.
759 */
760 static boolean root_passes_early_filter(INP t_pb_graph_node *root, INP t_pack_molecule *molecule, INP int clb_index) {
761  int i, j;
762  boolean feasible;
763  t_logical_block *root_block;
764  t_model_ports *model_port;
765  int inet;
766  int isink;
767  t_pb_graph_pin *sink_pb_graph_pin;
768 
769  feasible = TRUE;
770  root_block = molecule->logical_block_ptrs[molecule->root];
771  for(i = 0; feasible && i < root->num_output_ports; i++) {
772  for(j = 0; feasible && j < root->num_output_pins[i]; j++) {
773  if(root->output_pins[i][j].is_forced_connection) {
774  model_port = root->output_pins[i][j].port->model_port;
775  inet = root_block->output_nets[model_port->index][j];
776  if(inet != OPEN) {
777  /* This output pin has a dedicated connection to one output, make sure that molecule works */
778  if(molecule->type == MOLECULE_SINGLE_ATOM) {
779  feasible = FALSE; /* There is only one case where an atom can fit in here, so by default, feasibility is false unless proven otherwise */
780  if(vpack_net[inet].num_sinks == 1) {
781  isink = vpack_net[inet].node_block[1];
782  if(logical_block[isink].clb_index == clb_index) {
783  sink_pb_graph_pin = &root->output_pins[i][j];
784  while(sink_pb_graph_pin->num_output_edges != 0) {
785  assert(sink_pb_graph_pin->num_output_edges == 1);
786  assert(sink_pb_graph_pin->output_edges[0]->num_output_pins == 1);
787  sink_pb_graph_pin = sink_pb_graph_pin->output_edges[0]->output_pins[0];
788  }
789  if(sink_pb_graph_pin->parent_node == logical_block[isink].pb->pb_graph_node) {
790  /* There is a logical block mapped to the physical position that pulls in the atom in question */
791  feasible = TRUE;
792  }
793  }
794  }
795  }
796  }
797  }
798  }
799  }
800  return feasible;
801 }
802 
static boolean expand_forced_pack_molecule_placement(INP t_pack_molecule *molecule, INP t_pack_pattern_block *pack_pattern_block, INOUTP t_pb_graph_node **primitives_list, INOUTP float *cost)
boolean is_clock
void set_mode_cluster_placement_stats(INP t_pb_graph_node *pb_graph_node, int mode)
boolean primitive_type_feasible(int iblk, const t_pb_type *cur_pb_type)
Definition: vpr_utils.c:241
t_pb_graph_pin ** clock_pins
struct s_pb_type * pb_type_children
struct s_pb_graph_node * parent_pb_graph_node
t_type_ptr EMPTY_TYPE
Definition: globals.c:41
t_mode * modes
t_pb_graph_pin ** output_pins
t_pack_pattern_block * from_block
Definition: cad_types.h:21
struct s_pb_graph_edge ** output_edges
int get_max_primitives_in_pb_type(t_pb_type *pb_type)
Definition: vpr_utils.c:173
void free_cluster_placement_stats(INOUTP t_cluster_placement_stats *cluster_placement_stats_list)
void * my_calloc(size_t nelem, size_t size)
Definition: util.c:132
static void update_primitive_cost_or_status(INP t_pb_graph_node *pb_graph_node, INP float incremental_cost, INP boolean valid)
int * node_block
Definition: vpr_types.h:507
void commit_primitive(INOUTP t_cluster_placement_stats *cluster_placement_stats, INP t_pb_graph_node *primitive)
t_pb_graph_pin ** output_pins
t_pack_pattern_block * to_block
Definition: cad_types.h:24
t_cluster_placement_stats * alloc_and_load_cluster_placement_stats(void)
#define INOUTP
Definition: util.h:21
static t_pb_graph_pin * expand_pack_molecule_pin_edge(INP int pattern_id, INP t_pb_graph_pin *cur_pin, INP boolean forward)
t_pack_molecule * curr_molecule
Definition: vpr_types.h:266
static float try_place_molecule(INP t_pack_molecule *molecule, INP t_pb_graph_node *root, INOUTP t_pb_graph_node **primitives_list, INP int clb_index)
struct s_cluster_placement_primitive * cluster_placement_primitive
t_pack_patterns * pack_pattern
Definition: vpr_types.h:246
Definition: util.h:12
t_mode * parent_mode
struct s_cluster_placement_primitive * next_primitive
Definition: cad_types.h:58
static void flush_intermediate_queues(INOUTP t_cluster_placement_stats *cluster_placement_stats)
struct s_pb_graph_edge ** input_edges
float compute_primitive_base_cost(INP t_pb_graph_node *primitive)
Definition: vpr_utils.c:452
static boolean root_passes_early_filter(INP t_pb_graph_node *root, INP t_pack_molecule *molecule, INP int clb_index)
#define HUGE_POSITIVE_FLOAT
Definition: vpr_types.h:79
struct s_trace * next
Definition: vpr_types.h:870
int get_array_size_of_molecule(t_pack_molecule *molecule)
#define INP
Definition: util.h:19
t_pb_graph_pin * from_pin
Definition: cad_types.h:22
void reset_cluster_placement_stats(INOUTP t_cluster_placement_stats *cluster_placement_stats)
struct s_pb_graph_node * parent_node
void reset_tried_but_unused_cluster_placements(INOUTP t_cluster_placement_stats *cluster_placement_stats)
struct s_pack_pattern_connections * next
Definition: cad_types.h:27
boolean exists_free_primitive_for_logical_block(INOUTP t_cluster_placement_stats *cluster_placement_stats, INP int ilogical_block)
struct s_pb_graph_node *** child_pb_graph_nodes
int num_pb_type_children
int port_index_by_type
struct s_pb_type * pb_type
t_pb_graph_pin ** input_pins
int num_types
Definition: globals.c:37
t_cluster_placement_primitive ** valid_primitives
Definition: vpr_types.h:267
t_pb_graph_node * pb_graph_node
Definition: cad_types.h:57
Definition: slre.c:50
enum e_pack_pattern_molecule_type type
Definition: vpr_types.h:245
struct s_type_descriptor * type_descriptors
Definition: globals.c:38
struct s_net * vpack_net
Definition: globals.c:19
int ** output_nets
Definition: vpr_types.h:212
t_pb_graph_node * pb_graph_node
Definition: vpr_types.h:180
static void requeue_primitive(INOUTP t_cluster_placement_stats *cluster_placement_stats, t_cluster_placement_primitive *cluster_placement_primitive)
boolean get_next_primitive_list(INOUTP t_cluster_placement_stats *cluster_placement_stats, INP t_pack_molecule *molecule, INOUTP t_pb_graph_node **primitives_list, INP int clb_index)
static void load_cluster_placement_stats_for_pb_graph_node(INOUTP t_cluster_placement_stats *cluster_placement_stats, INOUTP t_pb_graph_node *pb_graph_node)
t_pb_graph_pin ** input_pins
struct s_logical_block * logical_block
Definition: globals.c:20
Definition: util.h:12