111666Stushar@ece.gatech.edu/*
211666Stushar@ece.gatech.edu * Copyright (c) 2008 Princeton University
311666Stushar@ece.gatech.edu * Copyright (c) 2016 Georgia Institute of Technology
411666Stushar@ece.gatech.edu * All rights reserved.
511666Stushar@ece.gatech.edu *
611666Stushar@ece.gatech.edu * Redistribution and use in source and binary forms, with or without
711666Stushar@ece.gatech.edu * modification, are permitted provided that the following conditions are
811666Stushar@ece.gatech.edu * met: redistributions of source code must retain the above copyright
911666Stushar@ece.gatech.edu * notice, this list of conditions and the following disclaimer;
1011666Stushar@ece.gatech.edu * redistributions in binary form must reproduce the above copyright
1111666Stushar@ece.gatech.edu * notice, this list of conditions and the following disclaimer in the
1211666Stushar@ece.gatech.edu * documentation and/or other materials provided with the distribution;
1311666Stushar@ece.gatech.edu * neither the name of the copyright holders nor the names of its
1411666Stushar@ece.gatech.edu * contributors may be used to endorse or promote products derived from
1511666Stushar@ece.gatech.edu * this software without specific prior written permission.
1611666Stushar@ece.gatech.edu *
1711666Stushar@ece.gatech.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1811666Stushar@ece.gatech.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1911666Stushar@ece.gatech.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2011666Stushar@ece.gatech.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2111666Stushar@ece.gatech.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2211666Stushar@ece.gatech.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2311666Stushar@ece.gatech.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2411666Stushar@ece.gatech.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2511666Stushar@ece.gatech.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2611666Stushar@ece.gatech.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2711666Stushar@ece.gatech.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2811666Stushar@ece.gatech.edu *
2911666Stushar@ece.gatech.edu * Authors: Niket Agarwal
3011666Stushar@ece.gatech.edu *          Tushar Krishna
3111666Stushar@ece.gatech.edu */
3211666Stushar@ece.gatech.edu
3311666Stushar@ece.gatech.edu
3411666Stushar@ece.gatech.edu#include "mem/ruby/network/garnet2.0/NetworkInterface.hh"
3511666Stushar@ece.gatech.edu
3611666Stushar@ece.gatech.edu#include <cassert>
3711666Stushar@ece.gatech.edu#include <cmath>
3811666Stushar@ece.gatech.edu
3911666Stushar@ece.gatech.edu#include "base/cast.hh"
4011666Stushar@ece.gatech.edu#include "base/stl_helpers.hh"
4111666Stushar@ece.gatech.edu#include "debug/RubyNetwork.hh"
4211666Stushar@ece.gatech.edu#include "mem/ruby/network/MessageBuffer.hh"
4311666Stushar@ece.gatech.edu#include "mem/ruby/network/garnet2.0/Credit.hh"
4411666Stushar@ece.gatech.edu#include "mem/ruby/network/garnet2.0/flitBuffer.hh"
4511666Stushar@ece.gatech.edu#include "mem/ruby/slicc_interface/Message.hh"
4611666Stushar@ece.gatech.edu
4711666Stushar@ece.gatech.eduusing namespace std;
4811666Stushar@ece.gatech.eduusing m5::stl_helpers::deletePointers;
4911666Stushar@ece.gatech.edu
5011666Stushar@ece.gatech.eduNetworkInterface::NetworkInterface(const Params *p)
5111666Stushar@ece.gatech.edu    : ClockedObject(p), Consumer(this), m_id(p->id),
5211666Stushar@ece.gatech.edu      m_virtual_networks(p->virt_nets), m_vc_per_vnet(p->vcs_per_vnet),
5311762Sjieming.yin@amd.com      m_num_vcs(m_vc_per_vnet * m_virtual_networks),
5411762Sjieming.yin@amd.com      m_deadlock_threshold(p->garnet_deadlock_threshold),
5511762Sjieming.yin@amd.com      vc_busy_counter(m_virtual_networks, 0)
5611666Stushar@ece.gatech.edu{
5711666Stushar@ece.gatech.edu    m_router_id = -1;
5811666Stushar@ece.gatech.edu    m_vc_round_robin = 0;
5911666Stushar@ece.gatech.edu    m_ni_out_vcs.resize(m_num_vcs);
6011666Stushar@ece.gatech.edu    m_ni_out_vcs_enqueue_time.resize(m_num_vcs);
6111666Stushar@ece.gatech.edu    outCreditQueue = new flitBuffer();
6211666Stushar@ece.gatech.edu
6311666Stushar@ece.gatech.edu    // instantiating the NI flit buffers
6411666Stushar@ece.gatech.edu    for (int i = 0; i < m_num_vcs; i++) {
6511666Stushar@ece.gatech.edu        m_ni_out_vcs[i] = new flitBuffer();
6611666Stushar@ece.gatech.edu        m_ni_out_vcs_enqueue_time[i] = Cycles(INFINITE_);
6711666Stushar@ece.gatech.edu    }
6811666Stushar@ece.gatech.edu
6911666Stushar@ece.gatech.edu    m_vc_allocator.resize(m_virtual_networks); // 1 allocator per vnet
7011666Stushar@ece.gatech.edu    for (int i = 0; i < m_virtual_networks; i++) {
7111666Stushar@ece.gatech.edu        m_vc_allocator[i] = 0;
7211666Stushar@ece.gatech.edu    }
7311797Smatthew.poremba@amd.com
7411797Smatthew.poremba@amd.com    m_stall_count.resize(m_virtual_networks);
7511666Stushar@ece.gatech.edu}
7611666Stushar@ece.gatech.edu
7711666Stushar@ece.gatech.eduvoid
7811666Stushar@ece.gatech.eduNetworkInterface::init()
7911666Stushar@ece.gatech.edu{
8011666Stushar@ece.gatech.edu    for (int i = 0; i < m_num_vcs; i++) {
8111666Stushar@ece.gatech.edu        m_out_vc_state.push_back(new OutVcState(i, m_net_ptr));
8211666Stushar@ece.gatech.edu    }
8311666Stushar@ece.gatech.edu}
8411666Stushar@ece.gatech.edu
8511666Stushar@ece.gatech.eduNetworkInterface::~NetworkInterface()
8611666Stushar@ece.gatech.edu{
8711666Stushar@ece.gatech.edu    deletePointers(m_out_vc_state);
8811666Stushar@ece.gatech.edu    deletePointers(m_ni_out_vcs);
8911666Stushar@ece.gatech.edu    delete outCreditQueue;
9011666Stushar@ece.gatech.edu    delete outFlitQueue;
9111666Stushar@ece.gatech.edu}
9211666Stushar@ece.gatech.edu
9311666Stushar@ece.gatech.eduvoid
9411666Stushar@ece.gatech.eduNetworkInterface::addInPort(NetworkLink *in_link,
9511666Stushar@ece.gatech.edu                              CreditLink *credit_link)
9611666Stushar@ece.gatech.edu{
9711666Stushar@ece.gatech.edu    inNetLink = in_link;
9811666Stushar@ece.gatech.edu    in_link->setLinkConsumer(this);
9911666Stushar@ece.gatech.edu    outCreditLink = credit_link;
10011666Stushar@ece.gatech.edu    credit_link->setSourceQueue(outCreditQueue);
10111666Stushar@ece.gatech.edu}
10211666Stushar@ece.gatech.edu
10311666Stushar@ece.gatech.eduvoid
10411666Stushar@ece.gatech.eduNetworkInterface::addOutPort(NetworkLink *out_link,
10511666Stushar@ece.gatech.edu                             CreditLink *credit_link,
10611666Stushar@ece.gatech.edu                             SwitchID router_id)
10711666Stushar@ece.gatech.edu{
10811666Stushar@ece.gatech.edu    inCreditLink = credit_link;
10911666Stushar@ece.gatech.edu    credit_link->setLinkConsumer(this);
11011666Stushar@ece.gatech.edu
11111666Stushar@ece.gatech.edu    outNetLink = out_link;
11211666Stushar@ece.gatech.edu    outFlitQueue = new flitBuffer();
11311666Stushar@ece.gatech.edu    out_link->setSourceQueue(outFlitQueue);
11411666Stushar@ece.gatech.edu
11511666Stushar@ece.gatech.edu    m_router_id = router_id;
11611666Stushar@ece.gatech.edu}
11711666Stushar@ece.gatech.edu
11811666Stushar@ece.gatech.eduvoid
11911666Stushar@ece.gatech.eduNetworkInterface::addNode(vector<MessageBuffer *>& in,
12011666Stushar@ece.gatech.edu                            vector<MessageBuffer *>& out)
12111666Stushar@ece.gatech.edu{
12211666Stushar@ece.gatech.edu    inNode_ptr = in;
12311666Stushar@ece.gatech.edu    outNode_ptr = out;
12411666Stushar@ece.gatech.edu
12511666Stushar@ece.gatech.edu    for (auto& it : in) {
12611666Stushar@ece.gatech.edu        if (it != nullptr) {
12711666Stushar@ece.gatech.edu            it->setConsumer(this);
12811666Stushar@ece.gatech.edu        }
12911666Stushar@ece.gatech.edu    }
13011666Stushar@ece.gatech.edu}
13111666Stushar@ece.gatech.edu
13211797Smatthew.poremba@amd.comvoid
13311797Smatthew.poremba@amd.comNetworkInterface::dequeueCallback()
13411797Smatthew.poremba@amd.com{
13511797Smatthew.poremba@amd.com    // An output MessageBuffer has dequeued something this cycle and there
13611797Smatthew.poremba@amd.com    // is now space to enqueue a stalled message. However, we cannot wake
13711797Smatthew.poremba@amd.com    // on the same cycle as the dequeue. Schedule a wake at the soonest
13811797Smatthew.poremba@amd.com    // possible time (next cycle).
13911797Smatthew.poremba@amd.com    scheduleEventAbsolute(clockEdge(Cycles(1)));
14011797Smatthew.poremba@amd.com}
14111797Smatthew.poremba@amd.com
14211797Smatthew.poremba@amd.comvoid
14311797Smatthew.poremba@amd.comNetworkInterface::incrementStats(flit *t_flit)
14411797Smatthew.poremba@amd.com{
14511797Smatthew.poremba@amd.com    int vnet = t_flit->get_vnet();
14611797Smatthew.poremba@amd.com
14711797Smatthew.poremba@amd.com    // Latency
14811797Smatthew.poremba@amd.com    m_net_ptr->increment_received_flits(vnet);
14911797Smatthew.poremba@amd.com    Cycles network_delay =
15011797Smatthew.poremba@amd.com        t_flit->get_dequeue_time() - t_flit->get_enqueue_time() - Cycles(1);
15111797Smatthew.poremba@amd.com    Cycles src_queueing_delay = t_flit->get_src_delay();
15211797Smatthew.poremba@amd.com    Cycles dest_queueing_delay = (curCycle() - t_flit->get_dequeue_time());
15311797Smatthew.poremba@amd.com    Cycles queueing_delay = src_queueing_delay + dest_queueing_delay;
15411797Smatthew.poremba@amd.com
15511797Smatthew.poremba@amd.com    m_net_ptr->increment_flit_network_latency(network_delay, vnet);
15611797Smatthew.poremba@amd.com    m_net_ptr->increment_flit_queueing_latency(queueing_delay, vnet);
15711797Smatthew.poremba@amd.com
15811797Smatthew.poremba@amd.com    if (t_flit->get_type() == TAIL_ || t_flit->get_type() == HEAD_TAIL_) {
15911797Smatthew.poremba@amd.com        m_net_ptr->increment_received_packets(vnet);
16011797Smatthew.poremba@amd.com        m_net_ptr->increment_packet_network_latency(network_delay, vnet);
16111797Smatthew.poremba@amd.com        m_net_ptr->increment_packet_queueing_latency(queueing_delay, vnet);
16211797Smatthew.poremba@amd.com    }
16311797Smatthew.poremba@amd.com
16411797Smatthew.poremba@amd.com    // Hops
16511797Smatthew.poremba@amd.com    m_net_ptr->increment_total_hops(t_flit->get_route().hops_traversed);
16611797Smatthew.poremba@amd.com}
16711666Stushar@ece.gatech.edu
16811666Stushar@ece.gatech.edu/*
16911666Stushar@ece.gatech.edu * The NI wakeup checks whether there are any ready messages in the protocol
17011666Stushar@ece.gatech.edu * buffer. If yes, it picks that up, flitisizes it into a number of flits and
17111666Stushar@ece.gatech.edu * puts it into an output buffer and schedules the output link. On a wakeup
17211666Stushar@ece.gatech.edu * it also checks whether there are flits in the input link. If yes, it picks
17311666Stushar@ece.gatech.edu * them up and if the flit is a tail, the NI inserts the corresponding message
17411666Stushar@ece.gatech.edu * into the protocol buffer. It also checks for credits being sent by the
17511666Stushar@ece.gatech.edu * downstream router.
17611666Stushar@ece.gatech.edu */
17711666Stushar@ece.gatech.edu
17811666Stushar@ece.gatech.eduvoid
17911666Stushar@ece.gatech.eduNetworkInterface::wakeup()
18011666Stushar@ece.gatech.edu{
18111666Stushar@ece.gatech.edu    DPRINTF(RubyNetwork, "Network Interface %d connected to router %d "
18211666Stushar@ece.gatech.edu            "woke up at time: %lld\n", m_id, m_router_id, curCycle());
18311666Stushar@ece.gatech.edu
18411666Stushar@ece.gatech.edu    MsgPtr msg_ptr;
18511666Stushar@ece.gatech.edu    Tick curTime = clockEdge();
18611666Stushar@ece.gatech.edu
18711666Stushar@ece.gatech.edu    // Checking for messages coming from the protocol
18811666Stushar@ece.gatech.edu    // can pick up a message/cycle for each virtual net
18911666Stushar@ece.gatech.edu    for (int vnet = 0; vnet < inNode_ptr.size(); ++vnet) {
19011666Stushar@ece.gatech.edu        MessageBuffer *b = inNode_ptr[vnet];
19111666Stushar@ece.gatech.edu        if (b == nullptr) {
19211666Stushar@ece.gatech.edu            continue;
19311666Stushar@ece.gatech.edu        }
19411666Stushar@ece.gatech.edu
19511666Stushar@ece.gatech.edu        if (b->isReady(curTime)) { // Is there a message waiting
19611666Stushar@ece.gatech.edu            msg_ptr = b->peekMsgPtr();
19711666Stushar@ece.gatech.edu            if (flitisizeMessage(msg_ptr, vnet)) {
19811666Stushar@ece.gatech.edu                b->dequeue(curTime);
19911666Stushar@ece.gatech.edu            }
20011666Stushar@ece.gatech.edu        }
20111666Stushar@ece.gatech.edu    }
20211666Stushar@ece.gatech.edu
20311666Stushar@ece.gatech.edu    scheduleOutputLink();
20411666Stushar@ece.gatech.edu    checkReschedule();
20511666Stushar@ece.gatech.edu
20611797Smatthew.poremba@amd.com    // Check if there are flits stalling a virtual channel. Track if a
20711797Smatthew.poremba@amd.com    // message is enqueued to restrict ejection to one message per cycle.
20811797Smatthew.poremba@amd.com    bool messageEnqueuedThisCycle = checkStallQueue();
20911797Smatthew.poremba@amd.com
21011666Stushar@ece.gatech.edu    /*********** Check the incoming flit link **********/
21111666Stushar@ece.gatech.edu    if (inNetLink->isReady(curCycle())) {
21211666Stushar@ece.gatech.edu        flit *t_flit = inNetLink->consumeLink();
21311797Smatthew.poremba@amd.com        int vnet = t_flit->get_vnet();
21411797Smatthew.poremba@amd.com        t_flit->set_dequeue_time(curCycle());
21511797Smatthew.poremba@amd.com
21611797Smatthew.poremba@amd.com        // If a tail flit is received, enqueue into the protocol buffers if
21711797Smatthew.poremba@amd.com        // space is available. Otherwise, exchange non-tail flits for credits.
21811666Stushar@ece.gatech.edu        if (t_flit->get_type() == TAIL_ || t_flit->get_type() == HEAD_TAIL_) {
21911797Smatthew.poremba@amd.com            if (!messageEnqueuedThisCycle &&
22011797Smatthew.poremba@amd.com                outNode_ptr[vnet]->areNSlotsAvailable(1, curTime)) {
22111797Smatthew.poremba@amd.com                // Space is available. Enqueue to protocol buffer.
22211797Smatthew.poremba@amd.com                outNode_ptr[vnet]->enqueue(t_flit->get_msg_ptr(), curTime,
22311797Smatthew.poremba@amd.com                                           cyclesToTicks(Cycles(1)));
22411666Stushar@ece.gatech.edu
22511797Smatthew.poremba@amd.com                // Simply send a credit back since we are not buffering
22611797Smatthew.poremba@amd.com                // this flit in the NI
22711797Smatthew.poremba@amd.com                sendCredit(t_flit, true);
22811797Smatthew.poremba@amd.com
22911797Smatthew.poremba@amd.com                // Update stats and delete flit pointer
23011797Smatthew.poremba@amd.com                incrementStats(t_flit);
23111797Smatthew.poremba@amd.com                delete t_flit;
23211797Smatthew.poremba@amd.com            } else {
23311797Smatthew.poremba@amd.com                // No space available- Place tail flit in stall queue and set
23411797Smatthew.poremba@amd.com                // up a callback for when protocol buffer is dequeued. Stat
23511797Smatthew.poremba@amd.com                // update and flit pointer deletion will occur upon unstall.
23611797Smatthew.poremba@amd.com                m_stall_queue.push_back(t_flit);
23711797Smatthew.poremba@amd.com                m_stall_count[vnet]++;
23811797Smatthew.poremba@amd.com
23911797Smatthew.poremba@amd.com                auto cb = std::bind(&NetworkInterface::dequeueCallback, this);
24011797Smatthew.poremba@amd.com                outNode_ptr[vnet]->registerDequeueCallback(cb);
24111797Smatthew.poremba@amd.com            }
24211797Smatthew.poremba@amd.com        } else {
24311797Smatthew.poremba@amd.com            // Non-tail flit. Send back a credit but not VC free signal.
24411797Smatthew.poremba@amd.com            sendCredit(t_flit, false);
24511797Smatthew.poremba@amd.com
24611797Smatthew.poremba@amd.com            // Update stats and delete flit pointer.
24711797Smatthew.poremba@amd.com            incrementStats(t_flit);
24811797Smatthew.poremba@amd.com            delete t_flit;
24911666Stushar@ece.gatech.edu        }
25011666Stushar@ece.gatech.edu    }
25111666Stushar@ece.gatech.edu
25211666Stushar@ece.gatech.edu    /****************** Check the incoming credit link *******/
25311666Stushar@ece.gatech.edu
25411666Stushar@ece.gatech.edu    if (inCreditLink->isReady(curCycle())) {
25511666Stushar@ece.gatech.edu        Credit *t_credit = (Credit*) inCreditLink->consumeLink();
25611666Stushar@ece.gatech.edu        m_out_vc_state[t_credit->get_vc()]->increment_credit();
25711666Stushar@ece.gatech.edu        if (t_credit->is_free_signal()) {
25811666Stushar@ece.gatech.edu            m_out_vc_state[t_credit->get_vc()]->setState(IDLE_, curCycle());
25911666Stushar@ece.gatech.edu        }
26011666Stushar@ece.gatech.edu        delete t_credit;
26111666Stushar@ece.gatech.edu    }
26211797Smatthew.poremba@amd.com
26311797Smatthew.poremba@amd.com
26411797Smatthew.poremba@amd.com    // It is possible to enqueue multiple outgoing credit flits if a message
26511797Smatthew.poremba@amd.com    // was unstalled in the same cycle as a new message arrives. In this
26611797Smatthew.poremba@amd.com    // case, we should schedule another wakeup to ensure the credit is sent
26711797Smatthew.poremba@amd.com    // back.
26811797Smatthew.poremba@amd.com    if (outCreditQueue->getSize() > 0) {
26911797Smatthew.poremba@amd.com        outCreditLink->scheduleEventAbsolute(clockEdge(Cycles(1)));
27011797Smatthew.poremba@amd.com    }
27111666Stushar@ece.gatech.edu}
27211666Stushar@ece.gatech.edu
27311797Smatthew.poremba@amd.comvoid
27411797Smatthew.poremba@amd.comNetworkInterface::sendCredit(flit *t_flit, bool is_free)
27511797Smatthew.poremba@amd.com{
27611797Smatthew.poremba@amd.com    Credit *credit_flit = new Credit(t_flit->get_vc(), is_free, curCycle());
27711797Smatthew.poremba@amd.com    outCreditQueue->insert(credit_flit);
27811797Smatthew.poremba@amd.com}
27911797Smatthew.poremba@amd.com
28011797Smatthew.poremba@amd.combool
28111797Smatthew.poremba@amd.comNetworkInterface::checkStallQueue()
28211797Smatthew.poremba@amd.com{
28311797Smatthew.poremba@amd.com    bool messageEnqueuedThisCycle = false;
28411797Smatthew.poremba@amd.com    Tick curTime = clockEdge();
28511797Smatthew.poremba@amd.com
28611797Smatthew.poremba@amd.com    if (!m_stall_queue.empty()) {
28711797Smatthew.poremba@amd.com        for (auto stallIter = m_stall_queue.begin();
28811797Smatthew.poremba@amd.com             stallIter != m_stall_queue.end(); ) {
28911797Smatthew.poremba@amd.com            flit *stallFlit = *stallIter;
29011797Smatthew.poremba@amd.com            int vnet = stallFlit->get_vnet();
29111797Smatthew.poremba@amd.com
29211797Smatthew.poremba@amd.com            // If we can now eject to the protocol buffer, send back credits
29311797Smatthew.poremba@amd.com            if (outNode_ptr[vnet]->areNSlotsAvailable(1, curTime)) {
29411797Smatthew.poremba@amd.com                outNode_ptr[vnet]->enqueue(stallFlit->get_msg_ptr(), curTime,
29511797Smatthew.poremba@amd.com                                           cyclesToTicks(Cycles(1)));
29611797Smatthew.poremba@amd.com
29711797Smatthew.poremba@amd.com                // Send back a credit with free signal now that the VC is no
29811797Smatthew.poremba@amd.com                // longer stalled.
29911797Smatthew.poremba@amd.com                sendCredit(stallFlit, true);
30011797Smatthew.poremba@amd.com
30111797Smatthew.poremba@amd.com                // Update Stats
30211797Smatthew.poremba@amd.com                incrementStats(stallFlit);
30311797Smatthew.poremba@amd.com
30411797Smatthew.poremba@amd.com                // Flit can now safely be deleted and removed from stall queue
30511797Smatthew.poremba@amd.com                delete stallFlit;
30611797Smatthew.poremba@amd.com                m_stall_queue.erase(stallIter);
30711797Smatthew.poremba@amd.com                m_stall_count[vnet]--;
30811797Smatthew.poremba@amd.com
30911797Smatthew.poremba@amd.com                // If there are no more stalled messages for this vnet, the
31011797Smatthew.poremba@amd.com                // callback on it's MessageBuffer is not needed.
31111797Smatthew.poremba@amd.com                if (m_stall_count[vnet] == 0)
31211797Smatthew.poremba@amd.com                    outNode_ptr[vnet]->unregisterDequeueCallback();
31311797Smatthew.poremba@amd.com
31411797Smatthew.poremba@amd.com                messageEnqueuedThisCycle = true;
31511797Smatthew.poremba@amd.com                break;
31611797Smatthew.poremba@amd.com            } else {
31711797Smatthew.poremba@amd.com                ++stallIter;
31811797Smatthew.poremba@amd.com            }
31911797Smatthew.poremba@amd.com        }
32011797Smatthew.poremba@amd.com    }
32111797Smatthew.poremba@amd.com
32211797Smatthew.poremba@amd.com    return messageEnqueuedThisCycle;
32311797Smatthew.poremba@amd.com}
32411666Stushar@ece.gatech.edu
32511666Stushar@ece.gatech.edu// Embed the protocol message into flits
32611666Stushar@ece.gatech.edubool
32711666Stushar@ece.gatech.eduNetworkInterface::flitisizeMessage(MsgPtr msg_ptr, int vnet)
32811666Stushar@ece.gatech.edu{
32911666Stushar@ece.gatech.edu    Message *net_msg_ptr = msg_ptr.get();
33011666Stushar@ece.gatech.edu    NetDest net_msg_dest = net_msg_ptr->getDestination();
33111666Stushar@ece.gatech.edu
33211666Stushar@ece.gatech.edu    // gets all the destinations associated with this message.
33311666Stushar@ece.gatech.edu    vector<NodeID> dest_nodes = net_msg_dest.getAllDest();
33411666Stushar@ece.gatech.edu
33511666Stushar@ece.gatech.edu    // Number of flits is dependent on the link bandwidth available.
33611666Stushar@ece.gatech.edu    // This is expressed in terms of bytes/cycle or the flit size
33711666Stushar@ece.gatech.edu    int num_flits = (int) ceil((double) m_net_ptr->MessageSizeType_to_int(
33811666Stushar@ece.gatech.edu        net_msg_ptr->getMessageSize())/m_net_ptr->getNiFlitSize());
33911666Stushar@ece.gatech.edu
34011666Stushar@ece.gatech.edu    // loop to convert all multicast messages into unicast messages
34111666Stushar@ece.gatech.edu    for (int ctr = 0; ctr < dest_nodes.size(); ctr++) {
34211666Stushar@ece.gatech.edu
34311666Stushar@ece.gatech.edu        // this will return a free output virtual channel
34411666Stushar@ece.gatech.edu        int vc = calculateVC(vnet);
34511666Stushar@ece.gatech.edu
34611666Stushar@ece.gatech.edu        if (vc == -1) {
34711666Stushar@ece.gatech.edu            return false ;
34811666Stushar@ece.gatech.edu        }
34911666Stushar@ece.gatech.edu        MsgPtr new_msg_ptr = msg_ptr->clone();
35011666Stushar@ece.gatech.edu        NodeID destID = dest_nodes[ctr];
35111666Stushar@ece.gatech.edu
35211666Stushar@ece.gatech.edu        Message *new_net_msg_ptr = new_msg_ptr.get();
35311666Stushar@ece.gatech.edu        if (dest_nodes.size() > 1) {
35411666Stushar@ece.gatech.edu            NetDest personal_dest;
35511666Stushar@ece.gatech.edu            for (int m = 0; m < (int) MachineType_NUM; m++) {
35611666Stushar@ece.gatech.edu                if ((destID >= MachineType_base_number((MachineType) m)) &&
35711666Stushar@ece.gatech.edu                    destID < MachineType_base_number((MachineType) (m+1))) {
35811666Stushar@ece.gatech.edu                    // calculating the NetDest associated with this destID
35911666Stushar@ece.gatech.edu                    personal_dest.clear();
36011666Stushar@ece.gatech.edu                    personal_dest.add((MachineID) {(MachineType) m, (destID -
36111666Stushar@ece.gatech.edu                        MachineType_base_number((MachineType) m))});
36211666Stushar@ece.gatech.edu                    new_net_msg_ptr->getDestination() = personal_dest;
36311666Stushar@ece.gatech.edu                    break;
36411666Stushar@ece.gatech.edu                }
36511666Stushar@ece.gatech.edu            }
36611666Stushar@ece.gatech.edu            net_msg_dest.removeNetDest(personal_dest);
36711666Stushar@ece.gatech.edu            // removing the destination from the original message to reflect
36811666Stushar@ece.gatech.edu            // that a message with this particular destination has been
36911666Stushar@ece.gatech.edu            // flitisized and an output vc is acquired
37011666Stushar@ece.gatech.edu            net_msg_ptr->getDestination().removeNetDest(personal_dest);
37111666Stushar@ece.gatech.edu        }
37211666Stushar@ece.gatech.edu
37311666Stushar@ece.gatech.edu        // Embed Route into the flits
37411666Stushar@ece.gatech.edu        // NetDest format is used by the routing table
37511666Stushar@ece.gatech.edu        // Custom routing algorithms just need destID
37611666Stushar@ece.gatech.edu        RouteInfo route;
37711666Stushar@ece.gatech.edu        route.vnet = vnet;
37811666Stushar@ece.gatech.edu        route.net_dest = new_net_msg_ptr->getDestination();
37911666Stushar@ece.gatech.edu        route.src_ni = m_id;
38011666Stushar@ece.gatech.edu        route.src_router = m_router_id;
38111666Stushar@ece.gatech.edu        route.dest_ni = destID;
38211666Stushar@ece.gatech.edu        route.dest_router = m_net_ptr->get_router_id(destID);
38311666Stushar@ece.gatech.edu
38411666Stushar@ece.gatech.edu        // initialize hops_traversed to -1
38511666Stushar@ece.gatech.edu        // so that the first router increments it to 0
38611666Stushar@ece.gatech.edu        route.hops_traversed = -1;
38711666Stushar@ece.gatech.edu
38811666Stushar@ece.gatech.edu        m_net_ptr->increment_injected_packets(vnet);
38911666Stushar@ece.gatech.edu        for (int i = 0; i < num_flits; i++) {
39011666Stushar@ece.gatech.edu            m_net_ptr->increment_injected_flits(vnet);
39111666Stushar@ece.gatech.edu            flit *fl = new flit(i, vc, vnet, route, num_flits, new_msg_ptr,
39211666Stushar@ece.gatech.edu                curCycle());
39311666Stushar@ece.gatech.edu
39411666Stushar@ece.gatech.edu            fl->set_src_delay(curCycle() - ticksToCycles(msg_ptr->getTime()));
39511666Stushar@ece.gatech.edu            m_ni_out_vcs[vc]->insert(fl);
39611666Stushar@ece.gatech.edu        }
39711666Stushar@ece.gatech.edu
39811666Stushar@ece.gatech.edu        m_ni_out_vcs_enqueue_time[vc] = curCycle();
39911666Stushar@ece.gatech.edu        m_out_vc_state[vc]->setState(ACTIVE_, curCycle());
40011666Stushar@ece.gatech.edu    }
40111666Stushar@ece.gatech.edu    return true ;
40211666Stushar@ece.gatech.edu}
40311666Stushar@ece.gatech.edu
40411666Stushar@ece.gatech.edu// Looking for a free output vc
40511666Stushar@ece.gatech.eduint
40611666Stushar@ece.gatech.eduNetworkInterface::calculateVC(int vnet)
40711666Stushar@ece.gatech.edu{
40811666Stushar@ece.gatech.edu    for (int i = 0; i < m_vc_per_vnet; i++) {
40911666Stushar@ece.gatech.edu        int delta = m_vc_allocator[vnet];
41011666Stushar@ece.gatech.edu        m_vc_allocator[vnet]++;
41111666Stushar@ece.gatech.edu        if (m_vc_allocator[vnet] == m_vc_per_vnet)
41211666Stushar@ece.gatech.edu            m_vc_allocator[vnet] = 0;
41311666Stushar@ece.gatech.edu
41411666Stushar@ece.gatech.edu        if (m_out_vc_state[(vnet*m_vc_per_vnet) + delta]->isInState(
41511666Stushar@ece.gatech.edu                    IDLE_, curCycle())) {
41611762Sjieming.yin@amd.com            vc_busy_counter[vnet] = 0;
41711666Stushar@ece.gatech.edu            return ((vnet*m_vc_per_vnet) + delta);
41811666Stushar@ece.gatech.edu        }
41911666Stushar@ece.gatech.edu    }
42011762Sjieming.yin@amd.com
42111762Sjieming.yin@amd.com    vc_busy_counter[vnet] += 1;
42211762Sjieming.yin@amd.com    panic_if(vc_busy_counter[vnet] > m_deadlock_threshold,
42311762Sjieming.yin@amd.com        "%s: Possible network deadlock in vnet: %d at time: %llu \n",
42411762Sjieming.yin@amd.com        name(), vnet, curTick());
42511762Sjieming.yin@amd.com
42611666Stushar@ece.gatech.edu    return -1;
42711666Stushar@ece.gatech.edu}
42811666Stushar@ece.gatech.edu
42911666Stushar@ece.gatech.edu
43011666Stushar@ece.gatech.edu/** This function looks at the NI buffers
43111666Stushar@ece.gatech.edu *  if some buffer has flits which are ready to traverse the link in the next
43211666Stushar@ece.gatech.edu *  cycle, and the downstream output vc associated with this flit has buffers
43311666Stushar@ece.gatech.edu *  left, the link is scheduled for the next cycle
43411666Stushar@ece.gatech.edu */
43511666Stushar@ece.gatech.edu
43611666Stushar@ece.gatech.eduvoid
43711666Stushar@ece.gatech.eduNetworkInterface::scheduleOutputLink()
43811666Stushar@ece.gatech.edu{
43911666Stushar@ece.gatech.edu    int vc = m_vc_round_robin;
44011666Stushar@ece.gatech.edu
44111666Stushar@ece.gatech.edu    for (int i = 0; i < m_num_vcs; i++) {
44211666Stushar@ece.gatech.edu        vc++;
44311666Stushar@ece.gatech.edu        if (vc == m_num_vcs)
44411666Stushar@ece.gatech.edu            vc = 0;
44511666Stushar@ece.gatech.edu
44611666Stushar@ece.gatech.edu        // model buffer backpressure
44711666Stushar@ece.gatech.edu        if (m_ni_out_vcs[vc]->isReady(curCycle()) &&
44811666Stushar@ece.gatech.edu            m_out_vc_state[vc]->has_credit()) {
44911666Stushar@ece.gatech.edu
45011666Stushar@ece.gatech.edu            bool is_candidate_vc = true;
45111666Stushar@ece.gatech.edu            int t_vnet = get_vnet(vc);
45211666Stushar@ece.gatech.edu            int vc_base = t_vnet * m_vc_per_vnet;
45311666Stushar@ece.gatech.edu
45411666Stushar@ece.gatech.edu            if (m_net_ptr->isVNetOrdered(t_vnet)) {
45511666Stushar@ece.gatech.edu                for (int vc_offset = 0; vc_offset < m_vc_per_vnet;
45611666Stushar@ece.gatech.edu                     vc_offset++) {
45711666Stushar@ece.gatech.edu                    int t_vc = vc_base + vc_offset;
45811666Stushar@ece.gatech.edu                    if (m_ni_out_vcs[t_vc]->isReady(curCycle())) {
45911666Stushar@ece.gatech.edu                        if (m_ni_out_vcs_enqueue_time[t_vc] <
46011666Stushar@ece.gatech.edu                            m_ni_out_vcs_enqueue_time[vc]) {
46111666Stushar@ece.gatech.edu                            is_candidate_vc = false;
46211666Stushar@ece.gatech.edu                            break;
46311666Stushar@ece.gatech.edu                        }
46411666Stushar@ece.gatech.edu                    }
46511666Stushar@ece.gatech.edu                }
46611666Stushar@ece.gatech.edu            }
46711666Stushar@ece.gatech.edu            if (!is_candidate_vc)
46811666Stushar@ece.gatech.edu                continue;
46911666Stushar@ece.gatech.edu
47013736Ssrikant.bharadwaj@amd.com            m_vc_round_robin = vc;
47113736Ssrikant.bharadwaj@amd.com
47211666Stushar@ece.gatech.edu            m_out_vc_state[vc]->decrement_credit();
47311666Stushar@ece.gatech.edu            // Just removing the flit
47411666Stushar@ece.gatech.edu            flit *t_flit = m_ni_out_vcs[vc]->getTopFlit();
47511666Stushar@ece.gatech.edu            t_flit->set_time(curCycle() + Cycles(1));
47611666Stushar@ece.gatech.edu            outFlitQueue->insert(t_flit);
47711666Stushar@ece.gatech.edu            // schedule the out link
47811666Stushar@ece.gatech.edu            outNetLink->scheduleEventAbsolute(clockEdge(Cycles(1)));
47911666Stushar@ece.gatech.edu
48011666Stushar@ece.gatech.edu            if (t_flit->get_type() == TAIL_ ||
48111666Stushar@ece.gatech.edu               t_flit->get_type() == HEAD_TAIL_) {
48211666Stushar@ece.gatech.edu                m_ni_out_vcs_enqueue_time[vc] = Cycles(INFINITE_);
48311666Stushar@ece.gatech.edu            }
48411666Stushar@ece.gatech.edu            return;
48511666Stushar@ece.gatech.edu        }
48611666Stushar@ece.gatech.edu    }
48711666Stushar@ece.gatech.edu}
48811666Stushar@ece.gatech.edu
48911666Stushar@ece.gatech.eduint
49011666Stushar@ece.gatech.eduNetworkInterface::get_vnet(int vc)
49111666Stushar@ece.gatech.edu{
49211666Stushar@ece.gatech.edu    for (int i = 0; i < m_virtual_networks; i++) {
49311666Stushar@ece.gatech.edu        if (vc >= (i*m_vc_per_vnet) && vc < ((i+1)*m_vc_per_vnet)) {
49411666Stushar@ece.gatech.edu            return i;
49511666Stushar@ece.gatech.edu        }
49611666Stushar@ece.gatech.edu    }
49711666Stushar@ece.gatech.edu    fatal("Could not determine vc");
49811666Stushar@ece.gatech.edu}
49911666Stushar@ece.gatech.edu
50011666Stushar@ece.gatech.edu
50111666Stushar@ece.gatech.edu// Wakeup the NI in the next cycle if there are waiting
50211666Stushar@ece.gatech.edu// messages in the protocol buffer, or waiting flits in the
50311666Stushar@ece.gatech.edu// output VC buffer
50411666Stushar@ece.gatech.eduvoid
50511666Stushar@ece.gatech.eduNetworkInterface::checkReschedule()
50611666Stushar@ece.gatech.edu{
50711666Stushar@ece.gatech.edu    for (const auto& it : inNode_ptr) {
50811666Stushar@ece.gatech.edu        if (it == nullptr) {
50911666Stushar@ece.gatech.edu            continue;
51011666Stushar@ece.gatech.edu        }
51111666Stushar@ece.gatech.edu
51211666Stushar@ece.gatech.edu        while (it->isReady(clockEdge())) { // Is there a message waiting
51311666Stushar@ece.gatech.edu            scheduleEvent(Cycles(1));
51411666Stushar@ece.gatech.edu            return;
51511666Stushar@ece.gatech.edu        }
51611666Stushar@ece.gatech.edu    }
51711666Stushar@ece.gatech.edu
51811666Stushar@ece.gatech.edu    for (int vc = 0; vc < m_num_vcs; vc++) {
51911666Stushar@ece.gatech.edu        if (m_ni_out_vcs[vc]->isReady(curCycle() + Cycles(1))) {
52011666Stushar@ece.gatech.edu            scheduleEvent(Cycles(1));
52111666Stushar@ece.gatech.edu            return;
52211666Stushar@ece.gatech.edu        }
52311666Stushar@ece.gatech.edu    }
52411666Stushar@ece.gatech.edu}
52511666Stushar@ece.gatech.edu
52611666Stushar@ece.gatech.eduvoid
52711666Stushar@ece.gatech.eduNetworkInterface::print(std::ostream& out) const
52811666Stushar@ece.gatech.edu{
52911666Stushar@ece.gatech.edu    out << "[Network Interface]";
53011666Stushar@ece.gatech.edu}
53111666Stushar@ece.gatech.edu
53211666Stushar@ece.gatech.eduuint32_t
53311666Stushar@ece.gatech.eduNetworkInterface::functionalWrite(Packet *pkt)
53411666Stushar@ece.gatech.edu{
53511666Stushar@ece.gatech.edu    uint32_t num_functional_writes = 0;
53611666Stushar@ece.gatech.edu    for (unsigned int i  = 0; i < m_num_vcs; ++i) {
53711666Stushar@ece.gatech.edu        num_functional_writes += m_ni_out_vcs[i]->functionalWrite(pkt);
53811666Stushar@ece.gatech.edu    }
53911666Stushar@ece.gatech.edu
54011666Stushar@ece.gatech.edu    num_functional_writes += outFlitQueue->functionalWrite(pkt);
54111666Stushar@ece.gatech.edu    return num_functional_writes;
54211666Stushar@ece.gatech.edu}
54311666Stushar@ece.gatech.edu
54411666Stushar@ece.gatech.eduNetworkInterface *
54511666Stushar@ece.gatech.eduGarnetNetworkInterfaceParams::create()
54611666Stushar@ece.gatech.edu{
54711666Stushar@ece.gatech.edu    return new NetworkInterface(this);
54811666Stushar@ece.gatech.edu}
549