ruby: network: drop member m_in_use
[gem5.git] / src / mem / ruby / network / garnet / fixed-pipeline / SWallocator_d.cc
1 /*
2 * Copyright (c) 2008 Princeton University
3 * All rights reserved.
4 *
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.
15 *
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.
27 *
28 * Authors: Niket Agarwal
29 */
30
31 #include "mem/ruby/network/garnet/fixed-pipeline/GarnetNetwork_d.hh"
32 #include "mem/ruby/network/garnet/fixed-pipeline/InputUnit_d.hh"
33 #include "mem/ruby/network/garnet/fixed-pipeline/OutputUnit_d.hh"
34 #include "mem/ruby/network/garnet/fixed-pipeline/Router_d.hh"
35 #include "mem/ruby/network/garnet/fixed-pipeline/SWallocator_d.hh"
36
37 SWallocator_d::SWallocator_d(Router_d *router)
38 : Consumer(router)
39 {
40 m_router = router;
41 m_num_vcs = m_router->get_num_vcs();
42 m_vc_per_vnet = m_router->get_vc_per_vnet();
43
44 m_local_arbiter_activity = 0;
45 m_global_arbiter_activity = 0;
46 }
47
48 void
49 SWallocator_d::init()
50 {
51 m_input_unit = m_router->get_inputUnit_ref();
52 m_output_unit = m_router->get_outputUnit_ref();
53
54 m_num_inports = m_router->get_num_inports();
55 m_num_outports = m_router->get_num_outports();
56 m_round_robin_outport.resize(m_num_outports);
57 m_round_robin_inport.resize(m_num_inports);
58 m_port_req.resize(m_num_outports);
59 m_vc_winners.resize(m_num_outports);
60
61 for (int i = 0; i < m_num_inports; i++) {
62 m_round_robin_inport[i] = 0;
63 }
64
65 for (int i = 0; i < m_num_outports; i++) {
66 m_port_req[i].resize(m_num_inports);
67 m_vc_winners[i].resize(m_num_inports);
68
69 m_round_robin_outport[i] = 0;
70
71 for (int j = 0; j < m_num_inports; j++) {
72 m_port_req[i][j] = false; // [outport][inport]
73 }
74 }
75 }
76
77 void
78 SWallocator_d::wakeup()
79 {
80 arbitrate_inports(); // First stage of allocation
81 arbitrate_outports(); // Second stage of allocation
82
83 clear_request_vector();
84 check_for_wakeup();
85 m_router->call_switch();
86
87 }
88
89 void
90 SWallocator_d::arbitrate_inports()
91 {
92 // First do round robin arbitration on a set of input vc requests
93 for (int inport = 0; inport < m_num_inports; inport++) {
94 int invc = m_round_robin_inport[inport];
95
96 // Select next round robin vc candidate within valid vnet
97 int next_round_robin_invc = invc;
98 next_round_robin_invc++;
99 if (next_round_robin_invc >= m_num_vcs)
100 next_round_robin_invc = 0;
101 m_round_robin_inport[inport] = next_round_robin_invc;
102
103 for (int invc_iter = 0; invc_iter < m_num_vcs; invc_iter++) {
104 invc++;
105 if (invc >= m_num_vcs)
106 invc = 0;
107
108 if (m_input_unit[inport]->need_stage(invc, ACTIVE_, SA_,
109 m_router->curCycle()) &&
110 m_input_unit[inport]->has_credits(invc)) {
111
112 if (is_candidate_inport(inport, invc)) {
113 int outport = m_input_unit[inport]->get_route(invc);
114 m_local_arbiter_activity++;
115 m_port_req[outport][inport] = true;
116 m_vc_winners[outport][inport]= invc;
117 break; // got one vc winner for this port
118 }
119 }
120 }
121 }
122 }
123
124 bool
125 SWallocator_d::is_candidate_inport(int inport, int invc)
126 {
127 int outport = m_input_unit[inport]->get_route(invc);
128 Cycles t_enqueue_time = m_input_unit[inport]->get_enqueue_time(invc);
129 int t_vnet = get_vnet(invc);
130 int vc_base = t_vnet*m_vc_per_vnet;
131 if ((m_router->get_net_ptr())->isVNetOrdered(t_vnet)) {
132 for (int vc_offset = 0; vc_offset < m_vc_per_vnet; vc_offset++) {
133 int temp_vc = vc_base + vc_offset;
134 if (m_input_unit[inport]->need_stage(temp_vc, ACTIVE_, SA_,
135 m_router->curCycle()) &&
136 (m_input_unit[inport]->get_route(temp_vc) == outport) &&
137 (m_input_unit[inport]->get_enqueue_time(temp_vc) <
138 t_enqueue_time)) {
139 return false;
140 break;
141 }
142 }
143 }
144 return true;
145 }
146
147
148 void
149 SWallocator_d::arbitrate_outports()
150 {
151 // Now there are a set of input vc requests for output vcs.
152 // Again do round robin arbitration on these requests
153 for (int outport = 0; outport < m_num_outports; outport++) {
154 int inport = m_round_robin_outport[outport];
155 m_round_robin_outport[outport]++;
156
157 if (m_round_robin_outport[outport] >= m_num_outports)
158 m_round_robin_outport[outport] = 0;
159
160 for (int inport_iter = 0; inport_iter < m_num_inports; inport_iter++) {
161 inport++;
162 if (inport >= m_num_inports)
163 inport = 0;
164
165 // inport has a request this cycle for outport:
166 if (m_port_req[outport][inport]) {
167 m_port_req[outport][inport] = false;
168 int invc = m_vc_winners[outport][inport];
169 int outvc = m_input_unit[inport]->get_outvc(invc);
170
171 // remove flit from Input Unit
172 flit_d *t_flit = m_input_unit[inport]->getTopFlit(invc);
173 t_flit->advance_stage(ST_, m_router->curCycle());
174 t_flit->set_vc(outvc);
175 t_flit->set_outport(outport);
176 t_flit->set_time(m_router->curCycle());
177
178 m_output_unit[outport]->decrement_credit(outvc);
179 m_router->update_sw_winner(inport, t_flit);
180 m_global_arbiter_activity++;
181
182 if ((t_flit->get_type() == TAIL_) ||
183 t_flit->get_type() == HEAD_TAIL_) {
184
185 // Send a credit back
186 // along with the information that this VC is now idle
187 m_input_unit[inport]->increment_credit(invc, true,
188 m_router->curCycle());
189
190 // This Input VC should now be empty
191 assert(m_input_unit[inport]->isReady(invc,
192 m_router->curCycle()) == false);
193
194 m_input_unit[inport]->set_vc_state(IDLE_, invc,
195 m_router->curCycle());
196 m_input_unit[inport]->set_enqueue_time(invc,
197 Cycles(INFINITE_));
198 } else {
199 // Send a credit back
200 // but do not indicate that the VC is idle
201 m_input_unit[inport]->increment_credit(invc, false,
202 m_router->curCycle());
203 }
204 break; // got a in request for this outport
205 }
206 }
207 }
208 }
209
210 void
211 SWallocator_d::check_for_wakeup()
212 {
213 Cycles nextCycle = m_router->curCycle() + Cycles(1);
214
215 for (int i = 0; i < m_num_inports; i++) {
216 for (int j = 0; j < m_num_vcs; j++) {
217 if (m_input_unit[i]->need_stage(j, ACTIVE_, SA_, nextCycle)) {
218 m_router->vcarb_req();
219 return;
220 }
221 }
222 }
223 }
224
225 int
226 SWallocator_d::get_vnet(int invc)
227 {
228 int vnet = invc/m_vc_per_vnet;
229 assert(vnet < m_router->get_num_vnets());
230 return vnet;
231 }
232
233 void
234 SWallocator_d::clear_request_vector()
235 {
236 for (int i = 0; i < m_num_outports; i++) {
237 for (int j = 0; j < m_num_inports; j++) {
238 m_port_req[i][j] = false;
239 }
240 }
241 }