13bbe2b08181aa2032b5d50b7ff73411862872d7
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 m_ni_buffers
.resize(m_num_vcs
);
55 inNode_ptr
.resize(m_virtual_networks
);
56 outNode_ptr
.resize(m_virtual_networks
);
58 // instantiating the NI flit buffers
59 for (int i
=0; i
< m_num_vcs
; i
++)
60 m_ni_buffers
[i
] = new flitBuffer();
62 m_vc_allocator
.resize(m_virtual_networks
);
63 for (int i
= 0; i
< m_virtual_networks
; i
++) {
64 m_vc_allocator
[i
] = 0;
67 for (int i
= 0; i
< m_num_vcs
; i
++) {
68 m_out_vc_state
.push_back(new OutVcState(i
));
72 NetworkInterface::~NetworkInterface()
74 deletePointers(m_out_vc_state
);
75 deletePointers(m_ni_buffers
);
80 NetworkInterface::addInPort(NetworkLink
*in_link
)
83 in_link
->setLinkConsumer(this);
87 NetworkInterface::addOutPort(NetworkLink
*out_link
)
89 outNetLink
= out_link
;
90 outSrcQueue
= new flitBuffer();
91 out_link
->setSourceQueue(outSrcQueue
);
92 out_link
->setSource(this);
96 NetworkInterface::addNode(vector
<MessageBuffer
*>& in
,
97 vector
<MessageBuffer
*>& out
)
99 assert(in
.size() == m_virtual_networks
);
103 // protocol injects messages into the NI
104 for (int j
= 0; j
< m_virtual_networks
; j
++) {
105 inNode_ptr
[j
]->setConsumer(this);
106 inNode_ptr
[j
]->setReceiver(this);
107 outNode_ptr
[j
]->setSender(this);
112 NetworkInterface::request_vc(int in_vc
, int in_port
, NetDest destination
,
115 inNetLink
->grant_vc_link(in_vc
, request_time
);
119 NetworkInterface::flitisizeMessage(MsgPtr msg_ptr
, int vnet
)
121 NetworkMessage
*net_msg_ptr
= safe_cast
<NetworkMessage
*>(msg_ptr
.get());
122 NetDest net_msg_dest
= net_msg_ptr
->getInternalDestination();
124 // get all the destinations associated with this message.
125 vector
<NodeID
> dest_nodes
= net_msg_dest
.getAllDest();
127 // Number of flits is dependent on the link bandwidth available.
128 // This is expressed in terms of bytes/cycle or the flit size
130 int num_flits
= (int) ceil((double) m_net_ptr
->MessageSizeType_to_int(
131 net_msg_ptr
->getMessageSize())/m_net_ptr
->getNiFlitSize());
133 // loop to convert all multicast messages into unicast messages
134 for (int ctr
= 0; ctr
< dest_nodes
.size(); ctr
++) {
135 int vc
= calculateVC(vnet
); // this will return a free output vc
138 // did not find a free output vc
141 MsgPtr new_msg_ptr
= msg_ptr
->clone();
142 NodeID destID
= dest_nodes
[ctr
];
144 NetworkMessage
*new_net_msg_ptr
=
145 safe_cast
<NetworkMessage
*>(new_msg_ptr
.get());
146 if (dest_nodes
.size() > 1) {
147 NetDest personal_dest
;
148 for (int m
= 0; m
< (int) MachineType_NUM
; m
++) {
149 if ((destID
>= MachineType_base_number((MachineType
) m
)) &&
150 destID
< MachineType_base_number((MachineType
) (m
+1))) {
151 // calculating the NetDest associated with this destID
152 personal_dest
.clear();
153 personal_dest
.add((MachineID
) {(MachineType
) m
, (destID
-
154 MachineType_base_number((MachineType
) m
))});
155 new_net_msg_ptr
->getInternalDestination() = personal_dest
;
159 net_msg_dest
.removeNetDest(personal_dest
);
161 // removing the destination from the original message to reflect
162 // that a message with this particular destination has been
163 // flitisized and an output vc is acquired
164 net_msg_ptr
->getInternalDestination().removeNetDest(personal_dest
);
166 for (int i
= 0; i
< num_flits
; i
++) {
167 m_net_ptr
->increment_injected_flits(vnet
);
168 flit
*fl
= new flit(i
, vc
, vnet
, num_flits
, new_msg_ptr
,
170 fl
->set_delay(curCycle() - ticksToCycles(msg_ptr
->getTime()));
171 m_ni_buffers
[vc
]->insert(fl
);
174 m_out_vc_state
[vc
]->setState(VC_AB_
, curCycle());
176 // setting an output vc request for the next hop.
177 // This flit will be ready to traverse the link and into the next hop
178 // only when an output vc is acquired at the next hop
179 outNetLink
->request_vc_link(
180 vc
, new_net_msg_ptr
->getInternalDestination(), curCycle());
186 // An output vc has been granted at the next hop to one of the vc's.
187 // We have to update the state of the vc to reflect this
189 NetworkInterface::grant_vc(int out_port
, int vc
, Cycles grant_time
)
191 assert(m_out_vc_state
[vc
]->isInState(VC_AB_
, grant_time
));
192 m_out_vc_state
[vc
]->grant_vc(grant_time
);
193 scheduleEvent(Cycles(1));
196 // The tail flit corresponding to this vc has been buffered at the next hop
197 // and thus this vc is now free
199 NetworkInterface::release_vc(int out_port
, int vc
, Cycles release_time
)
201 assert(m_out_vc_state
[vc
]->isInState(ACTIVE_
, release_time
));
202 m_out_vc_state
[vc
]->setState(IDLE_
, release_time
);
203 scheduleEvent(Cycles(1));
206 // Looking for a free output vc
208 NetworkInterface::calculateVC(int vnet
)
211 if (m_net_ptr
->isVNetOrdered(vnet
))
214 vc_per_vnet
= m_vc_per_vnet
;
216 for (int i
= 0; i
< vc_per_vnet
; i
++) {
217 int delta
= m_vc_allocator
[vnet
];
218 m_vc_allocator
[vnet
]++;
219 if (m_vc_allocator
[vnet
] == vc_per_vnet
)
220 m_vc_allocator
[vnet
] = 0;
222 if (m_out_vc_state
[(vnet
*m_vc_per_vnet
) + delta
]->
223 isInState(IDLE_
, curCycle())) {
224 return ((vnet
*m_vc_per_vnet
) + delta
);
231 * The NI wakeup checks whether there are any ready messages in the protocol
232 * buffer. If yes, it picks that up, flitisizes it into a number of flits and
233 * puts it into an output buffer and schedules the output link.
234 * On a wakeup it also checks whether there are flits in the input link.
235 * If yes, it picks them up and if the flit is a tail, the NI inserts the
236 * corresponding message into the protocol buffer.
240 NetworkInterface::wakeup()
244 //Checking for messages coming from the protocol
245 // can pick up a message/cycle for each virtual net
246 for (int vnet
= 0; vnet
< m_virtual_networks
; vnet
++) {
247 while (inNode_ptr
[vnet
]->isReady()) // Is there a message waiting
249 msg_ptr
= inNode_ptr
[vnet
]->peekMsgPtr();
250 if (flitisizeMessage(msg_ptr
, vnet
)) {
251 inNode_ptr
[vnet
]->dequeue();
258 scheduleOutputLink();
261 /*********** Picking messages destined for this NI **********/
263 if (inNetLink
->isReady()) {
264 flit
*t_flit
= inNetLink
->consumeLink();
265 if (t_flit
->get_type() == TAIL_
|| t_flit
->get_type() == HEAD_TAIL_
) {
266 DPRINTF(RubyNetwork
, "m_id: %d, Message delivered at time: %lld\n",
269 outNode_ptr
[t_flit
->get_vnet()]->enqueue(
270 t_flit
->get_msg_ptr(), Cycles(1));
272 // signal the upstream router that this vc can be freed now
273 inNetLink
->release_vc_link(t_flit
->get_vc(),
274 curCycle() + Cycles(1));
277 int vnet
= t_flit
->get_vnet();
278 m_net_ptr
->increment_received_flits(vnet
);
279 Cycles network_delay
= curCycle() - t_flit
->get_enqueue_time();
280 Cycles queueing_delay
= t_flit
->get_delay();
282 m_net_ptr
->increment_network_latency(network_delay
, vnet
);
283 m_net_ptr
->increment_queueing_latency(queueing_delay
, vnet
);
288 /* This function looks at the NI buffers and if some buffer has flits which
289 * are ready to traverse the link in the next cycle and also the downstream
290 * output vc associated with this flit has buffers left, the link is scheduled
295 NetworkInterface::scheduleOutputLink()
297 int vc
= m_vc_round_robin
;
299 if (m_vc_round_robin
== m_num_vcs
)
300 m_vc_round_robin
= 0;
302 for (int i
= 0; i
< m_num_vcs
; i
++) {
306 if (m_ni_buffers
[vc
]->isReady(curCycle())) {
307 if (m_out_vc_state
[vc
]->isInState(ACTIVE_
, curCycle()) &&
308 outNetLink
->isBufferNotFull_link(vc
)) { // buffer backpressure
310 // Just removing the flit
311 flit
*t_flit
= m_ni_buffers
[vc
]->getTopFlit();
312 t_flit
->set_time(curCycle() + Cycles(1));
313 outSrcQueue
->insert(t_flit
);
315 // schedule the out link
317 scheduleEventAbsolute(clockEdge(Cycles(1)));
325 NetworkInterface::checkReschedule()
327 for (int vnet
= 0; vnet
< m_virtual_networks
; vnet
++) {
328 if (inNode_ptr
[vnet
]->isReady()) { // Is there a message waiting
329 scheduleEvent(Cycles(1));
333 for (int vc
= 0; vc
< m_num_vcs
; vc
++) {
334 if (m_ni_buffers
[vc
]->isReadyForNext(curCycle())) {
335 scheduleEvent(Cycles(1));
342 NetworkInterface::functionalRead(Packet
*pkt
)
344 // Go through the internal buffers
345 for (unsigned int i
= 0; i
< m_ni_buffers
.size(); ++i
) {
346 if (m_ni_buffers
[i
]->functionalRead(pkt
)) {
351 // Go through the buffer between this network interface and the router
352 if (outSrcQueue
->functionalRead(pkt
)) {
360 NetworkInterface::functionalWrite(Packet
*pkt
)
362 uint32_t num_functional_writes
= 0;
363 for (unsigned int i
= 0; i
< m_ni_buffers
.size(); ++i
) {
364 num_functional_writes
+= m_ni_buffers
[i
]->functionalWrite(pkt
);
367 num_functional_writes
+= outSrcQueue
->functionalWrite(pkt
);
368 return num_functional_writes
;
372 NetworkInterface::print(std::ostream
& out
) const
374 out
<< "[Network Interface]";
378 GarnetNetworkInterfaceParams::create()
380 return new NetworkInterface(this);