2 * Copyright (c) 2020 Advanced Micro Devices, Inc.
5 * For use for simulation and test purposes only
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
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.
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.
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.
33 * Authors: Srikant Bharadwaj
37 #include "mem/ruby/network/garnet/NetworkBridge.hh"
41 #include "debug/RubyNetwork.hh"
42 #include "params/GarnetIntLink.hh"
44 NetworkBridge::NetworkBridge(const Params
&p
)
51 cdcLatency
= p
.cdc_latency
;
52 serDesLatency
= p
.serdes_latency
;
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
);
63 // CDC type must be set
64 panic("CDC type must be set");
69 NetworkBridge::setVcsPerVnet(uint32_t consumerVcs
)
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
);
78 nLink
->setVcsPerVnet(consumerVcs
);
82 NetworkBridge::initBridge(NetworkBridge
*coBrid
, bool cdc_en
, bool serdes_en
)
89 NetworkBridge::~NetworkBridge()
94 NetworkBridge::scheduleFlit(flit
*t_flit
, Cycles latency
)
96 Cycles totLatency
= latency
;
99 // Add the CDC latency
100 totLatency
= latency
+ cdcLatency
;
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
);
114 NetworkBridge::neutralize(int vc
, int eCredit
)
116 extraCredit
[vc
].push(eCredit
);
120 NetworkBridge::flitisizeAndSend(flit
*t_flit
)
122 // Serialize-Deserialize only if it is enabled
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
;
132 DPRINTF(RubyNetwork
, "Target width: %d Current: %d\n",
133 target_width
, cur_width
);
134 assert(target_width
!= cur_width
);
136 int vc
= t_flit
->get_vc();
138 if (target_width
> cur_width
) {
140 // This deserializer combines flits from the
141 // same message together
143 int flitPossible
= 0;
144 if (t_flit
->get_type() == CREDIT_
) {
146 assert(extraCredit
[vc
].front());
147 if (lenBuffer
[vc
] == extraCredit
[vc
].front()) {
149 extraCredit
[vc
].pop();
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
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.
164 // If we are yet to receive the complete packet
165 // track the size recieved and flits deserialized.
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
];
172 sizeSent
[vc
] += target_width
;
173 flitsSent
[vc
] = t_flit
->get_id() + 1;
177 DPRINTF(RubyNetwork
, "Deserialize :%dB -----> %dB "
178 " vc:%d\n", cur_width
, target_width
, vc
);
182 fl
= t_flit
->deserialize(lenBuffer
[vc
], num_flits
,
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
);
192 // Schedule only if we are done deserializing
194 DPRINTF(RubyNetwork
, "Scheduling a flit\n");
196 scheduleFlit(fl
, serDesLatency
);
198 // Delete this flit, new flit is sent in any case
202 DPRINTF(RubyNetwork
, "Serializing flit :%d -----> %d "
203 "(vc:%d, Original Message Size: %d)\n",
204 cur_width
, target_width
, vc
, t_flit
->msgSize
);
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_
) {
217 ((t_flit
->get_id() + 1)*cur_width
) - sizeSent
[vc
];
218 flitPossible
= floor((float)sizeAvail
/(float)target_width
);
220 sizeSent
[vc
] += flitPossible
*target_width
;
221 flitsSent
[vc
] += flitPossible
;
224 int sizeAvail
= t_flit
->msgSize
- sizeSent
[vc
];
225 flitPossible
= ceil((float)sizeAvail
/(float)target_width
);
229 assert(flitPossible
> 0);
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
);
241 if (t_flit
->get_type() != CREDIT_
) {
242 coBridge
->neutralize(vc
, flitPossible
);
244 // Delete this flit, new flit is sent in any case
250 // If only CDC is enabled schedule it
251 scheduleFlit(t_flit
, Cycles(0));
254 NetworkBridge::wakeup()
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
);
264 assert(!link_srcQueue
->getSize());