vpr/src/route/rr_graph.cpp
/* Calculates the number of track connections from each block pin to each segment type */
Calculates the number of track connections from each block pin to each segment type
Calculates the number of track connections from each block pin to each segment type
std::vector<vtr::Matrix<int>> alloc_and_load_actual_fc(const std::vector<t_physical_tile_type>& types,
                                                       const int max_pins,
                                                       const std::vector<t_segment_inf>& segment_inf,
                                                       const int* sets_per_seg_type,
                                                       const int max_chan_width,
                                                       const e_fc_type fc_type,
                                                       const enum e_directionality directionality,
                                                       bool* Fc_clipped) {
    auto zeros = vtr::Matrix<int>({size_t(max_pins), segment_inf.size()}, 0);
    std::vector<vtr::Matrix<int>> Fc(types.size(), zeros);
    *Fc_clipped = false;
    int fac = 1;
    if (UNI_DIRECTIONAL == directionality) {
        fac = 2;
    }
    VTR_ASSERT((max_chan_width % fac) == 0);
    for (const auto& type : types) { 
        int itype = type.index;
        for (const t_fc_specification& fc_spec : type.fc_specs) {
            if (fc_type != fc_spec.fc_type) continue;
            VTR_ASSERT(fc_spec.pins.size() > 0);
            int iseg = fc_spec.seg_index;
            if (fc_spec.fc_value == 0) {
                for (int ipin : fc_spec.pins) {
                    Fc[itype][ipin][iseg] = 0;
                }
            } else {
                int total_connections = 0;
                if (fc_spec.fc_value_type == e_fc_value_type::FRACTIONAL) {
                    float conns_per_pin = fac * sets_per_seg_type[iseg] * fc_spec.fc_value;
                    float flt_total_connections = conns_per_pin * fc_spec.pins.size();
                    total_connections = vtr::nint(flt_total_connections); 
                } else {
                    VTR_ASSERT(fc_spec.fc_value_type == e_fc_value_type::ABSOLUTE);
                    if (std::fmod(fc_spec.fc_value, fac) != 0.) {
                        VPR_FATAL_ERROR(VPR_ERROR_ROUTE, "Absolute Fc value must be a multiple of %d (was %f) between block pin '%s' and wire segment '%s'",
                                        fac, fc_spec.fc_value,
                                        block_type_pin_index_to_name(&type, fc_spec.pins[0]).c_str(),
                                        segment_inf[iseg].name.c_str());
                    }
                    if (fc_spec.fc_value < fac) {
                        VPR_FATAL_ERROR(VPR_ERROR_ROUTE, "Absolute Fc value must be at least %d (was %f) between block pin '%s' to wire segment %s",
                                        fac, fc_spec.fc_value,
                                        block_type_pin_index_to_name(&type, fc_spec.pins[0]).c_str(),
                                        segment_inf[iseg].name.c_str());
                    }
                    total_connections = vtr::nint(fc_spec.fc_value) * fc_spec.pins.size();
                }
                total_connections = std::max(total_connections, fac);
                total_connections += (total_connections % fac);
                VTR_ASSERT(total_connections > 0);
                VTR_ASSERT(total_connections % fac == 0);
                int connections_remaining = total_connections;
                while (connections_remaining != 0) {
                    for (int ipin : fc_spec.pins) {
                        if (connections_remaining >= fac) {
                            Fc[itype][ipin][iseg] += fac;
                            connections_remaining -= fac;
                        } else {
                            VTR_ASSERT(connections_remaining == 0);
                            break;
                        }
                    }
                }
                for (int ipin : fc_spec.pins) {
                    if (Fc[itype][ipin][iseg] > sets_per_seg_type[iseg] * fac) {
                        *Fc_clipped = true;
                        Fc[itype][ipin][iseg] = sets_per_seg_type[iseg] * fac;
                    }
                    VTR_ASSERT_MSG(Fc[itype][ipin][iseg] >= 0, "Calculated absolute Fc must be positive");
                    VTR_ASSERT_MSG(Fc[itype][ipin][iseg] % fac == 0, "Calculated absolute Fc must be divisible by 1 (bidir architecture) or 2 (unidir architecture)"); 
                }
            }
        }
    }
    return Fc;
}
std :: vector < vtr :: Matrix < int > > alloc_and_load_actual_fc ( const std :: vector < t_physical_tile_type > & types , const int max_pins , const std :: vector < t_segment_inf > & segment_inf , const int * sets_per_seg_type , const int max_chan_width , const e_fc_type fc_type , const enum e_directionality directionality , bool * Fc_clipped ) { auto zeros = vtr :: Matrix < int > ( { size_t ( max_pins ) , segment_inf . size ( ) } , 0 ) ; std :: vector < vtr :: Matrix < int > > Fc ( types . size ( ) , zeros ) ; * Fc_clipped = false ; int fac = 1 ; if ( UNI_DIRECTIONAL == directionality ) { fac = 2 ; } VTR_ASSERT ( ( max_chan_width % fac ) == 0 ) ; for ( const auto & type : types ) { int itype = type . index ; for ( const t_fc_specification & fc_spec : type . fc_specs ) { if ( fc_type != fc_spec . fc_type ) continue ; VTR_ASSERT ( fc_spec . pins . size ( ) > 0 ) ; int iseg = fc_spec . seg_index ; if ( fc_spec . fc_value == 0 ) { for ( int ipin : fc_spec . pins ) { Fc [ itype ] [ ipin ] [ iseg ] = 0 ; } } else { int total_connections = 0 ; if ( fc_spec . fc_value_type == e_fc_value_type :: FRACTIONAL ) { float conns_per_pin = fac * sets_per_seg_type [ iseg ] * fc_spec . fc_value ; float flt_total_connections = conns_per_pin * fc_spec . pins . size ( ) ; total_connections = vtr :: nint ( flt_total_connections ) ; } else { VTR_ASSERT ( fc_spec . fc_value_type == e_fc_value_type :: ABSOLUTE ) ; if ( std :: fmod ( fc_spec . fc_value , fac ) != 0. ) { VPR_FATAL_ERROR ( VPR_ERROR_ROUTE , " " , fac , fc_spec . fc_value , block_type_pin_index_to_name ( & type , fc_spec . pins [ 0 ] ) . c_str ( ) , segment_inf [ iseg ] . name . c_str ( ) ) ; } if ( fc_spec . fc_value < fac ) { VPR_FATAL_ERROR ( VPR_ERROR_ROUTE , " " , fac , fc_spec . fc_value , block_type_pin_index_to_name ( & type , fc_spec . pins [ 0 ] ) . c_str ( ) , segment_inf [ iseg ] . name . c_str ( ) ) ; } total_connections = vtr :: nint ( fc_spec . fc_value ) * fc_spec . pins . size ( ) ; } total_connections = std :: max ( total_connections , fac ) ; total_connections += ( total_connections % fac ) ; VTR_ASSERT ( total_connections > 0 ) ; VTR_ASSERT ( total_connections % fac == 0 ) ; int connections_remaining = total_connections ; while ( connections_remaining != 0 ) { for ( int ipin : fc_spec . pins ) { if ( connections_remaining >= fac ) { Fc [ itype ] [ ipin ] [ iseg ] += fac ; connections_remaining -= fac ; } else { VTR_ASSERT ( connections_remaining == 0 ) ; break ; } } } for ( int ipin : fc_spec . pins ) { if ( Fc [ itype ] [ ipin ] [ iseg ] > sets_per_seg_type [ iseg ] * fac ) { * Fc_clipped = true ; Fc [ itype ] [ ipin ] [ iseg ] = sets_per_seg_type [ iseg ] * fac ; } VTR_ASSERT_MSG ( Fc [ itype ] [ ipin ] [ iseg ] >= 0 , " " ) ; VTR_ASSERT_MSG ( Fc [ itype ] [ ipin ] [ iseg ] % fac == 0 , " " ) ; } } } } return Fc ; }
Calculates the number of track connections from each block pin to each segment type
Calculates the number of track connections from each block pin to each segment type
//Initialize Fc of all blocks to zero /* Unidir tracks formed in pairs, otherwise no effect. */ //Skip EMPTY /* Special case indicating that this pin does not connect to general-purpose routing */ /* General case indicating that this pin connects to general-purpose routing */ //Calculate how many connections there should be accross all the pins in this fc_spec //Round to integer //Ensure that there are at least fac connections, this ensures that low Fc ports //targeting small sets of segs get connection(s), even if flt_total_connections < fac. //Ensure total evenly divides fac by adding the remainder //We walk through all the pins this fc_spec applies to, adding fac connections //to each pin, until we run out of connections. This should distribute the connections //as evenly as possible (if total_connections % pins.size() != 0, there will be //some inevitable imbalance). //Add one set of connections to each pin //It is possible that we may want more connections that wires of this type exist; //clip to the maximum number of wires //Required by connection block construction code