gem5 v24.0.0.0
Loading...
Searching...
No Matches
serial_link.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2011-2013 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2006 The Regents of The University of Michigan
15 * Copyright (c) 2015 The University of Bologna
16 * All rights reserved.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions are
20 * met: redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer;
22 * redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution;
25 * neither the name of the copyright holders nor the names of its
26 * contributors may be used to endorse or promote products derived from
27 * this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 */
41
48#include "mem/serial_link.hh"
49
50#include "base/trace.hh"
51#include "debug/SerialLink.hh"
52#include "params/SerialLink.hh"
53
54namespace gem5
55{
56
58SerialLinkResponsePort(const std::string& _name,
59 SerialLink& _serial_link,
60 SerialLinkRequestPort& _mem_side_port,
61 Cycles _delay, int _resp_limit,
63 _ranges)
64 : ResponsePort(_name), serial_link(_serial_link),
65 mem_side_port(_mem_side_port), delay(_delay),
66 ranges(_ranges.begin(), _ranges.end()),
67 outstandingResponses(0), retryReq(false),
68 respQueueLimit(_resp_limit),
69 sendEvent([this]{ trySendTiming(); }, _name)
70{
71}
72
74 _name, SerialLink& _serial_link,
76 _cpu_side_port, Cycles _delay,
77 int _req_limit)
78 : RequestPort(_name), serial_link(_serial_link),
79 cpu_side_port(_cpu_side_port), delay(_delay), reqQueueLimit(_req_limit),
80 sendEvent([this]{ trySendTiming(); }, _name)
81{
82}
83
84SerialLink::SerialLink(const SerialLinkParams &p)
86 cpu_side_port(p.name + ".cpu_side_port", *this, mem_side_port,
87 ticksToCycles(p.delay), p.resp_size, p.ranges),
88 mem_side_port(p.name + ".mem_side_port", *this, cpu_side_port,
89 ticksToCycles(p.delay), p.req_size),
92{
93}
94
95Port&
96SerialLink::getPort(const std::string &if_name, PortID idx)
97{
98 if (if_name == "mem_side_port")
99 return mem_side_port;
100 else if (if_name == "cpu_side_port")
101 return cpu_side_port;
102 else
103 // pass it along to our super class
104 return ClockedObject::getPort(if_name, idx);
105}
106
107void
109{
110 // make sure both sides are connected and have the same block size
112 fatal("Both ports of a serial_link must be connected.\n");
113
114 // notify the request side of our address ranges
116}
117
118bool
123
124bool
126{
127 return transmitList.size() == reqQueueLimit;
128}
129
130bool
132{
133 // all checks are done when the request is accepted on the response
134 // side, so we are guaranteed to have space for the response
135 DPRINTF(SerialLink, "recvTimingResp: %s addr 0x%x\n",
136 pkt->cmdString(), pkt->getAddr());
137
138 DPRINTF(SerialLink, "Request queue size: %d\n", transmitList.size());
139
140 // @todo: We need to pay for this and not just zero it out
141 pkt->headerDelay = pkt->payloadDelay = 0;
142
143 // This is similar to what happens for the request packets:
144 // The serializer will start serialization as soon as it receives the
145 // first flit, but the deserializer (at the host side in this case), will
146 // have to wait to receive the whole packet. So we only account for the
147 // deserialization latency.
148 Cycles cycles = delay;
149 cycles += Cycles(divCeil(pkt->getSize() * 8, serial_link.num_lanes
150 * serial_link.link_speed));
151 Tick t = serial_link.clockEdge(cycles);
152
153 //@todo: If the processor sends two uncached requests towards HMC and the
154 // second one is smaller than the first one. It may happen that the second
155 // one crosses this link faster than the first one (because the packet
156 // waits in the link based on its size). This can reorder the received
157 // response.
159
160 return true;
161}
162
163bool
165{
166 DPRINTF(SerialLink, "recvTimingReq: %s addr 0x%x\n",
167 pkt->cmdString(), pkt->getAddr());
168
169 // we should not see a timing request if we are already in a retry
170 assert(!retryReq);
171
172 DPRINTF(SerialLink, "Response queue size: %d outresp: %d\n",
173 transmitList.size(), outstandingResponses);
174
175 // if the request queue is full then there is no hope
177 DPRINTF(SerialLink, "Request queue full\n");
178 retryReq = true;
179 } else if ( !retryReq ) {
180 // look at the response queue if we expect to see a response
181 bool expects_response = pkt->needsResponse() &&
182 !pkt->cacheResponding();
183 if (expects_response) {
184 if (respQueueFull()) {
185 DPRINTF(SerialLink, "Response queue full\n");
186 retryReq = true;
187 } else {
188 // ok to send the request with space for the response
189 DPRINTF(SerialLink, "Reserving space for response\n");
190 assert(outstandingResponses != respQueueLimit);
191 ++outstandingResponses;
192
193 // no need to set retryReq to false as this is already the
194 // case
195 }
196 }
197
198 if (!retryReq) {
199 // @todo: We need to pay for this and not just zero it out
200 pkt->headerDelay = pkt->payloadDelay = 0;
201
202 // We assume that the serializer component at the transmitter side
203 // does not need to receive the whole packet to start the
204 // serialization (this assumption is consistent with the HMC
205 // standard). But the deserializer waits for the complete packet
206 // to check its integrity first. So everytime a packet crosses a
207 // serial link, we should account for its deserialization latency
208 // only.
209 Cycles cycles = delay;
210 cycles += Cycles(divCeil(pkt->getSize() * 8,
211 serial_link.num_lanes * serial_link.link_speed));
212 Tick t = serial_link.clockEdge(cycles);
213
214 //@todo: If the processor sends two uncached requests towards HMC
215 // and the second one is smaller than the first one. It may happen
216 // that the second one crosses this link faster than the first one
217 // (because the packet waits in the link based on its size).
218 // This can reorder the received response.
220 }
221 }
222
223 // remember that we are now stalling a packet and that we have to
224 // tell the sending requestor to retry once space becomes available,
225 // we make no distinction whether the stalling is due to the
226 // request queue or response queue being full
227 return !retryReq;
228}
229
230void
232{
233 if (retryReq) {
234 DPRINTF(SerialLink, "Request waiting for retry, now retrying\n");
235 retryReq = false;
236 sendRetryReq();
237 }
238}
239
240void
242{
243 // If we're about to put this packet at the head of the queue, we
244 // need to schedule an event to do the transmit. Otherwise there
245 // should already be an event scheduled for sending the head
246 // packet.
247 if (transmitList.empty()) {
248 serial_link.schedule(sendEvent, when);
249 }
250
251 assert(transmitList.size() != reqQueueLimit);
252
253 transmitList.emplace_back(DeferredPacket(pkt, when));
254}
255
256
257void
259{
260 // If we're about to put this packet at the head of the queue, we
261 // need to schedule an event to do the transmit. Otherwise there
262 // should already be an event scheduled for sending the head
263 // packet.
264 if (transmitList.empty()) {
265 serial_link.schedule(sendEvent, when);
266 }
267
268 transmitList.emplace_back(DeferredPacket(pkt, when));
269}
270
271void
273{
274 assert(!transmitList.empty());
275
276 DeferredPacket req = transmitList.front();
277
278 assert(req.tick <= curTick());
279
280 PacketPtr pkt = req.pkt;
281
282 DPRINTF(SerialLink, "trySend request addr 0x%x, queue size %d\n",
283 pkt->getAddr(), transmitList.size());
284
285 if (sendTimingReq(pkt)) {
286 // send successful
287 transmitList.pop_front();
288
289 DPRINTF(SerialLink, "trySend request successful\n");
290
291 // If there are more packets to send, schedule event to try again.
292 if (!transmitList.empty()) {
293 DeferredPacket next_req = transmitList.front();
294 DPRINTF(SerialLink, "Scheduling next send\n");
295
296 // Make sure bandwidth limitation is met
297 Cycles cycles = Cycles(divCeil(pkt->getSize() * 8,
298 serial_link.num_lanes * serial_link.link_speed));
299 Tick t = serial_link.clockEdge(cycles);
300 serial_link.schedule(sendEvent, std::max(next_req.tick, t));
301 }
302
303 // if we have stalled a request due to a full request queue,
304 // then send a retry at this point, also note that if the
305 // request we stalled was waiting for the response queue
306 // rather than the request queue we might stall it again
308 }
309
310 // if the send failed, then we try again once we receive a retry,
311 // and therefore there is no need to take any action
312}
313
314void
316{
317 assert(!transmitList.empty());
318
319 DeferredPacket resp = transmitList.front();
320
321 assert(resp.tick <= curTick());
322
323 PacketPtr pkt = resp.pkt;
324
325 DPRINTF(SerialLink, "trySend response addr 0x%x, outstanding %d\n",
326 pkt->getAddr(), outstandingResponses);
327
328 if (sendTimingResp(pkt)) {
329 // send successful
330 transmitList.pop_front();
331 DPRINTF(SerialLink, "trySend response successful\n");
332
333 assert(outstandingResponses != 0);
334 --outstandingResponses;
335
336 // If there are more packets to send, schedule event to try again.
337 if (!transmitList.empty()) {
338 DeferredPacket next_resp = transmitList.front();
339 DPRINTF(SerialLink, "Scheduling next send\n");
340
341 // Make sure bandwidth limitation is met
342 Cycles cycles = Cycles(divCeil(pkt->getSize() * 8,
343 serial_link.num_lanes * serial_link.link_speed));
344 Tick t = serial_link.clockEdge(cycles);
345 serial_link.schedule(sendEvent, std::max(next_resp.tick, t));
346 }
347
348 // if there is space in the request queue and we were stalling
349 // a request, it will definitely be possible to accept it now
350 // since there is guaranteed space in the response queue
351 if (!mem_side_port.reqQueueFull() && retryReq) {
352 DPRINTF(SerialLink, "Request waiting for retry, now retrying\n");
353 retryReq = false;
354 sendRetryReq();
355 }
356 }
357
358 // if the send failed, then we try again once we receive a retry,
359 // and therefore there is no need to take any action
360}
361
362void
364{
365 trySendTiming();
366}
367
368void
373
374Tick
376{
377 return delay * serial_link.clockPeriod() + mem_side_port.sendAtomic(pkt);
378}
379
380void
382{
383 pkt->pushLabel(name());
384
385 // check the response queue
386 for (auto i = transmitList.begin(); i != transmitList.end(); ++i) {
387 if (pkt->trySatisfyFunctional((*i).pkt)) {
388 pkt->makeResponse();
389 return;
390 }
391 }
392
393 // also check the memory-side port's request queue
395 return;
396 }
397
398 pkt->popLabel();
399
400 // fall through if pkt still not satisfied
402}
403
404bool
406{
407 bool found = false;
408 auto i = transmitList.begin();
409
410 while (i != transmitList.end() && !found) {
411 if (pkt->trySatisfyFunctional((*i).pkt)) {
412 pkt->makeResponse();
413 found = true;
414 }
415 ++i;
416 }
417
418 return found;
419}
420
423{
424 return ranges;
425}
426
427} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:210
The ClockedObject class extends the SimObject with a clock and accessor functions to relate ticks to ...
Cycles ticksToCycles(Tick t) const
Cycles is a wrapper class for representing cycle counts, i.e.
Definition types.hh:79
const std::string _name
Definition named.hh:41
virtual std::string name() const
Definition named.hh:47
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition packet.hh:295
Addr getAddr() const
Definition packet.hh:807
void pushLabel(const std::string &lbl)
Push label for PrintReq (safe to call unconditionally).
Definition packet.hh:1470
const std::string & cmdString() const
Return the string name of the cmd field (for debugging and tracing).
Definition packet.hh:588
bool needsResponse() const
Definition packet.hh:608
uint32_t payloadDelay
The extra pipelining delay from seeing the packet until the end of payload is transmitted by the comp...
Definition packet.hh:449
void makeResponse()
Take a request packet and modify it in place to be suitable for returning as a response to that reque...
Definition packet.hh:1062
uint32_t headerDelay
The extra delay from seeing the packet until the header is transmitted.
Definition packet.hh:431
bool trySatisfyFunctional(PacketPtr other)
Check a functional request against a memory value stored in another packet (i.e.
Definition packet.hh:1399
unsigned getSize() const
Definition packet.hh:817
void popLabel()
Pop label for PrintReq (safe to call unconditionally).
Definition packet.hh:1480
bool cacheResponding() const
Definition packet.hh:659
Ports are used to interface objects to each other.
Definition port.hh:62
bool isConnected() const
Is this port currently connected to a peer?
Definition port.hh:133
A RequestPort is a specialisation of a Port, which implements the default protocol for the three diff...
Definition port.hh:136
Tick sendAtomic(PacketPtr pkt)
Send an atomic request packet, where the data is moved and the state is updated in zero time,...
Definition port.hh:552
void sendFunctional(PacketPtr pkt) const
Send a functional request packet, where the data is instantly updated everywhere in the memory system...
Definition port.hh:579
A ResponsePort is a specialization of a port.
Definition port.hh:349
void sendRangeChange() const
Called by the owner to send a range change.
Definition port.hh:380
STL vector class.
Definition stl.hh:37
static constexpr T divCeil(const T &a, const U &b)
Definition intmath.hh:110
#define fatal(...)
This implements a cprintf based fatal() function.
Definition logging.hh:200
virtual Port & getPort(const std::string &if_name, PortID idx=InvalidPortID)
Get a port with a given name and index.
Bitfield< 5 > t
Definition misc_types.hh:71
Bitfield< 7 > i
Definition misc_types.hh:67
void sendEvent(ThreadContext *tc)
Send an event (SEV) to a specific PE if there isn't already a pending event.
Definition utility.cc:65
Bitfield< 0 > p
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
Tick curTick()
The universal simulation clock.
Definition cur_tick.hh:46
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
Definition types.hh:245
uint64_t Tick
Tick count type.
Definition types.hh:58

Generated on Tue Jun 18 2024 16:24:05 for gem5 by doxygen 1.11.0