2 * Copyright (c) 2008 Princeton University
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * Authors: Niket Agarwal
31 #include "base/cast.hh"
32 #include "base/stl_helpers.hh"
33 #include "debug/RubyNetwork.hh"
34 #include "mem/ruby/network/garnet/flexible-pipeline/InVcState.hh"
35 #include "mem/ruby/network/garnet/flexible-pipeline/OutVcState.hh"
36 #include "mem/ruby/network/garnet/flexible-pipeline/Router.hh"
37 #include "mem/ruby/network/garnet/flexible-pipeline/VCarbiter.hh"
38 #include "mem/ruby/slicc_interface/NetworkMessage.hh"
41 using m5::stl_helpers::deletePointers
;
43 Router::Router(const Params
*p
)
44 : BasicRouter(p
), FlexibleConsumer(this)
47 m_virtual_networks
= p
->virt_nets
;
48 m_vc_per_vnet
= p
->vcs_per_vnet
;
49 m_round_robin_inport
= 0;
50 m_round_robin_start
= 0;
51 m_num_vcs
= m_vc_per_vnet
* m_virtual_networks
;
52 m_vc_arbiter
= new VCarbiter(this);
57 for (int i
= 0; i
< m_in_link
.size(); i
++) {
58 deletePointers(m_in_vc_state
[i
]);
60 for (int i
= 0; i
< m_out_link
.size(); i
++) {
61 deletePointers(m_out_vc_state
[i
]);
62 deletePointers(m_router_buffers
[i
]);
64 deletePointers(m_out_src_queue
);
69 Router::addInPort(NetworkLink
*in_link
)
71 int port
= m_in_link
.size();
72 vector
<InVcState
*> in_vc_vector
;
73 for (int i
= 0; i
< m_num_vcs
; i
++) {
74 in_vc_vector
.push_back(new InVcState(i
));
75 in_vc_vector
[i
]->setState(IDLE_
, g_system_ptr
->getTime());
77 m_in_vc_state
.push_back(in_vc_vector
);
78 m_in_link
.push_back(in_link
);
79 in_link
->setLinkConsumer(this);
80 in_link
->setInPort(port
);
83 m_round_robin_invc
.push_back(start
);
87 Router::addOutPort(NetworkLink
*out_link
, const NetDest
& routing_table_entry
,
90 int port
= m_out_link
.size();
91 out_link
->setOutPort(port
);
93 m_vc_round_robin
.push_back(start
);
95 m_out_src_queue
.push_back(new flitBuffer());
97 m_out_link
.push_back(out_link
);
98 m_routing_table
.push_back(routing_table_entry
);
99 out_link
->setSourceQueue(m_out_src_queue
[port
]);
100 out_link
->setSource(this);
102 vector
<flitBuffer
*> intermediateQueues
;
103 for (int i
= 0; i
< m_num_vcs
; i
++) {
104 int buffer_size
= m_net_ptr
->getBufferSize();
105 if (buffer_size
> 0) // finite size
106 intermediateQueues
.push_back(new flitBuffer(buffer_size
));
107 else // infinite size
108 intermediateQueues
.push_back(new flitBuffer());
110 m_router_buffers
.push_back(intermediateQueues
);
112 vector
<OutVcState
*> out_vc_vector
;
113 for (int i
= 0; i
< m_num_vcs
; i
++) {
114 out_vc_vector
.push_back(new OutVcState(i
));
115 out_vc_vector
[i
]->setState(IDLE_
, g_system_ptr
->getTime());
117 m_out_vc_state
.push_back(out_vc_vector
);
118 m_link_weights
.push_back(link_weight
);
122 Router::isBufferNotFull(int vc
, int inport
)
124 int outport
= m_in_vc_state
[inport
][vc
]->get_outport();
125 int outvc
= m_in_vc_state
[inport
][vc
]->get_outvc();
127 return (!m_router_buffers
[outport
][outvc
]->isFull());
130 // A request for an output vc has been placed by an upstream Router/NI.
131 // This has to be updated and arbitration performed
133 Router::request_vc(int in_vc
, int in_port
, NetDest destination
,
136 assert(m_in_vc_state
[in_port
][in_vc
]->isInState(IDLE_
, request_time
));
138 int outport
= getRoute(destination
);
139 m_in_vc_state
[in_port
][in_vc
]->setRoute(outport
);
140 m_in_vc_state
[in_port
][in_vc
]->setState(VC_AB_
, request_time
);
141 assert(request_time
>= g_system_ptr
->getTime());
142 if (request_time
> g_system_ptr
->getTime())
143 m_vc_arbiter
->scheduleEventAbsolute(request_time
);
149 Router::vc_arbitrate()
151 int inport
= m_round_robin_inport
;
152 m_round_robin_inport
++;
153 if (m_round_robin_inport
== m_in_link
.size())
154 m_round_robin_inport
= 0;
156 for (int port_iter
= 0; port_iter
< m_in_link
.size(); port_iter
++) {
158 if (inport
>= m_in_link
.size())
160 int invc
= m_round_robin_invc
[inport
];
162 int next_round_robin_invc
= invc
;
164 next_round_robin_invc
++;
166 if (next_round_robin_invc
>= m_num_vcs
)
167 next_round_robin_invc
= 0;
169 } while (!(m_net_ptr
->validVirtualNetwork(
170 get_vnet(next_round_robin_invc
))));
172 m_round_robin_invc
[inport
] = next_round_robin_invc
;
174 for (int vc_iter
= 0; vc_iter
< m_num_vcs
; vc_iter
++) {
176 if (invc
>= m_num_vcs
)
179 if (!(m_net_ptr
->validVirtualNetwork(get_vnet(invc
))))
182 InVcState
*in_vc_state
= m_in_vc_state
[inport
][invc
];
184 if (in_vc_state
->isInState(VC_AB_
, g_system_ptr
->getTime())) {
185 int outport
= in_vc_state
->get_outport();
186 vector
<int> valid_vcs
= get_valid_vcs(invc
);
187 for (int valid_vc_iter
= 0; valid_vc_iter
< valid_vcs
.size();
189 if (m_out_vc_state
[outport
][valid_vcs
[valid_vc_iter
]]
190 ->isInState(IDLE_
, g_system_ptr
->getTime())) {
192 in_vc_state
->grant_vc(valid_vcs
[valid_vc_iter
],
193 g_system_ptr
->getTime());
195 m_in_link
[inport
]->grant_vc_link(invc
,
196 g_system_ptr
->getTime());
198 m_out_vc_state
[outport
][valid_vcs
[valid_vc_iter
]]
199 ->setState(VC_AB_
, g_system_ptr
->getTime());
209 Router::get_valid_vcs(int invc
)
213 for (int vnet
= 0; vnet
< m_virtual_networks
; vnet
++) {
214 if (invc
>= (vnet
*m_vc_per_vnet
) && invc
< ((vnet
+1)*m_vc_per_vnet
)) {
215 int base
= vnet
*m_vc_per_vnet
;
217 if (m_net_ptr
->isVNetOrdered(vnet
))
220 vc_per_vnet
= m_vc_per_vnet
;
222 for (int offset
= 0; offset
< vc_per_vnet
; offset
++) {
223 vc_list
.push_back(base
+offset
);
232 Router::grant_vc(int out_port
, int vc
, Time grant_time
)
234 assert(m_out_vc_state
[out_port
][vc
]->isInState(VC_AB_
, grant_time
));
235 m_out_vc_state
[out_port
][vc
]->grant_vc(grant_time
);
240 Router::release_vc(int out_port
, int vc
, Time release_time
)
242 assert(m_out_vc_state
[out_port
][vc
]->isInState(ACTIVE_
, release_time
));
243 m_out_vc_state
[out_port
][vc
]->setState(IDLE_
, release_time
);
247 // This function calculated the output port for a particular destination.
249 Router::getRoute(NetDest destination
)
251 int output_link
= -1;
252 int min_weight
= INFINITE_
;
253 for (int link
= 0; link
< m_routing_table
.size(); link
++) {
254 if (destination
.intersectionIsNotEmpty(m_routing_table
[link
])) {
255 if ((m_link_weights
[link
] >= min_weight
))
258 min_weight
= m_link_weights
[link
];
265 Router::routeCompute(flit
*m_flit
, int inport
)
267 int invc
= m_flit
->get_vc();
268 int outport
= m_in_vc_state
[inport
][invc
]->get_outport();
269 int outvc
= m_in_vc_state
[inport
][invc
]->get_outvc();
271 assert(m_net_ptr
->getNumPipeStages() >= 1);
273 // Subtract 1 as 1 cycle will be consumed in scheduling the output link
274 m_flit
->set_time(g_system_ptr
->getTime() +
275 (m_net_ptr
->getNumPipeStages() - 1));
276 m_flit
->set_vc(outvc
);
277 m_router_buffers
[outport
][outvc
]->insert(m_flit
);
279 if (m_net_ptr
->getNumPipeStages() > 1)
280 scheduleEvent(m_net_ptr
->getNumPipeStages() - 1 );
281 if ((m_flit
->get_type() == HEAD_
) || (m_flit
->get_type() == HEAD_TAIL_
)) {
283 safe_cast
<NetworkMessage
*>(m_flit
->get_msg_ptr().get());
284 NetDest destination
= nm
->getInternalDestination();
286 if (m_net_ptr
->getNumPipeStages() > 1) {
287 m_out_vc_state
[outport
][outvc
]->setState(VC_AB_
,
288 g_system_ptr
->getTime() + 1);
290 m_out_link
[outport
]->request_vc_link(outvc
, destination
,
291 g_system_ptr
->getTime() + 1);
293 m_out_vc_state
[outport
][outvc
]->setState(VC_AB_
,
294 g_system_ptr
->getTime());
296 m_out_link
[outport
]->request_vc_link(outvc
, destination
,
297 g_system_ptr
->getTime());
300 if ((m_flit
->get_type() == TAIL_
) || (m_flit
->get_type() == HEAD_TAIL_
)) {
301 m_in_vc_state
[inport
][invc
]->setState(IDLE_
,
302 g_system_ptr
->getTime() + 1);
304 m_in_link
[inport
]->release_vc_link(invc
,
305 g_system_ptr
->getTime() + 1);
314 // This is for round-robin scheduling of incoming ports
315 int incoming_port
= m_round_robin_start
;
316 m_round_robin_start
++;
317 if (m_round_robin_start
>= m_in_link
.size()) {
318 m_round_robin_start
= 0;
321 for (int port
= 0; port
< m_in_link
.size(); port
++) {
322 // Round robin scheduling
324 if (incoming_port
>= m_in_link
.size())
327 // checking the incoming link
328 if (m_in_link
[incoming_port
]->isReady()) {
329 DPRINTF(RubyNetwork
, "m_id: %d, Time: %lld\n",
330 m_id
, g_system_ptr
->getTime());
331 t_flit
= m_in_link
[incoming_port
]->peekLink();
332 routeCompute(t_flit
, incoming_port
);
333 m_in_link
[incoming_port
]->consumeLink();
336 scheduleOutputLinks();
337 checkReschedule(); // This is for flits lying in the router buffers
339 check_arbiter_reschedule();
343 Router::scheduleOutputLinks()
345 for (int port
= 0; port
< m_out_link
.size(); port
++) {
346 int vc_tolookat
= m_vc_round_robin
[port
];
348 int next_round_robin_vc_tolookat
= vc_tolookat
;
350 next_round_robin_vc_tolookat
++;
352 if (next_round_robin_vc_tolookat
== m_num_vcs
)
353 next_round_robin_vc_tolookat
= 0;
354 } while (!(m_net_ptr
->validVirtualNetwork(
355 get_vnet(next_round_robin_vc_tolookat
))));
357 m_vc_round_robin
[port
] = next_round_robin_vc_tolookat
;
359 for (int i
= 0; i
< m_num_vcs
; i
++) {
361 if (vc_tolookat
== m_num_vcs
)
364 if (m_router_buffers
[port
][vc_tolookat
]->isReady()) {
366 // models buffer backpressure
367 if (m_out_vc_state
[port
][vc_tolookat
]->isInState(ACTIVE_
,
368 g_system_ptr
->getTime()) &&
369 m_out_link
[port
]->isBufferNotFull_link(vc_tolookat
)) {
372 m_router_buffers
[port
][vc_tolookat
]->getTopFlit();
373 t_flit
->set_time(g_system_ptr
->getTime() + 1 );
374 m_out_src_queue
[port
]->insert(t_flit
);
375 m_out_link
[port
]->scheduleEvent(1);
376 break; // done for this port
384 Router::get_vnet(int vc
)
386 int vnet
= vc
/m_vc_per_vnet
;
387 assert(vnet
< m_virtual_networks
);
392 Router::checkReschedule()
394 for (int port
= 0; port
< m_out_link
.size(); port
++) {
395 for (int vc
= 0; vc
< m_num_vcs
; vc
++) {
396 if (m_router_buffers
[port
][vc
]->isReadyForNext()) {
405 Router::check_arbiter_reschedule()
407 for (int port
= 0; port
< m_in_link
.size(); port
++) {
408 for (int vc
= 0; vc
< m_num_vcs
; vc
++) {
409 if (m_in_vc_state
[port
][vc
]->isInState(VC_AB_
,
410 g_system_ptr
->getTime() + 1)) {
412 m_vc_arbiter
->scheduleEvent(1);
420 Router::print(ostream
& out
) const
426 GarnetRouterParams::create()
428 return new Router(this);