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/garnet2.0/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");
67 lenBuffer
.resize(p
->vcs_per_vnet
* p
->virt_nets
);
68 sizeSent
.resize(p
->vcs_per_vnet
* p
->virt_nets
);
69 flitsSent
.resize(p
->vcs_per_vnet
* p
->virt_nets
);
70 extraCredit
.resize(p
->vcs_per_vnet
* p
->virt_nets
);
74 NetworkBridge::initBridge(NetworkBridge
*coBrid
, bool cdc_en
, bool serdes_en
)
81 NetworkBridge::~NetworkBridge()
86 NetworkBridge::scheduleFlit(flit
*t_flit
, Cycles latency
)
88 Cycles totLatency
= latency
;
91 // Add the CDC latency
92 totLatency
= latency
+ cdcLatency
;
95 Tick sendTime
= link_consumer
->getObject()->clockEdge(totLatency
);
96 Tick nextAvailTick
= lastScheduledAt
+ link_consumer
->getObject()->\
97 cyclesToTicks(Cycles(1));
98 sendTime
= std::max(nextAvailTick
, sendTime
);
99 t_flit
->set_time(sendTime
);
100 lastScheduledAt
= sendTime
;
101 linkBuffer
.insert(t_flit
);
102 link_consumer
->scheduleEventAbsolute(sendTime
);
106 NetworkBridge::neutralize(int vc
, int eCredit
)
108 extraCredit
[vc
].push(eCredit
);
112 NetworkBridge::flitisizeAndSend(flit
*t_flit
)
114 // Serialize-Deserialize only if it is enabled
116 // Calculate the target-width
117 int target_width
= bitWidth
;
118 int cur_width
= nLink
->bitWidth
;
119 if (mType
== Enums::OBJECT_LINK
) {
120 target_width
= nLink
->bitWidth
;
121 cur_width
= bitWidth
;
124 DPRINTF(RubyNetwork
, "Target width: %d Current: %d\n",
125 target_width
, cur_width
);
126 assert(target_width
!= cur_width
);
128 int vc
= t_flit
->get_vc();
130 if (target_width
> cur_width
) {
132 // This deserializer combines flits from the
133 // same message together
135 int flitPossible
= 0;
136 if (t_flit
->get_type() == CREDIT_
) {
138 assert(extraCredit
[vc
].front());
139 if (lenBuffer
[vc
] == extraCredit
[vc
].front()) {
141 extraCredit
[vc
].pop();
144 } else if (t_flit
->get_type() == TAIL_
||
145 t_flit
->get_type() == HEAD_TAIL_
) {
146 // If its the end of packet, then send whatever
148 int sizeAvail
= (t_flit
->msgSize
- sizeSent
[vc
]);
149 flitPossible
= ceil((float)sizeAvail
/(float)target_width
);
150 assert (flitPossible
< 2);
151 num_flits
= (t_flit
->get_id() + 1) - flitsSent
[vc
];
152 // Stop tracking the packet.
156 // If we are yet to receive the complete packet
157 // track the size recieved and flits deserialized.
159 ((t_flit
->get_id() + 1)*cur_width
) - sizeSent
[vc
];
160 flitPossible
= floor((float)sizeAvail
/(float)target_width
);
161 assert (flitPossible
< 2);
162 num_flits
= (t_flit
->get_id() + 1) - flitsSent
[vc
];
164 sizeSent
[vc
] += target_width
;
165 flitsSent
[vc
] = t_flit
->get_id() + 1;
169 DPRINTF(RubyNetwork
, "Deserialize :%dB -----> %dB "
170 " vc:%d\n", cur_width
, target_width
, vc
);
174 fl
= t_flit
->deserialize(lenBuffer
[vc
], num_flits
,
178 // Inform the credit serializer about the number
179 // of flits that were generated.
180 if (t_flit
->get_type() != CREDIT_
&& fl
) {
181 coBridge
->neutralize(vc
, num_flits
);
184 // Schedule only if we are done deserializing
186 DPRINTF(RubyNetwork
, "Scheduling a flit\n");
188 scheduleFlit(fl
, serDesLatency
);
190 // Delete this flit, new flit is sent in any case
194 DPRINTF(RubyNetwork
, "Serializing flit :%d -----> %d "
195 "(vc:%d, Original Message Size: %d)\n",
196 cur_width
, target_width
, vc
, t_flit
->msgSize
);
198 int flitPossible
= 0;
199 if (t_flit
->get_type() == CREDIT_
) {
200 // We store the deserialization ratio and then
201 // access it when serializing credits in the
202 // oppposite direction.
203 assert(extraCredit
[vc
].front());
204 flitPossible
= extraCredit
[vc
].front();
205 extraCredit
[vc
].pop();
206 } else if (t_flit
->get_type() == HEAD_
||
207 t_flit
->get_type() == BODY_
) {
209 ((t_flit
->get_id() + 1)*cur_width
) - sizeSent
[vc
];
210 flitPossible
= floor((float)sizeAvail
/(float)target_width
);
212 sizeSent
[vc
] += flitPossible
*target_width
;
213 flitsSent
[vc
] += flitPossible
;
216 int sizeAvail
= t_flit
->msgSize
- sizeSent
[vc
];
217 flitPossible
= ceil((float)sizeAvail
/(float)target_width
);
221 assert(flitPossible
> 0);
223 // Schedule all the flits
224 // num_flits could be zero for credits
225 for (int i
= 0; i
< flitPossible
; i
++) {
226 // Ignore neutralized credits
227 flit
*fl
= t_flit
->serialize(i
, flitPossible
, target_width
);
228 scheduleFlit(fl
, serDesLatency
);
229 DPRINTF(RubyNetwork
, "Serialized to flit[%d of %d parts]:"
230 " %s\n", i
+1, flitPossible
, *fl
);
233 if (t_flit
->get_type() != CREDIT_
) {
234 coBridge
->neutralize(vc
, flitPossible
);
236 // Delete this flit, new flit is sent in any case
242 // If only CDC is enabled schedule it
243 scheduleFlit(t_flit
, Cycles(0));
246 NetworkBridge::wakeup()
250 if (link_srcQueue
->isReady(curTick())) {
251 t_flit
= link_srcQueue
->getTopFlit();
252 DPRINTF(RubyNetwork
, "Recieved flit %s\n", *t_flit
);
253 flitisizeAndSend(t_flit
);
256 assert(!link_srcQueue
->getSize());
260 NetworkBridgeParams::create()
262 return new NetworkBridge(this);