f6b828d068
Result of running 'hg m5style --skip-all --fix-control -a' to get rid of '== true' comparisons, plus trivial manual edits to get rid of '== false'/'== False' comparisons. Left a couple of explicit comparisons in where they didn't seem unreasonable: invalid boolean comparison in src/arch/mips/interrupts.cc:155 >> DPRINTF(Interrupt, "Interrupts OnCpuTimerINterrupt(tc) == true\n");<< invalid boolean comparison in src/unittest/unittest.hh:110 >> "EXPECT_FALSE(" #expr ")", (expr) == false)<<
242 lines
8.4 KiB
C++
242 lines
8.4 KiB
C++
/*
|
|
* Copyright (c) 2008 Princeton University
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met: redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer;
|
|
* redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution;
|
|
* neither the name of the copyright holders nor the names of its
|
|
* contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* Authors: Niket Agarwal
|
|
*/
|
|
|
|
#include "mem/ruby/network/garnet/fixed-pipeline/GarnetNetwork_d.hh"
|
|
#include "mem/ruby/network/garnet/fixed-pipeline/InputUnit_d.hh"
|
|
#include "mem/ruby/network/garnet/fixed-pipeline/OutputUnit_d.hh"
|
|
#include "mem/ruby/network/garnet/fixed-pipeline/Router_d.hh"
|
|
#include "mem/ruby/network/garnet/fixed-pipeline/SWallocator_d.hh"
|
|
|
|
SWallocator_d::SWallocator_d(Router_d *router)
|
|
: Consumer(router)
|
|
{
|
|
m_router = router;
|
|
m_num_vcs = m_router->get_num_vcs();
|
|
m_vc_per_vnet = m_router->get_vc_per_vnet();
|
|
|
|
m_local_arbiter_activity = 0;
|
|
m_global_arbiter_activity = 0;
|
|
}
|
|
|
|
void
|
|
SWallocator_d::init()
|
|
{
|
|
m_input_unit = m_router->get_inputUnit_ref();
|
|
m_output_unit = m_router->get_outputUnit_ref();
|
|
|
|
m_num_inports = m_router->get_num_inports();
|
|
m_num_outports = m_router->get_num_outports();
|
|
m_round_robin_outport.resize(m_num_outports);
|
|
m_round_robin_inport.resize(m_num_inports);
|
|
m_port_req.resize(m_num_outports);
|
|
m_vc_winners.resize(m_num_outports);
|
|
|
|
for (int i = 0; i < m_num_inports; i++) {
|
|
m_round_robin_inport[i] = 0;
|
|
}
|
|
|
|
for (int i = 0; i < m_num_outports; i++) {
|
|
m_port_req[i].resize(m_num_inports);
|
|
m_vc_winners[i].resize(m_num_inports);
|
|
|
|
m_round_robin_outport[i] = 0;
|
|
|
|
for (int j = 0; j < m_num_inports; j++) {
|
|
m_port_req[i][j] = false; // [outport][inport]
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
SWallocator_d::wakeup()
|
|
{
|
|
arbitrate_inports(); // First stage of allocation
|
|
arbitrate_outports(); // Second stage of allocation
|
|
|
|
clear_request_vector();
|
|
check_for_wakeup();
|
|
m_router->call_switch();
|
|
|
|
}
|
|
|
|
void
|
|
SWallocator_d::arbitrate_inports()
|
|
{
|
|
// First do round robin arbitration on a set of input vc requests
|
|
for (int inport = 0; inport < m_num_inports; inport++) {
|
|
int invc = m_round_robin_inport[inport];
|
|
|
|
// Select next round robin vc candidate within valid vnet
|
|
int next_round_robin_invc = invc;
|
|
next_round_robin_invc++;
|
|
if (next_round_robin_invc >= m_num_vcs)
|
|
next_round_robin_invc = 0;
|
|
m_round_robin_inport[inport] = next_round_robin_invc;
|
|
|
|
for (int invc_iter = 0; invc_iter < m_num_vcs; invc_iter++) {
|
|
invc++;
|
|
if (invc >= m_num_vcs)
|
|
invc = 0;
|
|
|
|
if (m_input_unit[inport]->need_stage(invc, ACTIVE_, SA_,
|
|
m_router->curCycle()) &&
|
|
m_input_unit[inport]->has_credits(invc)) {
|
|
|
|
if (is_candidate_inport(inport, invc)) {
|
|
int outport = m_input_unit[inport]->get_route(invc);
|
|
m_local_arbiter_activity++;
|
|
m_port_req[outport][inport] = true;
|
|
m_vc_winners[outport][inport]= invc;
|
|
break; // got one vc winner for this port
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool
|
|
SWallocator_d::is_candidate_inport(int inport, int invc)
|
|
{
|
|
int outport = m_input_unit[inport]->get_route(invc);
|
|
Cycles t_enqueue_time = m_input_unit[inport]->get_enqueue_time(invc);
|
|
int t_vnet = get_vnet(invc);
|
|
int vc_base = t_vnet*m_vc_per_vnet;
|
|
if ((m_router->get_net_ptr())->isVNetOrdered(t_vnet)) {
|
|
for (int vc_offset = 0; vc_offset < m_vc_per_vnet; vc_offset++) {
|
|
int temp_vc = vc_base + vc_offset;
|
|
if (m_input_unit[inport]->need_stage(temp_vc, ACTIVE_, SA_,
|
|
m_router->curCycle()) &&
|
|
(m_input_unit[inport]->get_route(temp_vc) == outport) &&
|
|
(m_input_unit[inport]->get_enqueue_time(temp_vc) <
|
|
t_enqueue_time)) {
|
|
return false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
void
|
|
SWallocator_d::arbitrate_outports()
|
|
{
|
|
// Now there are a set of input vc requests for output vcs.
|
|
// Again do round robin arbitration on these requests
|
|
for (int outport = 0; outport < m_num_outports; outport++) {
|
|
int inport = m_round_robin_outport[outport];
|
|
m_round_robin_outport[outport]++;
|
|
|
|
if (m_round_robin_outport[outport] >= m_num_outports)
|
|
m_round_robin_outport[outport] = 0;
|
|
|
|
for (int inport_iter = 0; inport_iter < m_num_inports; inport_iter++) {
|
|
inport++;
|
|
if (inport >= m_num_inports)
|
|
inport = 0;
|
|
|
|
// inport has a request this cycle for outport:
|
|
if (m_port_req[outport][inport]) {
|
|
m_port_req[outport][inport] = false;
|
|
int invc = m_vc_winners[outport][inport];
|
|
int outvc = m_input_unit[inport]->get_outvc(invc);
|
|
|
|
// remove flit from Input Unit
|
|
flit_d *t_flit = m_input_unit[inport]->getTopFlit(invc);
|
|
t_flit->advance_stage(ST_, m_router->curCycle());
|
|
t_flit->set_vc(outvc);
|
|
t_flit->set_outport(outport);
|
|
t_flit->set_time(m_router->curCycle());
|
|
|
|
m_output_unit[outport]->decrement_credit(outvc);
|
|
m_router->update_sw_winner(inport, t_flit);
|
|
m_global_arbiter_activity++;
|
|
|
|
if ((t_flit->get_type() == TAIL_) ||
|
|
t_flit->get_type() == HEAD_TAIL_) {
|
|
|
|
// Send a credit back
|
|
// along with the information that this VC is now idle
|
|
m_input_unit[inport]->increment_credit(invc, true,
|
|
m_router->curCycle());
|
|
|
|
// This Input VC should now be empty
|
|
assert(!m_input_unit[inport]->
|
|
isReady(invc, m_router->curCycle()));
|
|
|
|
m_input_unit[inport]->set_vc_state(IDLE_, invc,
|
|
m_router->curCycle());
|
|
m_input_unit[inport]->set_enqueue_time(invc,
|
|
Cycles(INFINITE_));
|
|
} else {
|
|
// Send a credit back
|
|
// but do not indicate that the VC is idle
|
|
m_input_unit[inport]->increment_credit(invc, false,
|
|
m_router->curCycle());
|
|
}
|
|
break; // got a in request for this outport
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
SWallocator_d::check_for_wakeup()
|
|
{
|
|
Cycles nextCycle = m_router->curCycle() + Cycles(1);
|
|
|
|
for (int i = 0; i < m_num_inports; i++) {
|
|
for (int j = 0; j < m_num_vcs; j++) {
|
|
if (m_input_unit[i]->need_stage(j, ACTIVE_, SA_, nextCycle)) {
|
|
m_router->vcarb_req();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
SWallocator_d::get_vnet(int invc)
|
|
{
|
|
int vnet = invc/m_vc_per_vnet;
|
|
assert(vnet < m_router->get_num_vnets());
|
|
return vnet;
|
|
}
|
|
|
|
void
|
|
SWallocator_d::clear_request_vector()
|
|
{
|
|
for (int i = 0; i < m_num_outports; i++) {
|
|
for (int j = 0; j < m_num_inports; j++) {
|
|
m_port_req[i][j] = false;
|
|
}
|
|
}
|
|
}
|