vpr/src/pack/cluster.cpp
/**
 * Try pack molecule into current cluster
 */
Try pack molecule into current cluster
Try pack molecule into current cluster
static enum e_block_pack_status try_pack_molecule(t_cluster_placement_stats* cluster_placement_stats_ptr,
                                                  const std::multimap<AtomBlockId, t_pack_molecule*>& atom_molecules,
                                                  t_pack_molecule* molecule,
                                                  t_pb_graph_node** primitives_list,
                                                  t_pb* pb,
                                                  const int max_models,
                                                  const int max_cluster_size,
                                                  const ClusterBlockId clb_index,
                                                  const int detailed_routing_stage,
                                                  t_lb_router_data* router_data,
                                                  int verbosity,
                                                  bool enable_pin_feasibility_filter,
                                                  const int feasible_block_array_size,
                                                  t_ext_pin_util max_external_pin_util) {
    int molecule_size, failed_location;
    int i;
    enum e_block_pack_status block_pack_status;
    t_pb* parent;
    t_pb* cur_pb;
    auto& atom_ctx = g_vpr_ctx.atom();
    parent = nullptr;
    block_pack_status = BLK_STATUS_UNDEFINED;
    molecule_size = get_array_size_of_molecule(molecule);
    failed_location = 0;
    if (verbosity > 3) {
        AtomBlockId root_atom = molecule->atom_block_ids[molecule->root];
        VTR_LOG("\t\tTry pack molecule: '%s' (%s)",
                atom_ctx.nlist.block_name(root_atom).c_str(),
                atom_ctx.nlist.block_model(root_atom)->name);
        VTR_LOGV(molecule->pack_pattern,
                 " molecule_type %s molecule_size %zu",
                 molecule->pack_pattern->name,
                 molecule->atom_block_ids.size());
        VTR_LOG("\n");
    }
    if (cluster_placement_stats_ptr->has_long_chain && molecule->is_chain() && molecule->chain_info->is_long_chain) {
        VTR_LOGV(verbosity > 4, "\t\t\tFAILED Placement Feasibility Filter: Only one long chain per cluster is allowed\n");
        return BLK_FAILED_FEASIBLE;
    }
    while (block_pack_status != BLK_PASSED) {
        if (get_next_primitive_list(cluster_placement_stats_ptr, molecule,
                                    primitives_list)) {
            block_pack_status = BLK_PASSED;
            for (i = 0; i < molecule_size && block_pack_status == BLK_PASSED; i++) {
                VTR_ASSERT((primitives_list[i] == nullptr) == (!molecule->atom_block_ids[i]));
                failed_location = i + 1;
                if (molecule->atom_block_ids[i]) {
                    block_pack_status = try_place_atom_block_rec(primitives_list[i],
                                                                 molecule->atom_block_ids[i], pb, &parent,
                                                                 max_models, max_cluster_size, clb_index,
                                                                 cluster_placement_stats_ptr, molecule, router_data,
                                                                 verbosity, feasible_block_array_size);
                }
            }
            if (enable_pin_feasibility_filter && block_pack_status == BLK_PASSED) {
                reset_lookahead_pins_used(pb);
                try_update_lookahead_pins_used(pb);
                if (!check_lookahead_pins_used(pb, max_external_pin_util)) {
                    VTR_LOGV(verbosity > 4, "\t\t\tFAILED Pin Feasibility Filter\n");
                    block_pack_status = BLK_FAILED_FEASIBLE;
                }
            }
            if (block_pack_status == BLK_PASSED) {
                t_mode_selection_status mode_status;
                bool is_routed = false;
                bool do_detailed_routing_stage = detailed_routing_stage == (int)E_DETAILED_ROUTE_FOR_EACH_ATOM;
                if (do_detailed_routing_stage) {
                    do {
                        reset_intra_lb_route(router_data);
                        is_routed = try_intra_lb_route(router_data, verbosity, &mode_status);
                    } while (do_detailed_routing_stage && mode_status.is_mode_issue());
                }
                if (do_detailed_routing_stage && is_routed == false) {
                    VTR_LOGV(verbosity > 4, "\t\t\tFAILED Detailed Routing Legality\n");
                    block_pack_status = BLK_FAILED_ROUTE;
                } else {
                    VTR_ASSERT(block_pack_status == BLK_PASSED);
                    if (molecule->is_chain()) {
                        AtomBlockId chain_root_blk_id = molecule->atom_block_ids[molecule->pack_pattern->root_block->block_id];
                        cur_pb = atom_ctx.lookup.atom_pb(chain_root_blk_id)->parent_pb;
                        while (cur_pb != nullptr) {
                            free(cur_pb->name);
                            cur_pb->name = vtr::strdup(atom_ctx.nlist.block_name(chain_root_blk_id).c_str());
                            cur_pb = cur_pb->parent_pb;
                        }
                        if (molecule->chain_info->is_long_chain) {
                            cluster_placement_stats_ptr->has_long_chain = true;
                            if (molecule->chain_info->chain_id == -1) {
                                update_molecule_chain_info(molecule, primitives_list[molecule->root]);
                            }
                        }
                    }
                    for (i = 0; i < molecule_size; i++) {
                        if (molecule->atom_block_ids[i]) {
                            auto rng = atom_molecules.equal_range(molecule->atom_block_ids[i]);
                            for (const auto& kv : vtr::make_range(rng.first, rng.second)) {
                                t_pack_molecule* cur_molecule = kv.second;
                                cur_molecule->valid = false;
                            }
                            commit_primitive(cluster_placement_stats_ptr, primitives_list[i]);
                        }
                    }
                }
            }
            if (block_pack_status != BLK_PASSED) {
                for (i = 0; i < failed_location; i++) {
                    if (molecule->atom_block_ids[i]) {
                        remove_atom_from_target(router_data, molecule->atom_block_ids[i]);
                    }
                }
                for (i = 0; i < failed_location; i++) {
                    if (molecule->atom_block_ids[i]) {
                        revert_place_atom_block(molecule->atom_block_ids[i], router_data, atom_molecules);
                    }
                }
                cleanup_pb(pb);
            } else {
                VTR_LOGV(verbosity > 3, "\t\tPASSED pack molecule\n");
            }
        } else {
            VTR_LOGV(verbosity > 3, "\t\tFAILED No candidate primitives available\n");
            block_pack_status = BLK_FAILED_FEASIBLE;
            break; 
        }
    }
    return block_pack_status;
}
static enum e_block_pack_status try_pack_molecule ( t_cluster_placement_stats * cluster_placement_stats_ptr , const std :: multimap < AtomBlockId , t_pack_molecule * > & atom_molecules , t_pack_molecule * molecule , t_pb_graph_node * * primitives_list , t_pb * pb , const int max_models , const int max_cluster_size , const ClusterBlockId clb_index , const int detailed_routing_stage , t_lb_router_data * router_data , int verbosity , bool enable_pin_feasibility_filter , const int feasible_block_array_size , t_ext_pin_util max_external_pin_util ) { int molecule_size , failed_location ; int i ; enum e_block_pack_status block_pack_status ; t_pb * parent ; t_pb * cur_pb ; auto & atom_ctx = g_vpr_ctx . atom ( ) ; parent = nullptr ; block_pack_status = BLK_STATUS_UNDEFINED ; molecule_size = get_array_size_of_molecule ( molecule ) ; failed_location = 0 ; if ( verbosity > 3 ) { AtomBlockId root_atom = molecule -> atom_block_ids [ molecule -> root ] ; VTR_LOG ( " \t \t " , atom_ctx . nlist . block_name ( root_atom ) . c_str ( ) , atom_ctx . nlist . block_model ( root_atom ) -> name ) ; VTR_LOGV ( molecule -> pack_pattern , " " , molecule -> pack_pattern -> name , molecule -> atom_block_ids . size ( ) ) ; VTR_LOG ( " \n " ) ; } if ( cluster_placement_stats_ptr -> has_long_chain && molecule -> is_chain ( ) && molecule -> chain_info -> is_long_chain ) { VTR_LOGV ( verbosity > 4 , " \t \t \t \n " ) ; return BLK_FAILED_FEASIBLE ; } while ( block_pack_status != BLK_PASSED ) { if ( get_next_primitive_list ( cluster_placement_stats_ptr , molecule , primitives_list ) ) { block_pack_status = BLK_PASSED ; for ( i = 0 ; i < molecule_size && block_pack_status == BLK_PASSED ; i ++ ) { VTR_ASSERT ( ( primitives_list [ i ] == nullptr ) == ( ! molecule -> atom_block_ids [ i ] ) ) ; failed_location = i + 1 ; if ( molecule -> atom_block_ids [ i ] ) { block_pack_status = try_place_atom_block_rec ( primitives_list [ i ] , molecule -> atom_block_ids [ i ] , pb , & parent , max_models , max_cluster_size , clb_index , cluster_placement_stats_ptr , molecule , router_data , verbosity , feasible_block_array_size ) ; } } if ( enable_pin_feasibility_filter && block_pack_status == BLK_PASSED ) { reset_lookahead_pins_used ( pb ) ; try_update_lookahead_pins_used ( pb ) ; if ( ! check_lookahead_pins_used ( pb , max_external_pin_util ) ) { VTR_LOGV ( verbosity > 4 , " \t \t \t \n " ) ; block_pack_status = BLK_FAILED_FEASIBLE ; } } if ( block_pack_status == BLK_PASSED ) { t_mode_selection_status mode_status ; bool is_routed = false ; bool do_detailed_routing_stage = detailed_routing_stage == ( int ) E_DETAILED_ROUTE_FOR_EACH_ATOM ; if ( do_detailed_routing_stage ) { do { reset_intra_lb_route ( router_data ) ; is_routed = try_intra_lb_route ( router_data , verbosity , & mode_status ) ; } while ( do_detailed_routing_stage && mode_status . is_mode_issue ( ) ) ; } if ( do_detailed_routing_stage && is_routed == false ) { VTR_LOGV ( verbosity > 4 , " \t \t \t \n " ) ; block_pack_status = BLK_FAILED_ROUTE ; } else { VTR_ASSERT ( block_pack_status == BLK_PASSED ) ; if ( molecule -> is_chain ( ) ) { AtomBlockId chain_root_blk_id = molecule -> atom_block_ids [ molecule -> pack_pattern -> root_block -> block_id ] ; cur_pb = atom_ctx . lookup . atom_pb ( chain_root_blk_id ) -> parent_pb ; while ( cur_pb != nullptr ) { free ( cur_pb -> name ) ; cur_pb -> name = vtr :: strdup ( atom_ctx . nlist . block_name ( chain_root_blk_id ) . c_str ( ) ) ; cur_pb = cur_pb -> parent_pb ; } if ( molecule -> chain_info -> is_long_chain ) { cluster_placement_stats_ptr -> has_long_chain = true ; if ( molecule -> chain_info -> chain_id == -1 ) { update_molecule_chain_info ( molecule , primitives_list [ molecule -> root ] ) ; } } } for ( i = 0 ; i < molecule_size ; i ++ ) { if ( molecule -> atom_block_ids [ i ] ) { auto rng = atom_molecules . equal_range ( molecule -> atom_block_ids [ i ] ) ; for ( const auto & kv : vtr :: make_range ( rng . first , rng . second ) ) { t_pack_molecule * cur_molecule = kv . second ; cur_molecule -> valid = false ; } commit_primitive ( cluster_placement_stats_ptr , primitives_list [ i ] ) ; } } } } if ( block_pack_status != BLK_PASSED ) { for ( i = 0 ; i < failed_location ; i ++ ) { if ( molecule -> atom_block_ids [ i ] ) { remove_atom_from_target ( router_data , molecule -> atom_block_ids [ i ] ) ; } } for ( i = 0 ; i < failed_location ; i ++ ) { if ( molecule -> atom_block_ids [ i ] ) { revert_place_atom_block ( molecule -> atom_block_ids [ i ] , router_data , atom_molecules ) ; } } cleanup_pb ( pb ) ; } else { VTR_LOGV ( verbosity > 3 , " \t \t \n " ) ; } } else { VTR_LOGV ( verbosity > 3 , " \t \t \n " ) ; block_pack_status = BLK_FAILED_FEASIBLE ; break ; } } return block_pack_status ; }
Try pack molecule into current cluster
Try pack molecule into current cluster
// if this cluster has a molecule placed in it that is part of a long chain // (a chain that consists of more than one molecule), don't allow more long chain // molecules to be placed in this cluster. To avoid possibly creating cluster level // blocks that have incompatible placement constraints or form very long placement // macros that limit placement flexibility. // try place atom block if it exists /* Check if pin usage is feasible for the current packing assignment */ /*
                 * during the clustering step of `do_clustering`, `detailed_routing_stage` is incremented at each iteration until it a cluster
                 * is correctly generated or `detailed_routing_stage` assumes an invalid value (E_DETAILED_ROUTE_INVALID).
                 * depending on its value we have different behaviors:
                 *	- E_DETAILED_ROUTE_AT_END_ONLY:	Skip routing if heuristic is to route at the end of packing complex block.
                 *	- E_DETAILED_ROUTE_FOR_EACH_ATOM: Try to route if heuristic is to route for every atom. If the clusterer arrives at this stage,
                 *	                                  it means that more checks have to be performed as the previous stage failed to generate a new cluster.
                 *
                 * mode_status is a data structure containing the status of the mode selection. Its members are:
                 *  - bool is_mode_conflict
                 *  - bool try_expand_all_modes
                 *  - bool expand_all_modes
                 *
                 * is_mode_conflict affects this stage. Its value determines whether the cluster failed to pack after a mode conflict issue.
                 * It holds a flag that is used to verify whether try_intra_lb_route ended in a mode conflict issue.
                 *
                 * Until is_mode_conflict is set to FALSE by try_intra_lb_route, the loop re-iterates. If all the available modes are exhausted
                 * an error will be thrown during mode conflicts checks (this to prevent infinite loops).
                 *
                 * If the value is TRUE the cluster has to be re-routed, and its internal pb_graph_nodes will have more restrict choices
                 * for what regards the mode that has to be selected.
                 *
                 * is_mode_conflict is initially set to TRUE, and, unless a mode conflict is found, it is set to false in `try_intra_lb_route`.
                 *
                 * try_expand_all_modes is set if the node expansion failed to find a valid routing path. The clusterer tries to find another route
                 * by using all the modes during node expansion.
                 *
                 * expand_all_modes is used to enable the expansion of all the nodes using all the possible modes.
                 */ /* Cannot pack */ /* Pack successful, commit
                     * TODO: SW Engineering note - may want to update cluster stats here too instead of doing it outside
                     */ /* Chained molecules often take up lots of area and are important,
                         * if a chain is packed in, want to rename logic block to match chain name */ // if this molecule is part of a chain, mark the cluster as having a long chain // molecule. Also check if it's the first molecule in the chain to be packed. // If so, update the chain id for this chain of molecules to make sure all // molecules will be packed to the same chain id and can reach each other using // the chain direct links between clusters /* invalidate all molecules that share atom block with current molecule */ /* Placement failed, clean the pb */ /* no more candidate primitives available, this molecule will not pack, return fail */