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
34 #include "base/cast.hh"
35 #include "base/stl_helpers.hh"
36 #include "debug/RubyNetwork.hh"
37 #include "mem/ruby/buffers/MessageBuffer.hh"
38 #include "mem/ruby/network/garnet/fixed-pipeline/NetworkInterface_d.hh"
39 #include "mem/ruby/network/garnet/fixed-pipeline/flitBuffer_d.hh"
40 #include "mem/ruby/slicc_interface/NetworkMessage.hh"
43 using m5::stl_helpers::deletePointers
;
45 NetworkInterface_d::NetworkInterface_d(int id
, int virtual_networks
,
46 GarnetNetwork_d
*network_ptr
)
47 : Consumer(network_ptr
)
50 m_net_ptr
= network_ptr
;
51 m_virtual_networks
= virtual_networks
;
52 m_vc_per_vnet
= m_net_ptr
->getVCsPerVnet();
53 m_num_vcs
= m_vc_per_vnet
*m_virtual_networks
;
56 m_ni_buffers
.resize(m_num_vcs
);
57 m_ni_enqueue_time
.resize(m_num_vcs
);
58 inNode_ptr
.resize(m_virtual_networks
);
59 outNode_ptr
.resize(m_virtual_networks
);
60 creditQueue
= new flitBuffer_d();
62 // instantiating the NI flit buffers
63 for (int i
= 0; i
< m_num_vcs
; i
++) {
64 m_ni_buffers
[i
] = new flitBuffer_d();
65 m_ni_enqueue_time
[i
] = INFINITE_
;
67 m_vc_allocator
.resize(m_virtual_networks
); // 1 allocator per vnet
68 for (int i
= 0; i
< m_virtual_networks
; i
++) {
69 m_vc_allocator
[i
] = 0;
72 for (int i
= 0; i
< m_num_vcs
; i
++) {
73 m_out_vc_state
.push_back(new OutVcState_d(i
, m_net_ptr
));
74 m_out_vc_state
[i
]->setState(IDLE_
, m_net_ptr
->curCycle());
78 NetworkInterface_d::~NetworkInterface_d()
80 deletePointers(m_out_vc_state
);
81 deletePointers(m_ni_buffers
);
87 NetworkInterface_d::addInPort(NetworkLink_d
*in_link
,
88 CreditLink_d
*credit_link
)
91 in_link
->setLinkConsumer(this);
92 m_ni_credit_link
= credit_link
;
93 credit_link
->setSourceQueue(creditQueue
);
97 NetworkInterface_d::addOutPort(NetworkLink_d
*out_link
,
98 CreditLink_d
*credit_link
)
100 m_credit_link
= credit_link
;
101 credit_link
->setLinkConsumer(this);
103 outNetLink
= out_link
;
104 outSrcQueue
= new flitBuffer_d();
105 out_link
->setSourceQueue(outSrcQueue
);
109 NetworkInterface_d::addNode(vector
<MessageBuffer
*>& in
,
110 vector
<MessageBuffer
*>& out
)
112 assert(in
.size() == m_virtual_networks
);
115 for (int j
= 0; j
< m_virtual_networks
; j
++) {
117 // the protocol injects messages into the NI
118 inNode_ptr
[j
]->setConsumer(this);
119 inNode_ptr
[j
]->setReceiver(m_net_ptr
);
121 outNode_ptr
[j
]->setSender(m_net_ptr
);
126 NetworkInterface_d::flitisizeMessage(MsgPtr msg_ptr
, int vnet
)
128 NetworkMessage
*net_msg_ptr
= safe_cast
<NetworkMessage
*>(msg_ptr
.get());
129 NetDest net_msg_dest
= net_msg_ptr
->getInternalDestination();
131 // gets all the destinations associated with this message.
132 vector
<NodeID
> dest_nodes
= net_msg_dest
.getAllDest();
134 // Number of flits is dependent on the link bandwidth available.
135 // This is expressed in terms of bytes/cycle or the flit size
136 int num_flits
= (int) ceil((double) m_net_ptr
->MessageSizeType_to_int(
137 net_msg_ptr
->getMessageSize())/m_net_ptr
->getNiFlitSize());
139 // loop to convert all multicast messages into unicast messages
140 for (int ctr
= 0; ctr
< dest_nodes
.size(); ctr
++) {
142 // this will return a free output virtual channel
143 int vc
= calculateVC(vnet
);
148 MsgPtr new_msg_ptr
= msg_ptr
->clone();
149 NodeID destID
= dest_nodes
[ctr
];
151 NetworkMessage
*new_net_msg_ptr
=
152 safe_cast
<NetworkMessage
*>(new_msg_ptr
.get());
153 if (dest_nodes
.size() > 1) {
154 NetDest personal_dest
;
155 for (int m
= 0; m
< (int) MachineType_NUM
; m
++) {
156 if ((destID
>= MachineType_base_number((MachineType
) m
)) &&
157 destID
< MachineType_base_number((MachineType
) (m
+1))) {
158 // calculating the NetDest associated with this destID
159 personal_dest
.clear();
160 personal_dest
.add((MachineID
) {(MachineType
) m
, (destID
-
161 MachineType_base_number((MachineType
) m
))});
162 new_net_msg_ptr
->getInternalDestination() = personal_dest
;
166 net_msg_dest
.removeNetDest(personal_dest
);
167 // removing the destination from the original message to reflect
168 // that a message with this particular destination has been
169 // flitisized and an output vc is acquired
170 net_msg_ptr
->getInternalDestination().removeNetDest(personal_dest
);
173 for (int i
= 0; i
< num_flits
; i
++) {
174 m_net_ptr
->increment_injected_flits(vnet
);
175 flit_d
*fl
= new flit_d(i
, vc
, vnet
, num_flits
, new_msg_ptr
,
176 m_net_ptr
->curCycle());
178 fl
->set_delay(m_net_ptr
->curCycle() -
179 m_net_ptr
->ticksToCycles(msg_ptr
->getTime()));
180 m_ni_buffers
[vc
]->insert(fl
);
183 m_ni_enqueue_time
[vc
] = m_net_ptr
->curCycle();
184 m_out_vc_state
[vc
]->setState(ACTIVE_
, m_net_ptr
->curCycle());
189 // Looking for a free output vc
191 NetworkInterface_d::calculateVC(int vnet
)
193 for (int i
= 0; i
< m_vc_per_vnet
; i
++) {
194 int delta
= m_vc_allocator
[vnet
];
195 m_vc_allocator
[vnet
]++;
196 if(m_vc_allocator
[vnet
] == m_vc_per_vnet
)
197 m_vc_allocator
[vnet
] = 0;
199 if (m_out_vc_state
[(vnet
*m_vc_per_vnet
) + delta
]->isInState(
200 IDLE_
, m_net_ptr
->curCycle())) {
201 return ((vnet
*m_vc_per_vnet
) + delta
);
208 * The NI wakeup checks whether there are any ready messages in the protocol
209 * buffer. If yes, it picks that up, flitisizes it into a number of flits and
210 * puts it into an output buffer and schedules the output link. On a wakeup
211 * it also checks whether there are flits in the input link. If yes, it picks
212 * them up and if the flit is a tail, the NI inserts the corresponding message
213 * into the protocol buffer. It also checks for credits being sent by the
218 NetworkInterface_d::wakeup()
220 DPRINTF(RubyNetwork
, "m_id: %d woke up at time: %lld",
221 m_id
, m_net_ptr
->curCycle());
225 // Checking for messages coming from the protocol
226 // can pick up a message/cycle for each virtual net
227 for (int vnet
= 0; vnet
< m_virtual_networks
; vnet
++) {
228 while (inNode_ptr
[vnet
]->isReady()) { // Is there a message waiting
229 msg_ptr
= inNode_ptr
[vnet
]->peekMsgPtr();
230 if (flitisizeMessage(msg_ptr
, vnet
)) {
231 inNode_ptr
[vnet
]->pop();
238 scheduleOutputLink();
241 /*********** Picking messages destined for this NI **********/
243 if (inNetLink
->isReady(m_net_ptr
->curCycle())) {
244 flit_d
*t_flit
= inNetLink
->consumeLink();
245 bool free_signal
= false;
246 if (t_flit
->get_type() == TAIL_
|| t_flit
->get_type() == HEAD_TAIL_
) {
249 outNode_ptr
[t_flit
->get_vnet()]->enqueue(
250 t_flit
->get_msg_ptr(), Cycles(1));
252 // Simply send a credit back since we are not buffering
253 // this flit in the NI
254 flit_d
*credit_flit
= new flit_d(t_flit
->get_vc(), free_signal
,
255 m_net_ptr
->curCycle());
256 creditQueue
->insert(credit_flit
);
257 m_ni_credit_link
->scheduleEvent(Cycles(1));
259 int vnet
= t_flit
->get_vnet();
260 m_net_ptr
->increment_received_flits(vnet
);
261 Cycles network_delay
= m_net_ptr
->curCycle() -
262 t_flit
->get_enqueue_time();
263 Cycles queueing_delay
= t_flit
->get_delay();
265 m_net_ptr
->increment_network_latency(network_delay
, vnet
);
266 m_net_ptr
->increment_queueing_latency(queueing_delay
, vnet
);
270 /****************** Checking for credit link *******/
272 if (m_credit_link
->isReady(m_net_ptr
->curCycle())) {
273 flit_d
*t_flit
= m_credit_link
->consumeLink();
274 m_out_vc_state
[t_flit
->get_vc()]->increment_credit();
275 if (t_flit
->is_free_signal()) {
276 m_out_vc_state
[t_flit
->get_vc()]->setState(IDLE_
,
277 m_net_ptr
->curCycle());
283 /** This function looks at the NI buffers
284 * if some buffer has flits which are ready to traverse the link in the next
285 * cycle, and the downstream output vc associated with this flit has buffers
286 * left, the link is scheduled for the next cycle
290 NetworkInterface_d::scheduleOutputLink()
292 int vc
= m_vc_round_robin
;
294 if (m_vc_round_robin
== m_num_vcs
)
295 m_vc_round_robin
= 0;
297 for (int i
= 0; i
< m_num_vcs
; i
++) {
302 // model buffer backpressure
303 if (m_ni_buffers
[vc
]->isReady(m_net_ptr
->curCycle()) &&
304 m_out_vc_state
[vc
]->has_credits()) {
306 bool is_candidate_vc
= true;
307 int t_vnet
= get_vnet(vc
);
308 int vc_base
= t_vnet
* m_vc_per_vnet
;
310 if (m_net_ptr
->isVNetOrdered(t_vnet
)) {
311 for (int vc_offset
= 0; vc_offset
< m_vc_per_vnet
;
313 int t_vc
= vc_base
+ vc_offset
;
314 if (m_ni_buffers
[t_vc
]->isReady(m_net_ptr
->curCycle())) {
315 if (m_ni_enqueue_time
[t_vc
] < m_ni_enqueue_time
[vc
]) {
316 is_candidate_vc
= false;
322 if (!is_candidate_vc
)
325 m_out_vc_state
[vc
]->decrement_credit();
326 // Just removing the flit
327 flit_d
*t_flit
= m_ni_buffers
[vc
]->getTopFlit();
328 t_flit
->set_time(m_net_ptr
->curCycle() + Cycles(1));
329 outSrcQueue
->insert(t_flit
);
330 // schedule the out link
331 outNetLink
->scheduleEvent(Cycles(1));
333 if (t_flit
->get_type() == TAIL_
||
334 t_flit
->get_type() == HEAD_TAIL_
) {
335 m_ni_enqueue_time
[vc
] = INFINITE_
;
343 NetworkInterface_d::get_vnet(int vc
)
345 for (int i
= 0; i
< m_net_ptr
->getNumberOfVirtualNetworks(); i
++) {
346 if (vc
>= (i
*m_vc_per_vnet
) && vc
< ((i
+1)*m_vc_per_vnet
)) {
350 fatal("Could not determine vc");
354 NetworkInterface_d::checkReschedule()
356 for (int vnet
= 0; vnet
< m_virtual_networks
; vnet
++) {
357 if (inNode_ptr
[vnet
]->isReady()) { // Is there a message waiting
358 scheduleEvent(Cycles(1));
362 for (int vc
= 0; vc
< m_num_vcs
; vc
++) {
363 if (m_ni_buffers
[vc
]->isReadyForNext(m_net_ptr
->curCycle())) {
364 scheduleEvent(Cycles(1));
371 NetworkInterface_d::print(std::ostream
& out
) const
373 out
<< "[Network Interface]";
377 NetworkInterface_d::functionalWrite(Packet
*pkt
)
379 uint32_t num_functional_writes
= 0;
380 for (unsigned int i
= 0; i
< m_num_vcs
; ++i
) {
381 num_functional_writes
+= m_ni_buffers
[i
]->functionalWrite(pkt
);
384 num_functional_writes
+= outSrcQueue
->functionalWrite(pkt
);
385 return num_functional_writes
;