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/network/MessageBuffer.hh"
38 #include "mem/ruby/network/garnet/flexible-pipeline/NetworkInterface.hh"
39 #include "mem/ruby/network/garnet/flexible-pipeline/flitBuffer.hh"
40 #include "mem/ruby/slicc_interface/NetworkMessage.hh"
43 using m5::stl_helpers::deletePointers
;
45 NetworkInterface::NetworkInterface(const Params
*p
)
46 : ClockedObject(p
), FlexibleConsumer(this)
49 m_virtual_networks
= p
->virt_nets
;
50 m_vc_per_vnet
= p
->vcs_per_vnet
;
51 m_num_vcs
= m_vc_per_vnet
*m_virtual_networks
;
54 // instantiating the NI flit buffers
55 m_ni_buffers
.resize(m_num_vcs
);
56 for (int i
=0; i
< m_num_vcs
; i
++)
57 m_ni_buffers
[i
] = new flitBuffer();
59 m_vc_allocator
.resize(m_virtual_networks
);
60 for (int i
= 0; i
< m_virtual_networks
; i
++) {
61 m_vc_allocator
[i
] = 0;
64 for (int i
= 0; i
< m_num_vcs
; i
++) {
65 m_out_vc_state
.push_back(new OutVcState(i
));
69 NetworkInterface::~NetworkInterface()
71 deletePointers(m_out_vc_state
);
72 deletePointers(m_ni_buffers
);
77 NetworkInterface::addInPort(NetworkLink
*in_link
)
80 in_link
->setLinkConsumer(this);
84 NetworkInterface::addOutPort(NetworkLink
*out_link
)
86 outNetLink
= out_link
;
87 outSrcQueue
= new flitBuffer();
88 out_link
->setSourceQueue(outSrcQueue
);
89 out_link
->setSource(this);
93 NetworkInterface::addNode(map
<int, MessageBuffer
*>& in
,
94 map
<int, MessageBuffer
*>& out
)
100 // the protocol injects messages into the NI
101 it
.second
->setConsumer(this);
102 it
.second
->setReceiver(this);
105 for (auto& it
: out
) {
106 it
.second
->setSender(this);
111 NetworkInterface::request_vc(int in_vc
, int in_port
, NetDest destination
,
114 inNetLink
->grant_vc_link(in_vc
, request_time
);
118 NetworkInterface::flitisizeMessage(MsgPtr msg_ptr
, int vnet
)
120 NetworkMessage
*net_msg_ptr
= safe_cast
<NetworkMessage
*>(msg_ptr
.get());
121 NetDest net_msg_dest
= net_msg_ptr
->getInternalDestination();
123 // get all the destinations associated with this message.
124 vector
<NodeID
> dest_nodes
= net_msg_dest
.getAllDest();
126 // Number of flits is dependent on the link bandwidth available.
127 // This is expressed in terms of bytes/cycle or the flit size
129 int num_flits
= (int) ceil((double) m_net_ptr
->MessageSizeType_to_int(
130 net_msg_ptr
->getMessageSize())/m_net_ptr
->getNiFlitSize());
132 // loop to convert all multicast messages into unicast messages
133 for (int ctr
= 0; ctr
< dest_nodes
.size(); ctr
++) {
134 int vc
= calculateVC(vnet
); // this will return a free output vc
137 // did not find a free output vc
140 MsgPtr new_msg_ptr
= msg_ptr
->clone();
141 NodeID destID
= dest_nodes
[ctr
];
143 NetworkMessage
*new_net_msg_ptr
=
144 safe_cast
<NetworkMessage
*>(new_msg_ptr
.get());
145 if (dest_nodes
.size() > 1) {
146 NetDest personal_dest
;
147 for (int m
= 0; m
< (int) MachineType_NUM
; m
++) {
148 if ((destID
>= MachineType_base_number((MachineType
) m
)) &&
149 destID
< MachineType_base_number((MachineType
) (m
+1))) {
150 // calculating the NetDest associated with this destID
151 personal_dest
.clear();
152 personal_dest
.add((MachineID
) {(MachineType
) m
, (destID
-
153 MachineType_base_number((MachineType
) m
))});
154 new_net_msg_ptr
->getInternalDestination() = personal_dest
;
158 net_msg_dest
.removeNetDest(personal_dest
);
160 // removing the destination from the original message to reflect
161 // that a message with this particular destination has been
162 // flitisized and an output vc is acquired
163 net_msg_ptr
->getInternalDestination().removeNetDest(personal_dest
);
165 for (int i
= 0; i
< num_flits
; i
++) {
166 m_net_ptr
->increment_injected_flits(vnet
);
167 flit
*fl
= new flit(i
, vc
, vnet
, num_flits
, new_msg_ptr
,
169 fl
->set_delay(curCycle() - ticksToCycles(msg_ptr
->getTime()));
170 m_ni_buffers
[vc
]->insert(fl
);
173 m_out_vc_state
[vc
]->setState(VC_AB_
, curCycle());
175 // setting an output vc request for the next hop.
176 // This flit will be ready to traverse the link and into the next hop
177 // only when an output vc is acquired at the next hop
178 outNetLink
->request_vc_link(
179 vc
, new_net_msg_ptr
->getInternalDestination(), curCycle());
185 // An output vc has been granted at the next hop to one of the vc's.
186 // We have to update the state of the vc to reflect this
188 NetworkInterface::grant_vc(int out_port
, int vc
, Cycles grant_time
)
190 assert(m_out_vc_state
[vc
]->isInState(VC_AB_
, grant_time
));
191 m_out_vc_state
[vc
]->grant_vc(grant_time
);
192 scheduleEvent(Cycles(1));
195 // The tail flit corresponding to this vc has been buffered at the next hop
196 // and thus this vc is now free
198 NetworkInterface::release_vc(int out_port
, int vc
, Cycles release_time
)
200 assert(m_out_vc_state
[vc
]->isInState(ACTIVE_
, release_time
));
201 m_out_vc_state
[vc
]->setState(IDLE_
, release_time
);
202 scheduleEvent(Cycles(1));
205 // Looking for a free output vc
207 NetworkInterface::calculateVC(int vnet
)
210 if (m_net_ptr
->isVNetOrdered(vnet
))
213 vc_per_vnet
= m_vc_per_vnet
;
215 for (int i
= 0; i
< vc_per_vnet
; i
++) {
216 int delta
= m_vc_allocator
[vnet
];
217 m_vc_allocator
[vnet
]++;
218 if (m_vc_allocator
[vnet
] == vc_per_vnet
)
219 m_vc_allocator
[vnet
] = 0;
221 if (m_out_vc_state
[(vnet
*m_vc_per_vnet
) + delta
]->
222 isInState(IDLE_
, curCycle())) {
223 return ((vnet
*m_vc_per_vnet
) + delta
);
230 * The NI wakeup checks whether there are any ready messages in the protocol
231 * buffer. If yes, it picks that up, flitisizes it into a number of flits and
232 * puts it into an output buffer and schedules the output link.
233 * On a wakeup it also checks whether there are flits in the input link.
234 * If yes, it picks them up and if the flit is a tail, the NI inserts the
235 * corresponding message into the protocol buffer.
239 NetworkInterface::wakeup()
243 //Checking for messages coming from the protocol
244 // can pick up a message/cycle for each virtual net
245 for (auto it
= inNode_ptr
.begin(); it
!= inNode_ptr
.end(); ++it
) {
246 int vnet
= (*it
).first
;
247 MessageBuffer
*b
= (*it
).second
;
249 while (b
->isReady()) { // Is there a message waiting
250 msg_ptr
= b
->peekMsgPtr();
251 if (flitisizeMessage(msg_ptr
, vnet
)) {
259 scheduleOutputLink();
262 /*********** Picking messages destined for this NI **********/
264 if (inNetLink
->isReady()) {
265 flit
*t_flit
= inNetLink
->consumeLink();
266 if (t_flit
->get_type() == TAIL_
|| t_flit
->get_type() == HEAD_TAIL_
) {
267 DPRINTF(RubyNetwork
, "m_id: %d, Message delivered at time: %lld\n",
270 outNode_ptr
[t_flit
->get_vnet()]->enqueue(
271 t_flit
->get_msg_ptr(), Cycles(1));
273 // signal the upstream router that this vc can be freed now
274 inNetLink
->release_vc_link(t_flit
->get_vc(),
275 curCycle() + Cycles(1));
278 int vnet
= t_flit
->get_vnet();
279 m_net_ptr
->increment_received_flits(vnet
);
280 Cycles network_delay
= curCycle() - t_flit
->get_enqueue_time();
281 Cycles queueing_delay
= t_flit
->get_delay();
283 m_net_ptr
->increment_network_latency(network_delay
, vnet
);
284 m_net_ptr
->increment_queueing_latency(queueing_delay
, vnet
);
289 /* This function looks at the NI buffers and if some buffer has flits which
290 * are ready to traverse the link in the next cycle and also the downstream
291 * output vc associated with this flit has buffers left, the link is scheduled
296 NetworkInterface::scheduleOutputLink()
298 int vc
= m_vc_round_robin
;
300 if (m_vc_round_robin
== m_num_vcs
)
301 m_vc_round_robin
= 0;
303 for (int i
= 0; i
< m_num_vcs
; i
++) {
307 if (m_ni_buffers
[vc
]->isReady(curCycle())) {
308 if (m_out_vc_state
[vc
]->isInState(ACTIVE_
, curCycle()) &&
309 outNetLink
->isBufferNotFull_link(vc
)) { // buffer backpressure
311 // Just removing the flit
312 flit
*t_flit
= m_ni_buffers
[vc
]->getTopFlit();
313 t_flit
->set_time(curCycle() + Cycles(1));
314 outSrcQueue
->insert(t_flit
);
316 // schedule the out link
318 scheduleEventAbsolute(clockEdge(Cycles(1)));
326 NetworkInterface::checkReschedule()
328 for (const auto& it
: inNode_ptr
) {
329 MessageBuffer
*b
= it
.second
;
331 while (b
->isReady()) { // Is there a message waiting
332 scheduleEvent(Cycles(1));
337 for (int vc
= 0; vc
< m_num_vcs
; vc
++) {
338 if (m_ni_buffers
[vc
]->isReady(curCycle() + Cycles(1))) {
339 scheduleEvent(Cycles(1));
346 NetworkInterface::functionalRead(Packet
*pkt
)
348 // Go through the internal buffers
349 for (unsigned int i
= 0; i
< m_ni_buffers
.size(); ++i
) {
350 if (m_ni_buffers
[i
]->functionalRead(pkt
)) {
355 // Go through the buffer between this network interface and the router
356 if (outSrcQueue
->functionalRead(pkt
)) {
364 NetworkInterface::functionalWrite(Packet
*pkt
)
366 uint32_t num_functional_writes
= 0;
367 for (unsigned int i
= 0; i
< m_ni_buffers
.size(); ++i
) {
368 num_functional_writes
+= m_ni_buffers
[i
]->functionalWrite(pkt
);
371 num_functional_writes
+= outSrcQueue
->functionalWrite(pkt
);
372 return num_functional_writes
;
376 NetworkInterface::print(std::ostream
& out
) const
378 out
<< "[Network Interface]";
382 GarnetNetworkInterfaceParams::create()
384 return new NetworkInterface(this);