2 * Copyright (c) 2008 Princeton University
3 * Copyright (c) 2016 Georgia Institute of Technology
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met: redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer;
10 * redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution;
13 * neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "mem/ruby/network/garnet2.0/RoutingUnit.hh"
33 #include "base/cast.hh"
34 #include "debug/RubyNetwork.hh"
35 #include "mem/ruby/network/garnet2.0/InputUnit.hh"
36 #include "mem/ruby/network/garnet2.0/Router.hh"
37 #include "mem/ruby/slicc_interface/Message.hh"
39 RoutingUnit::RoutingUnit(Router
*router
)
42 m_routing_table
.clear();
43 m_weight_table
.clear();
47 RoutingUnit::addRoute(std::vector
<NetDest
>& routing_table_entry
)
49 if (routing_table_entry
.size() > m_routing_table
.size()) {
50 m_routing_table
.resize(routing_table_entry
.size());
52 for (int v
= 0; v
< routing_table_entry
.size(); v
++) {
53 m_routing_table
[v
].push_back(routing_table_entry
[v
]);
58 RoutingUnit::addWeight(int link_weight
)
60 m_weight_table
.push_back(link_weight
);
64 RoutingUnit::supportsVnet(int vnet
, std::vector
<int> sVnets
)
66 // If all vnets are supported, return true
67 if (sVnets
.size() == 0) {
71 // Find the vnet in the vector, return true
72 if (std::find(sVnets
.begin(), sVnets
.end(), vnet
) != sVnets
.end()) {
81 * This is the default routing algorithm in garnet.
82 * The routing table is populated during topology creation.
83 * Routes can be biased via weight assignments in the topology file.
84 * Correct weight assignments are critical to provide deadlock avoidance.
87 RoutingUnit::lookupRoutingTable(int vnet
, NetDest msg_destination
)
89 // First find all possible output link candidates
90 // For ordered vnet, just choose the first
91 // (to make sure different packets don't choose different routes)
92 // For unordered vnet, randomly choose any of the links
93 // To have a strict ordering between links, they should be given
94 // different weights in the topology file
97 int min_weight
= INFINITE_
;
98 std::vector
<int> output_link_candidates
;
99 int num_candidates
= 0;
101 // Identify the minimum weight among the candidate output links
102 for (int link
= 0; link
< m_routing_table
[vnet
].size(); link
++) {
103 if (msg_destination
.intersectionIsNotEmpty(
104 m_routing_table
[vnet
][link
])) {
106 if (m_weight_table
[link
] <= min_weight
)
107 min_weight
= m_weight_table
[link
];
111 // Collect all candidate output links with this minimum weight
112 for (int link
= 0; link
< m_routing_table
[vnet
].size(); link
++) {
113 if (msg_destination
.intersectionIsNotEmpty(
114 m_routing_table
[vnet
][link
])) {
116 if (m_weight_table
[link
] == min_weight
) {
118 output_link_candidates
.push_back(link
);
123 if (output_link_candidates
.size() == 0) {
124 fatal("Fatal Error:: No Route exists from this Router.");
128 // Randomly select any candidate output link
130 if (!(m_router
->get_net_ptr())->isVNetOrdered(vnet
))
131 candidate
= rand() % num_candidates
;
133 output_link
= output_link_candidates
.at(candidate
);
139 RoutingUnit::addInDirection(PortDirection inport_dirn
, int inport_idx
)
141 m_inports_dirn2idx
[inport_dirn
] = inport_idx
;
142 m_inports_idx2dirn
[inport_idx
] = inport_dirn
;
146 RoutingUnit::addOutDirection(PortDirection outport_dirn
, int outport_idx
)
148 m_outports_dirn2idx
[outport_dirn
] = outport_idx
;
149 m_outports_idx2dirn
[outport_idx
] = outport_dirn
;
152 // outportCompute() is called by the InputUnit
153 // It calls the routing table by default.
154 // A template for adaptive topology-specific routing algorithm
155 // implementations using port directions rather than a static routing
156 // table is provided here.
159 RoutingUnit::outportCompute(RouteInfo route
, int inport
,
160 PortDirection inport_dirn
)
164 if (route
.dest_router
== m_router
->get_id()) {
166 // Multiple NIs may be connected to this router,
167 // all with output port direction = "Local"
168 // Get exact outport id from table
169 outport
= lookupRoutingTable(route
.vnet
, route
.net_dest
);
173 // Routing Algorithm set in GarnetNetwork.py
174 // Can be over-ridden from command line using --routing-algorithm = 1
175 RoutingAlgorithm routing_algorithm
=
176 (RoutingAlgorithm
) m_router
->get_net_ptr()->getRoutingAlgorithm();
178 switch (routing_algorithm
) {
179 case TABLE_
: outport
=
180 lookupRoutingTable(route
.vnet
, route
.net_dest
); break;
182 outportComputeXY(route
, inport
, inport_dirn
); break;
183 // any custom algorithm
184 case CUSTOM_
: outport
=
185 outportComputeCustom(route
, inport
, inport_dirn
); break;
187 lookupRoutingTable(route
.vnet
, route
.net_dest
); break;
190 assert(outport
!= -1);
194 // XY routing implemented using port directions
195 // Only for reference purpose in a Mesh
196 // By default Garnet uses the routing table
198 RoutingUnit::outportComputeXY(RouteInfo route
,
200 PortDirection inport_dirn
)
202 PortDirection outport_dirn
= "Unknown";
204 int M5_VAR_USED num_rows
= m_router
->get_net_ptr()->getNumRows();
205 int num_cols
= m_router
->get_net_ptr()->getNumCols();
206 assert(num_rows
> 0 && num_cols
> 0);
208 int my_id
= m_router
->get_id();
209 int my_x
= my_id
% num_cols
;
210 int my_y
= my_id
/ num_cols
;
212 int dest_id
= route
.dest_router
;
213 int dest_x
= dest_id
% num_cols
;
214 int dest_y
= dest_id
/ num_cols
;
216 int x_hops
= abs(dest_x
- my_x
);
217 int y_hops
= abs(dest_y
- my_y
);
219 bool x_dirn
= (dest_x
>= my_x
);
220 bool y_dirn
= (dest_y
>= my_y
);
222 // already checked that in outportCompute() function
223 assert(!(x_hops
== 0 && y_hops
== 0));
227 assert(inport_dirn
== "Local" || inport_dirn
== "West");
228 outport_dirn
= "East";
230 assert(inport_dirn
== "Local" || inport_dirn
== "East");
231 outport_dirn
= "West";
233 } else if (y_hops
> 0) {
235 // "Local" or "South" or "West" or "East"
236 assert(inport_dirn
!= "North");
237 outport_dirn
= "North";
239 // "Local" or "North" or "West" or "East"
240 assert(inport_dirn
!= "South");
241 outport_dirn
= "South";
244 // x_hops == 0 and y_hops == 0
245 // this is not possible
246 // already checked that in outportCompute() function
247 panic("x_hops == y_hops == 0");
250 return m_outports_dirn2idx
[outport_dirn
];
253 // Template for implementing custom routing algorithm
254 // using port directions. (Example adaptive)
256 RoutingUnit::outportComputeCustom(RouteInfo route
,
258 PortDirection inport_dirn
)
260 panic("%s placeholder executed", __FUNCTION__
);