For those who want to simulate
back-pressure effect in Garnet fixed pipeline model for the case when output
link has non-unit serial latency, here is the solution.
The idea is to pause flits at SA stage by
rescheduling them for the later time while the output port is busy with sending
current flit through the slow link. In order to implement this mechanism we
create a new time vector m_output_schedule which holds new scheduling for each
output port. During SA stage we set m_output_schedule of the current output
port to the current time plus output link latency. Thus, we advance flits to ST
stage only when current time is bigger or equal to the schedule in
m_output_schedule[outport]. The exact implementation is presented below.
SWallocator_d.C:
void SWallocator_d::init()
{
…
m_output_schedule.setSize(m_num_outports);
for (int i = 0; i < m_num_outports; i++)
{
m_output_schedule[i] = 0;
}
}
void SWallocator_d::arbitrate_outports()
{
// now I have 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 in_port = 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 = 0; inport < m_num_inports; inport++)
{
in_port++;
if(in_port >= m_num_inports)
in_port = 0;
if(m_port_req[outport][in_port]) // This Inport has a request this cycle for
this port
{
if (g_eventQueue_ptr->getTime() >= m_output_schedule[outport]) //
Checking schedule
{
m_port_req[outport][in_port] = false;
int invc = m_vc_winners[outport][in_port];
int outvc = m_input_unit[in_port]->get_outvc(invc);
flit_d *t_flit = m_input_unit[in_port]->getTopFlit(invc); // removes flit
from Input Unit
t_flit->advance_stage(ST_);
t_flit->set_vc(outvc);
t_flit->set_outport(outport);
t_flit->set_time(g_eventQueue_ptr->getTime() + 1);
m_output_unit[outport]->decrement_credit(outvc);
m_router->update_sw_winner(in_port, t_flit);
m_global_arbiter_activity++;
if((t_flit->get_type() == TAIL_) || t_flit->get_type() == HEAD_TAIL_)
{
m_input_unit[in_port]->increment_credit(invc, true); // Send a credit back
along with the information that this VC is not idle
assert(m_input_unit[in_port]->isReady(invc) == false); // This Input VC
should now be empty
m_input_unit[in_port]->set_vc_state(IDLE_, invc);
m_input_unit[in_port]->set_enqueue_time(invc,
INFINITE_);
}
else
{
m_input_unit[in_port]->increment_credit(invc, false); // Send a credit back
but do not indicate that the VC is idle
}
m_output_schedule[outport] = g_eventQueue_ptr->getTime() +
m_output_unit[outport]->get_outlink_latency(); // Creating schedule for the
outport
}
}
}
}
}
SWallocator_d.h:
…
private:
…
Vector<Time > m_output_schedule;
};
OutputUnit_d.h:
inline int get_outlink_latency()
{
return m_out_link->get_latency();
}
NetworkLink_d.h:
inline int get_latency()
{
return m_latency;
}
Thanks to Niket for the idea.
Kind regards,
Arseniy