misc: Delete the now unnecessary create methods.
[gem5.git] / src / mem / ruby / network / garnet / NetworkBridge.cc
1 /*
2 * Copyright (c) 2020 Advanced Micro Devices, Inc.
3 * All rights reserved.
4 *
5 * For use for simulation and test purposes only
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the copyright holder nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 *
33 * Authors: Srikant Bharadwaj
34 */
35
36
37 #include "mem/ruby/network/garnet/NetworkBridge.hh"
38
39 #include <cmath>
40
41 #include "debug/RubyNetwork.hh"
42 #include "params/GarnetIntLink.hh"
43
44 NetworkBridge::NetworkBridge(const Params &p)
45 :CreditLink(p)
46 {
47 enCdc = true;
48 enSerDes = true;
49 mType = p.vtype;
50
51 cdcLatency = p.cdc_latency;
52 serDesLatency = p.serdes_latency;
53 lastScheduledAt = 0;
54
55 nLink = p.link;
56 if (mType == Enums::LINK_OBJECT) {
57 nLink->setLinkConsumer(this);
58 setSourceQueue(nLink->getBuffer(), nLink);
59 } else if (mType == Enums::OBJECT_LINK) {
60 nLink->setSourceQueue(&linkBuffer, this);
61 setLinkConsumer(nLink);
62 } else {
63 // CDC type must be set
64 panic("CDC type must be set");
65 }
66 }
67
68 void
69 NetworkBridge::setVcsPerVnet(uint32_t consumerVcs)
70 {
71 DPRINTF(RubyNetwork, "VcsPerVnet VC: %d\n", consumerVcs);
72 NetworkLink::setVcsPerVnet(consumerVcs);
73 lenBuffer.resize(consumerVcs * m_virt_nets);
74 sizeSent.resize(consumerVcs * m_virt_nets);
75 flitsSent.resize(consumerVcs * m_virt_nets);
76 extraCredit.resize(consumerVcs * m_virt_nets);
77
78 nLink->setVcsPerVnet(consumerVcs);
79 }
80
81 void
82 NetworkBridge::initBridge(NetworkBridge *coBrid, bool cdc_en, bool serdes_en)
83 {
84 coBridge = coBrid;
85 enCdc = cdc_en;
86 enSerDes = serdes_en;
87 }
88
89 NetworkBridge::~NetworkBridge()
90 {
91 }
92
93 void
94 NetworkBridge::scheduleFlit(flit *t_flit, Cycles latency)
95 {
96 Cycles totLatency = latency;
97
98 if (enCdc) {
99 // Add the CDC latency
100 totLatency = latency + cdcLatency;
101 }
102
103 Tick sendTime = link_consumer->getObject()->clockEdge(totLatency);
104 Tick nextAvailTick = lastScheduledAt + link_consumer->getObject()->\
105 cyclesToTicks(Cycles(1));
106 sendTime = std::max(nextAvailTick, sendTime);
107 t_flit->set_time(sendTime);
108 lastScheduledAt = sendTime;
109 linkBuffer.insert(t_flit);
110 link_consumer->scheduleEventAbsolute(sendTime);
111 }
112
113 void
114 NetworkBridge::neutralize(int vc, int eCredit)
115 {
116 extraCredit[vc].push(eCredit);
117 }
118
119 void
120 NetworkBridge::flitisizeAndSend(flit *t_flit)
121 {
122 // Serialize-Deserialize only if it is enabled
123 if (enSerDes) {
124 // Calculate the target-width
125 int target_width = bitWidth;
126 int cur_width = nLink->bitWidth;
127 if (mType == Enums::OBJECT_LINK) {
128 target_width = nLink->bitWidth;
129 cur_width = bitWidth;
130 }
131
132 DPRINTF(RubyNetwork, "Target width: %d Current: %d\n",
133 target_width, cur_width);
134 assert(target_width != cur_width);
135
136 int vc = t_flit->get_vc();
137
138 if (target_width > cur_width) {
139 // Deserialize
140 // This deserializer combines flits from the
141 // same message together
142 int num_flits = 0;
143 int flitPossible = 0;
144 if (t_flit->get_type() == CREDIT_) {
145 lenBuffer[vc]++;
146 assert(extraCredit[vc].front());
147 if (lenBuffer[vc] == extraCredit[vc].front()) {
148 flitPossible = 1;
149 extraCredit[vc].pop();
150 lenBuffer[vc] = 0;
151 }
152 } else if (t_flit->get_type() == TAIL_ ||
153 t_flit->get_type() == HEAD_TAIL_) {
154 // If its the end of packet, then send whatever
155 // is available.
156 int sizeAvail = (t_flit->msgSize - sizeSent[vc]);
157 flitPossible = ceil((float)sizeAvail/(float)target_width);
158 assert (flitPossible < 2);
159 num_flits = (t_flit->get_id() + 1) - flitsSent[vc];
160 // Stop tracking the packet.
161 flitsSent[vc] = 0;
162 sizeSent[vc] = 0;
163 } else {
164 // If we are yet to receive the complete packet
165 // track the size recieved and flits deserialized.
166 int sizeAvail =
167 ((t_flit->get_id() + 1)*cur_width) - sizeSent[vc];
168 flitPossible = floor((float)sizeAvail/(float)target_width);
169 assert (flitPossible < 2);
170 num_flits = (t_flit->get_id() + 1) - flitsSent[vc];
171 if (flitPossible) {
172 sizeSent[vc] += target_width;
173 flitsSent[vc] = t_flit->get_id() + 1;
174 }
175 }
176
177 DPRINTF(RubyNetwork, "Deserialize :%dB -----> %dB "
178 " vc:%d\n", cur_width, target_width, vc);
179
180 flit *fl = NULL;
181 if (flitPossible) {
182 fl = t_flit->deserialize(lenBuffer[vc], num_flits,
183 target_width);
184 }
185
186 // Inform the credit serializer about the number
187 // of flits that were generated.
188 if (t_flit->get_type() != CREDIT_ && fl) {
189 coBridge->neutralize(vc, num_flits);
190 }
191
192 // Schedule only if we are done deserializing
193 if (fl) {
194 DPRINTF(RubyNetwork, "Scheduling a flit\n");
195 lenBuffer[vc] = 0;
196 scheduleFlit(fl, serDesLatency);
197 }
198 // Delete this flit, new flit is sent in any case
199 delete t_flit;
200 } else {
201 // Serialize
202 DPRINTF(RubyNetwork, "Serializing flit :%d -----> %d "
203 "(vc:%d, Original Message Size: %d)\n",
204 cur_width, target_width, vc, t_flit->msgSize);
205
206 int flitPossible = 0;
207 if (t_flit->get_type() == CREDIT_) {
208 // We store the deserialization ratio and then
209 // access it when serializing credits in the
210 // oppposite direction.
211 assert(extraCredit[vc].front());
212 flitPossible = extraCredit[vc].front();
213 extraCredit[vc].pop();
214 } else if (t_flit->get_type() == HEAD_ ||
215 t_flit->get_type() == BODY_) {
216 int sizeAvail =
217 ((t_flit->get_id() + 1)*cur_width) - sizeSent[vc];
218 flitPossible = floor((float)sizeAvail/(float)target_width);
219 if (flitPossible) {
220 sizeSent[vc] += flitPossible*target_width;
221 flitsSent[vc] += flitPossible;
222 }
223 } else {
224 int sizeAvail = t_flit->msgSize - sizeSent[vc];
225 flitPossible = ceil((float)sizeAvail/(float)target_width);
226 sizeSent[vc] = 0;
227 flitsSent[vc] = 0;
228 }
229 assert(flitPossible > 0);
230
231 // Schedule all the flits
232 // num_flits could be zero for credits
233 for (int i = 0; i < flitPossible; i++) {
234 // Ignore neutralized credits
235 flit *fl = t_flit->serialize(i, flitPossible, target_width);
236 scheduleFlit(fl, serDesLatency);
237 DPRINTF(RubyNetwork, "Serialized to flit[%d of %d parts]:"
238 " %s\n", i+1, flitPossible, *fl);
239 }
240
241 if (t_flit->get_type() != CREDIT_) {
242 coBridge->neutralize(vc, flitPossible);
243 }
244 // Delete this flit, new flit is sent in any case
245 delete t_flit;
246 }
247 return;
248 }
249
250 // If only CDC is enabled schedule it
251 scheduleFlit(t_flit, Cycles(0));
252 }
253 void
254 NetworkBridge::wakeup()
255 {
256 flit *t_flit;
257
258 if (link_srcQueue->isReady(curTick())) {
259 t_flit = link_srcQueue->getTopFlit();
260 DPRINTF(RubyNetwork, "Recieved flit %s\n", *t_flit);
261 flitisizeAndSend(t_flit);
262 return;
263 }
264 assert(!link_srcQueue->getSize());
265 }