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

Generated on Fri Feb 28 2020 16:27:02 for gem5 by doxygen 1.8.13