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

Generated on Fri Jun 9 2017 13:03:50 for gem5 by doxygen 1.8.6