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

Generated on Wed Sep 30 2020 14:02:14 for gem5 by doxygen 1.8.17