gem5  v20.0.0.3
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 
55  SerialLink& _serial_link,
56  SerialLinkMasterPort& _masterPort,
57  Cycles _delay, int _resp_limit,
59  _ranges)
60  : SlavePort(_name, &_serial_link), serial_link(_serial_link),
61  masterPort(_masterPort), delay(_delay),
62  ranges(_ranges.begin(), _ranges.end()),
63  outstandingResponses(0), retryReq(false),
64  respQueueLimit(_resp_limit),
65  sendEvent([this]{ trySendTiming(); }, _name)
66 {
67 }
68 
70  _name, SerialLink& _serial_link,
71  SerialLinkSlavePort& _slavePort,
72  Cycles _delay, int _req_limit)
73  : MasterPort(_name, &_serial_link), serial_link(_serial_link),
74  slavePort(_slavePort), delay(_delay), reqQueueLimit(_req_limit),
75  sendEvent([this]{ trySendTiming(); }, _name)
76 {
77 }
78 
79 SerialLink::SerialLink(SerialLinkParams *p)
80  : ClockedObject(p),
81  slavePort(p->name + ".slave", *this, masterPort,
82  ticksToCycles(p->delay), p->resp_size, p->ranges),
83  masterPort(p->name + ".master", *this, slavePort,
84  ticksToCycles(p->delay), p->req_size),
85  num_lanes(p->num_lanes),
87 
88 {
89 }
90 
91 Port&
92 SerialLink::getPort(const std::string &if_name, PortID idx)
93 {
94  if (if_name == "master")
95  return masterPort;
96  else if (if_name == "slave")
97  return slavePort;
98  else
99  // pass it along to our super class
100  return ClockedObject::getPort(if_name, idx);
101 }
102 
103 void
105 {
106  // make sure both sides are connected and have the same block size
108  fatal("Both ports of a serial_link must be connected.\n");
109 
110  // notify the master side of our address ranges
112 }
113 
114 bool
116 {
117  return outstandingResponses == respQueueLimit;
118 }
119 
120 bool
122 {
123  return transmitList.size() == reqQueueLimit;
124 }
125 
126 bool
128 {
129  // all checks are done when the request is accepted on the slave
130  // side, so we are guaranteed to have space for the response
131  DPRINTF(SerialLink, "recvTimingResp: %s addr 0x%x\n",
132  pkt->cmdString(), pkt->getAddr());
133 
134  DPRINTF(SerialLink, "Request queue size: %d\n", transmitList.size());
135 
136  // @todo: We need to pay for this and not just zero it out
137  pkt->headerDelay = pkt->payloadDelay = 0;
138 
139  // This is similar to what happens for the request packets:
140  // The serializer will start serialization as soon as it receives the
141  // first flit, but the deserializer (at the host side in this case), will
142  // have to wait to receive the whole packet. So we only account for the
143  // deserialization latency.
144  Cycles cycles = delay;
145  cycles += Cycles(divCeil(pkt->getSize() * 8, serial_link.num_lanes
146  * serial_link.link_speed));
147  Tick t = serial_link.clockEdge(cycles);
148 
149  //@todo: If the processor sends two uncached requests towards HMC and the
150  // second one is smaller than the first one. It may happen that the second
151  // one crosses this link faster than the first one (because the packet
152  // waits in the link based on its size). This can reorder the received
153  // response.
154  slavePort.schedTimingResp(pkt, t);
155 
156  return true;
157 }
158 
159 bool
161 {
162  DPRINTF(SerialLink, "recvTimingReq: %s addr 0x%x\n",
163  pkt->cmdString(), pkt->getAddr());
164 
165  // we should not see a timing request if we are already in a retry
166  assert(!retryReq);
167 
168  DPRINTF(SerialLink, "Response queue size: %d outresp: %d\n",
169  transmitList.size(), outstandingResponses);
170 
171  // if the request queue is full then there is no hope
172  if (masterPort.reqQueueFull()) {
173  DPRINTF(SerialLink, "Request queue full\n");
174  retryReq = true;
175  } else if ( !retryReq ) {
176  // look at the response queue if we expect to see a response
177  bool expects_response = pkt->needsResponse() &&
178  !pkt->cacheResponding();
179  if (expects_response) {
180  if (respQueueFull()) {
181  DPRINTF(SerialLink, "Response queue full\n");
182  retryReq = true;
183  } else {
184  // ok to send the request with space for the response
185  DPRINTF(SerialLink, "Reserving space for response\n");
186  assert(outstandingResponses != respQueueLimit);
187  ++outstandingResponses;
188 
189  // no need to set retryReq to false as this is already the
190  // case
191  }
192  }
193 
194  if (!retryReq) {
195  // @todo: We need to pay for this and not just zero it out
196  pkt->headerDelay = pkt->payloadDelay = 0;
197 
198  // We assume that the serializer component at the transmitter side
199  // does not need to receive the whole packet to start the
200  // serialization (this assumption is consistent with the HMC
201  // standard). But the deserializer waits for the complete packet
202  // to check its integrity first. So everytime a packet crosses a
203  // serial link, we should account for its deserialization latency
204  // only.
205  Cycles cycles = delay;
206  cycles += Cycles(divCeil(pkt->getSize() * 8,
207  serial_link.num_lanes * serial_link.link_speed));
208  Tick t = serial_link.clockEdge(cycles);
209 
210  //@todo: If the processor sends two uncached requests towards HMC
211  // and the second one is smaller than the first one. It may happen
212  // that the second one crosses this link faster than the first one
213  // (because the packet waits in the link based on its size).
214  // This can reorder the received response.
215  masterPort.schedTimingReq(pkt, t);
216  }
217  }
218 
219  // remember that we are now stalling a packet and that we have to
220  // tell the sending master to retry once space becomes available,
221  // we make no distinction whether the stalling is due to the
222  // request queue or response queue being full
223  return !retryReq;
224 }
225 
226 void
228 {
229  if (retryReq) {
230  DPRINTF(SerialLink, "Request waiting for retry, now retrying\n");
231  retryReq = false;
232  sendRetryReq();
233  }
234 }
235 
236 void
238 {
239  // If we're about to put this packet at the head of the queue, we
240  // need to schedule an event to do the transmit. Otherwise there
241  // should already be an event scheduled for sending the head
242  // packet.
243  if (transmitList.empty()) {
244  serial_link.schedule(sendEvent, when);
245  }
246 
247  assert(transmitList.size() != reqQueueLimit);
248 
249  transmitList.emplace_back(DeferredPacket(pkt, when));
250 }
251 
252 
253 void
255 {
256  // If we're about to put this packet at the head of the queue, we
257  // need to schedule an event to do the transmit. Otherwise there
258  // should already be an event scheduled for sending the head
259  // packet.
260  if (transmitList.empty()) {
261  serial_link.schedule(sendEvent, when);
262  }
263 
264  transmitList.emplace_back(DeferredPacket(pkt, when));
265 }
266 
267 void
269 {
270  assert(!transmitList.empty());
271 
272  DeferredPacket req = transmitList.front();
273 
274  assert(req.tick <= curTick());
275 
276  PacketPtr pkt = req.pkt;
277 
278  DPRINTF(SerialLink, "trySend request addr 0x%x, queue size %d\n",
279  pkt->getAddr(), transmitList.size());
280 
281  if (sendTimingReq(pkt)) {
282  // send successful
283  transmitList.pop_front();
284 
285  DPRINTF(SerialLink, "trySend request successful\n");
286 
287  // If there are more packets to send, schedule event to try again.
288  if (!transmitList.empty()) {
289  DeferredPacket next_req = transmitList.front();
290  DPRINTF(SerialLink, "Scheduling next send\n");
291 
292  // Make sure bandwidth limitation is met
293  Cycles cycles = Cycles(divCeil(pkt->getSize() * 8,
294  serial_link.num_lanes * serial_link.link_speed));
295  Tick t = serial_link.clockEdge(cycles);
296  serial_link.schedule(sendEvent, std::max(next_req.tick, t));
297  }
298 
299  // if we have stalled a request due to a full request queue,
300  // then send a retry at this point, also note that if the
301  // request we stalled was waiting for the response queue
302  // rather than the request queue we might stall it again
304  }
305 
306  // if the send failed, then we try again once we receive a retry,
307  // and therefore there is no need to take any action
308 }
309 
310 void
312 {
313  assert(!transmitList.empty());
314 
315  DeferredPacket resp = transmitList.front();
316 
317  assert(resp.tick <= curTick());
318 
319  PacketPtr pkt = resp.pkt;
320 
321  DPRINTF(SerialLink, "trySend response addr 0x%x, outstanding %d\n",
322  pkt->getAddr(), outstandingResponses);
323 
324  if (sendTimingResp(pkt)) {
325  // send successful
326  transmitList.pop_front();
327  DPRINTF(SerialLink, "trySend response successful\n");
328 
329  assert(outstandingResponses != 0);
330  --outstandingResponses;
331 
332  // If there are more packets to send, schedule event to try again.
333  if (!transmitList.empty()) {
334  DeferredPacket next_resp = transmitList.front();
335  DPRINTF(SerialLink, "Scheduling next send\n");
336 
337  // Make sure bandwidth limitation is met
338  Cycles cycles = Cycles(divCeil(pkt->getSize() * 8,
339  serial_link.num_lanes * serial_link.link_speed));
340  Tick t = serial_link.clockEdge(cycles);
341  serial_link.schedule(sendEvent, std::max(next_resp.tick, t));
342  }
343 
344  // if there is space in the request queue and we were stalling
345  // a request, it will definitely be possible to accept it now
346  // since there is guaranteed space in the response queue
347  if (!masterPort.reqQueueFull() && retryReq) {
348  DPRINTF(SerialLink, "Request waiting for retry, now retrying\n");
349  retryReq = false;
350  sendRetryReq();
351  }
352  }
353 
354  // if the send failed, then we try again once we receive a retry,
355  // and therefore there is no need to take any action
356 }
357 
358 void
360 {
361  trySendTiming();
362 }
363 
364 void
366 {
367  trySendTiming();
368 }
369 
370 Tick
372 {
373  return delay * serial_link.clockPeriod() + masterPort.sendAtomic(pkt);
374 }
375 
376 void
378 {
379  pkt->pushLabel(name());
380 
381  // check the response queue
382  for (auto i = transmitList.begin(); i != transmitList.end(); ++i) {
383  if (pkt->trySatisfyFunctional((*i).pkt)) {
384  pkt->makeResponse();
385  return;
386  }
387  }
388 
389  // also check the master port's request queue
390  if (masterPort.trySatisfyFunctional(pkt)) {
391  return;
392  }
393 
394  pkt->popLabel();
395 
396  // fall through if pkt still not satisfied
398 }
399 
400 bool
402 {
403  bool found = false;
404  auto i = transmitList.begin();
405 
406  while (i != transmitList.end() && !found) {
407  if (pkt->trySatisfyFunctional((*i).pkt)) {
408  pkt->makeResponse();
409  found = true;
410  }
411  ++i;
412  }
413 
414  return found;
415 }
416 
419 {
420  return ranges;
421 }
422 
423 SerialLink *
424 SerialLinkParams::create()
425 {
426  return new SerialLink(this);
427 }
A MasterPort is a specialisation of a BaseMasterPort, which implements the default protocol for the t...
Definition: port.hh:71
#define DPRINTF(x,...)
Definition: trace.hh:225
Ports are used to interface objects to each other.
Definition: port.hh:56
void sendRangeChange() const
Called by the owner to send a range change.
Definition: port.hh:282
Cycles is a wrapper class for representing cycle counts, i.e.
Definition: types.hh:81
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:171
Bitfield< 7 > i
bool cacheResponding() const
Definition: packet.hh:585
bool isConnected() const
Is this port currently connected to a peer?
Definition: port.hh:124
A SlavePort is a specialisation of a port.
Definition: port.hh:254
void pushLabel(const std::string &lbl)
Push label for PrintReq (safe to call unconditionally).
Definition: packet.hh:1320
unsigned getSize() const
Definition: packet.hh:730
Tick curTick()
The current simulated tick.
Definition: core.hh:44
virtual Port & getPort(const std::string &if_name, PortID idx=InvalidPortID)
Get a port with a given name and index.
Definition: sim_object.cc:123
bool needsResponse() const
Definition: packet.hh:536
uint32_t headerDelay
The extra delay from seeing the packet until the header is transmitted.
Definition: packet.hh:360
uint64_t Tick
Tick count type.
Definition: types.hh:61
bool trySatisfyFunctional(PacketPtr other)
Check a functional request against a memory value stored in another packet (i.e.
Definition: packet.hh:1258
void popLabel()
Pop label for PrintReq (safe to call unconditionally).
Definition: packet.hh:1330
The ClockedObject class extends the SimObject with a clock and accessor functions to relate ticks to ...
Addr getAddr() const
Definition: packet.hh:720
uint32_t payloadDelay
The extra pipelining delay from seeing the packet until the end of payload is transmitted by the comp...
Definition: packet.hh:378
A Packet is used to encapsulate a transfer between two objects in the memory system (e...
Definition: packet.hh:249
void sendEvent(ThreadContext *tc)
Send an event (SEV) to a specific PE if there isn&#39;t already a pending event.
Definition: utility.cc:165
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:931
virtual const std::string name() const
Definition: sim_object.hh:129
Cycles ticksToCycles(Tick t) const
const std::string name() const
Return port name (for DPRINTF).
Definition: port.hh:102
T divCeil(const T &a, const U &b)
Definition: intmath.hh:99
void sendFunctional(PacketPtr pkt) const
Send a functional request packet, where the data is instantly updated everywhere in the memory system...
Definition: port.hh:435
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
Definition: types.hh:235
Bitfield< 5 > t
const std::string & cmdString() const
Return the string name of the cmd field (for debugging and tracing).
Definition: packet.hh:517
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:423
Bitfield< 0 > p

Generated on Fri Jul 3 2020 15:53:04 for gem5 by doxygen 1.8.13