src/mem/ruby/network/garnet/SwitchAllocator.cc
/*
 * SA-II (or SA-o) loops through all output ports,
 * and selects one input VC (that placed a request during SA-I)
 * as the winner for this output port in a round robin manner.
 *      - For HEAD/HEAD_TAIL flits, performs simplified outvc allocation.
 *        (i.e., select a free VC from the output port).
 *      - For BODY/TAIL flits, decrement a credit in the output vc.
 * The winning flit is read out from the input VC and sent to the
 * CrossbarSwitch.
 * An increment_credit signal is sent from the InputUnit
 * to the upstream router. For HEAD_TAIL/TAIL flits, is_free_signal in the
 * credit is set to true.
 */
SA-II (or SA-o) loops through all output ports,
and selects one input VC (that placed a request during SA-I)
as the winner for this output port in a round robin manner.
- For HEAD/HEAD_TAIL flits, performs simplified outvc allocation.
.
- For BODY/TAIL flits, decrement a credit in the output vc.
The winning flit is read out from the input VC and sent to the
CrossbarSwitch.
An increment_credit signal is sent from the InputUnit
to the upstream router. For HEAD_TAIL/TAIL flits, is_free_signal in the
credit is set to true.
SA - II ( or SA - o ) loops through all output ports and selects one input VC ( that placed a request during SA - I ) as the winner for this output port in a round robin manner . - For HEAD / HEAD_TAIL flits performs simplified outvc allocation . . - For BODY / TAIL flits decrement a credit in the output vc . The winning flit is read out from the input VC and sent to the CrossbarSwitch . An increment_credit signal is sent from the InputUnit to the upstream router . For HEAD_TAIL / TAIL flits is_free_signal in the credit is set to true .
void
SwitchAllocator::arbitrate_outports()
{
    for (int outport = 0; outport < m_num_outports; outport++) {
        int inport = m_round_robin_inport[outport];
        for (int inport_iter = 0; inport_iter < m_num_inports;
                 inport_iter++) {
            if (m_port_requests[inport] == outport) {
                auto output_unit = m_router->getOutputUnit(outport);
                auto input_unit = m_router->getInputUnit(inport);
                int invc = m_vc_winners[inport];
                int outvc = input_unit->get_outvc(invc);
                if (outvc == -1) {
                    outvc = vc_allocate(outport, inport, invc);
                }
                flit *t_flit = input_unit->getTopFlit(invc);
                DPRINTF(RubyNetwork, "SwitchAllocator at Router %d "
                                     "granted outvc %d at outport %d "
                                     "to invc %d at inport %d to flit %s at "
                                     "cycle: %lld\n",
                        m_router->get_id(), outvc,
                        m_router->getPortDirectionName(
                            output_unit->get_direction()),
                        invc,
                        m_router->getPortDirectionName(
                            input_unit->get_direction()),
                            *t_flit,
                        m_router->curCycle());
                t_flit->set_outport(outport);
                t_flit->set_vc(outvc);
                output_unit->decrement_credit(outvc);
                t_flit->advance_stage(ST_, curTick());
                m_router->grant_switch(inport, t_flit);
                m_output_arbiter_activity++;
                if ((t_flit->get_type() == TAIL_) ||
                    t_flit->get_type() == HEAD_TAIL_) {
                    assert(!(input_unit->isReady(invc, curTick())));
                    input_unit->set_vc_idle(invc, curTick());
                    input_unit->increment_credit(invc, true, curTick());
                } else {
                    input_unit->increment_credit(invc, false, curTick());
                }
                m_port_requests[inport] = -1;
                m_round_robin_inport[outport] = inport + 1;
                if (m_round_robin_inport[outport] >= m_num_inports)
                    m_round_robin_inport[outport] = 0;
                 to the next VC
                m_round_robin_invc[inport] = invc + 1;
                if (m_round_robin_invc[inport] >= m_num_vcs)
                    m_round_robin_invc[inport] = 0;
                break; 
            }
            inport++;
            if (inport >= m_num_inports)
                inport = 0;
        }
    }
}
void SwitchAllocator :: arbitrate_outports ( ) { for ( int outport = 0 ; outport < m_num_outports ; outport ++ ) { int inport = m_round_robin_inport [ outport ] ; for ( int inport_iter = 0 ; inport_iter < m_num_inports ; inport_iter ++ ) { if ( m_port_requests [ inport ] == outport ) { auto output_unit = m_router -> getOutputUnit ( outport ) ; auto input_unit = m_router -> getInputUnit ( inport ) ; int invc = m_vc_winners [ inport ] ; int outvc = input_unit -> get_outvc ( invc ) ; if ( outvc == -1 ) { outvc = vc_allocate ( outport , inport , invc ) ; } flit * t_flit = input_unit -> getTopFlit ( invc ) ; DPRINTF ( RubyNetwork , " " " " " " " \n " , m_router -> get_id ( ) , outvc , m_router -> getPortDirectionName ( output_unit -> get_direction ( ) ) , invc , m_router -> getPortDirectionName ( input_unit -> get_direction ( ) ) , * t_flit , m_router -> curCycle ( ) ) ; t_flit -> set_outport ( outport ) ; t_flit -> set_vc ( outvc ) ; output_unit -> decrement_credit ( outvc ) ; t_flit -> advance_stage ( ST_ , curTick ( ) ) ; m_router -> grant_switch ( inport , t_flit ) ; m_output_arbiter_activity ++ ; if ( ( t_flit -> get_type ( ) == TAIL_ ) || t_flit -> get_type ( ) == HEAD_TAIL_ ) { assert ( ! ( input_unit -> isReady ( invc , curTick ( ) ) ) ) ; input_unit -> set_vc_idle ( invc , curTick ( ) ) ; input_unit -> increment_credit ( invc , true , curTick ( ) ) ; } else { input_unit -> increment_credit ( invc , false , curTick ( ) ) ; } m_port_requests [ inport ] = -1 ; m_round_robin_inport [ outport ] = inport + 1 ; if ( m_round_robin_inport [ outport ] >= m_num_inports ) m_round_robin_inport [ outport ] = 0 ; m_round_robin_invc [ inport ] = invc + 1 ; if ( m_round_robin_invc [ inport ] >= m_num_vcs ) m_round_robin_invc [ inport ] = 0 ; break ; } inport ++ ; if ( inport >= m_num_inports ) inport = 0 ; } } }
SA-II (or SA-o) loops through all output ports,
 and selects one input VC (that placed a request during SA-I)
 as the winner for this output port in a round robin manner.
SA - II ( or SA - o ) loops through all output ports and selects one input VC ( that placed a request during SA - I ) as the winner for this output port in a round robin manner .
// Now there are a set of input vc requests for output vcs. // Again do round robin arbitration on these requests // Independent arbiter at each output port // inport has a request this cycle for outport // grant this outport to this inport // VC Allocation - select any free VC from outport // remove flit from Input VC // Update outport field in the flit since this is // used by CrossbarSwitch code to send it out of // correct outport. // Note: post route compute in InputUnit, // outport is updated in VC, but not in flit // set outvc (i.e., invc for next hop) in flit // (This was updated in VC by vc_allocate, but not in flit) // decrement credit in outvc // flit ready for Switch Traversal // This Input VC should now be empty // Free this VC // Send a credit back // along with the information that this VC is now idle // Send a credit back // but do not indicate that the VC is idle // remove this request // Update Round Robin pointer // Update Round Robin pointer to the next VC // We do it here to keep it fair. // Only the VC which got switch traversal // is updated. // got a input winner for this outport