src/mem/ruby/network/garnet/NetworkInterface.cc
/*
 * The NI wakeup checks whether there are any ready messages in the protocol
 * buffer. If yes, it picks that up, flitisizes it into a number of flits and
 * puts it into an output buffer and schedules the output link. On a wakeup
 * it also checks whether there are flits in the input link. If yes, it picks
 * them up and if the flit is a tail, the NI inserts the corresponding message
 * into the protocol buffer. It also checks for credits being sent by the
 * downstream router.
 */
The NI wakeup checks whether there are any ready messages in the protocol
buffer. If yes, it picks that up, flitisizes it into a number of flits and
puts it into an output buffer and schedules the output link. On a wakeup
it also checks whether there are flits in the input link. If yes, it picks
them up and if the flit is a tail, the NI inserts the corresponding message
into the protocol buffer. It also checks for credits being sent by the
downstream router.
The NI wakeup checks whether there are any ready messages in the protocol buffer . If yes it picks that up flitisizes it into a number of flits and puts it into an output buffer and schedules the output link . On a wakeup it also checks whether there are flits in the input link . If yes it picks them up and if the flit is a tail the NI inserts the corresponding message into the protocol buffer . It also checks for credits being sent by the downstream router .
void
NetworkInterface::wakeup()
{
    std::ostringstream oss;
    for (auto &oPort: outPorts) {
        oss << oPort->routerID() << "[" << oPort->printVnets() << "] ";
    }
    DPRINTF(RubyNetwork, "Network Interface %d connected to router:%s "
            "woke up. Period: %ld\n", m_id, oss.str(), clockPeriod());
    assert(curTick() == clockEdge());
    MsgPtr msg_ptr;
    Tick curTime = clockEdge();
    for (int vnet = 0; vnet < inNode_ptr.size(); ++vnet) {
        MessageBuffer *b = inNode_ptr[vnet];
        if (b == nullptr) {
            continue;
        }
        if (b->isReady(curTime)) { 
            msg_ptr = b->peekMsgPtr();
            if (flitisizeMessage(msg_ptr, vnet)) {
                b->dequeue(curTime);
            }
        }
    }
    scheduleOutputLink();
    checkStallQueue();
    DPRINTF(RubyNetwork, "Number of input ports: %d\n", inPorts.size());
    for (auto &iPort: inPorts) {
        NetworkLink *inNetLink = iPort->inNetLink();
        if (inNetLink->isReady(curTick())) {
            flit *t_flit = inNetLink->consumeLink();
            DPRINTF(RubyNetwork, "Recieved flit:%s\n", *t_flit);
            assert(t_flit->m_width == iPort->bitWidth());
            int vnet = t_flit->get_vnet();
            t_flit->set_dequeue_time(curTick());
            if (t_flit->get_type() == TAIL_ ||
                t_flit->get_type() == HEAD_TAIL_) {
                if (!iPort->messageEnqueuedThisCycle &&
                    outNode_ptr[vnet]->areNSlotsAvailable(1, curTime)) {
                    outNode_ptr[vnet]->enqueue(t_flit->get_msg_ptr(), curTime,
                                               cyclesToTicks(Cycles(1)));
                    Credit *cFlit = new Credit(t_flit->get_vc(),
                                               true, curTick());
                    iPort->sendCredit(cFlit);
                    incrementStats(t_flit);
                    delete t_flit;
                } else {
                    iPort->m_stall_queue.push_back(t_flit);
                    m_stall_count[vnet]++;
                    outNode_ptr[vnet]->registerDequeueCallback([this]() {
                        dequeueCallback(); });
                }
            } else {
                Credit *cFlit = new Credit(t_flit->get_vc(), false,
                                               curTick());
                iPort->sendCredit(cFlit);
                .
                incrementStats(t_flit);
                delete t_flit;
            }
        }
    }
    for (auto &oPort: outPorts) {
        CreditLink *inCreditLink = oPort->inCreditLink();
        if (inCreditLink->isReady(curTick())) {
            Credit *t_credit = (Credit*) inCreditLink->consumeLink();
            outVcState[t_credit->get_vc()].increment_credit();
            if (t_credit->is_free_signal()) {
                outVcState[t_credit->get_vc()].setState(IDLE_,
                    curTick());
            }
            delete t_credit;
        }
    }
    for (auto &iPort: inPorts) {
        if (iPort->outCreditQueue()->getSize() > 0) {
            DPRINTF(RubyNetwork, "Sending a credit %s via %s at %ld\n",
            *(iPort->outCreditQueue()->peekTopFlit()),
            iPort->outCreditLink()->name(), clockEdge(Cycles(1)));
            iPort->outCreditLink()->
                scheduleEventAbsolute(clockEdge(Cycles(1)));
        }
    }
    checkReschedule();
}
void NetworkInterface :: wakeup ( ) { std :: ostringstream oss ; for ( auto & oPort : outPorts ) { oss << oPort -> routerID ( ) << " " << oPort -> printVnets ( ) << " " ; } DPRINTF ( RubyNetwork , " " " \n " , m_id , oss . str ( ) , clockPeriod ( ) ) ; assert ( curTick ( ) == clockEdge ( ) ) ; MsgPtr msg_ptr ; Tick curTime = clockEdge ( ) ; for ( int vnet = 0 ; vnet < inNode_ptr . size ( ) ; ++ vnet ) { MessageBuffer * b = inNode_ptr [ vnet ] ; if ( b == nullptr ) { continue ; } if ( b -> isReady ( curTime ) ) { msg_ptr = b -> peekMsgPtr ( ) ; if ( flitisizeMessage ( msg_ptr , vnet ) ) { b -> dequeue ( curTime ) ; } } } scheduleOutputLink ( ) ; checkStallQueue ( ) ; DPRINTF ( RubyNetwork , " \n " , inPorts . size ( ) ) ; for ( auto & iPort : inPorts ) { NetworkLink * inNetLink = iPort -> inNetLink ( ) ; if ( inNetLink -> isReady ( curTick ( ) ) ) { flit * t_flit = inNetLink -> consumeLink ( ) ; DPRINTF ( RubyNetwork , " \n " , * t_flit ) ; assert ( t_flit -> m_width == iPort -> bitWidth ( ) ) ; int vnet = t_flit -> get_vnet ( ) ; t_flit -> set_dequeue_time ( curTick ( ) ) ; if ( t_flit -> get_type ( ) == TAIL_ || t_flit -> get_type ( ) == HEAD_TAIL_ ) { if ( ! iPort -> messageEnqueuedThisCycle && outNode_ptr [ vnet ] -> areNSlotsAvailable ( 1 , curTime ) ) { outNode_ptr [ vnet ] -> enqueue ( t_flit -> get_msg_ptr ( ) , curTime , cyclesToTicks ( Cycles ( 1 ) ) ) ; Credit * cFlit = new Credit ( t_flit -> get_vc ( ) , true , curTick ( ) ) ; iPort -> sendCredit ( cFlit ) ; incrementStats ( t_flit ) ; delete t_flit ; } else { iPort -> m_stall_queue . push_back ( t_flit ) ; m_stall_count [ vnet ] ++ ; outNode_ptr [ vnet ] -> registerDequeueCallback ( [ this ] ( ) { dequeueCallback ( ) ; } ) ; } } else { Credit * cFlit = new Credit ( t_flit -> get_vc ( ) , false , curTick ( ) ) ; iPort -> sendCredit ( cFlit ) ; incrementStats ( t_flit ) ; delete t_flit ; } } } for ( auto & oPort : outPorts ) { CreditLink * inCreditLink = oPort -> inCreditLink ( ) ; if ( inCreditLink -> isReady ( curTick ( ) ) ) { Credit * t_credit = ( Credit * ) inCreditLink -> consumeLink ( ) ; outVcState [ t_credit -> get_vc ( ) ] . increment_credit ( ) ; if ( t_credit -> is_free_signal ( ) ) { outVcState [ t_credit -> get_vc ( ) ] . setState ( IDLE_ , curTick ( ) ) ; } delete t_credit ; } } for ( auto & iPort : inPorts ) { if ( iPort -> outCreditQueue ( ) -> getSize ( ) > 0 ) { DPRINTF ( RubyNetwork , " \n " , * ( iPort -> outCreditQueue ( ) -> peekTopFlit ( ) ) , iPort -> outCreditLink ( ) -> name ( ) , clockEdge ( Cycles ( 1 ) ) ) ; iPort -> outCreditLink ( ) -> scheduleEventAbsolute ( clockEdge ( Cycles ( 1 ) ) ) ; } } checkReschedule ( ) ; }
The NI wakeup checks whether there are any ready messages in the protocol
 buffer.
The NI wakeup checks whether there are any ready messages in the protocol buffer .
// Checking for messages coming from the protocol // can pick up a message/cycle for each virtual net // Is there a message waiting // Check if there are flits stalling a virtual channel. Track if a // message is enqueued to restrict ejection to one message per cycle. /*********** Check the incoming flit link **********/ // If a tail flit is received, enqueue into the protocol buffers // if space is available. Otherwise, exchange non-tail flits for // credits. // Space is available. Enqueue to protocol buffer. // Simply send a credit back since we are not buffering // this flit in the NI // Update stats and delete flit pointer // No space available- Place tail flit in stall queue and // set up a callback for when protocol buffer is dequeued. // Stat update and flit pointer deletion will occur upon // unstall. // Non-tail flit. Send back a credit but not VC free signal. // Simply send a credit back since we are not buffering // this flit in the NI // Update stats and delete flit pointer. /****************** Check the incoming credit link *******/ // It is possible to enqueue multiple outgoing credit flits if a message // was unstalled in the same cycle as a new message arrives. In this // case, we should schedule another wakeup to ensure the credit is sent // back.