gem5  v21.1.0.2
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 
54 namespace gem5
55 {
56 
58 SerialLinkResponsePort(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(_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(_serial_link),
79  cpu_side_port(_cpu_side_port), delay(_delay), reqQueueLimit(_req_limit),
80  sendEvent([this]{ trySendTiming(); }, _name)
81 {
82 }
83 
84 SerialLink::SerialLink(const SerialLinkParams &p)
85  : ClockedObject(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 
95 Port&
96 SerialLink::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 
107 void
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 
118 bool
120 {
122 }
123 
124 bool
126 {
127  return transmitList.size() == reqQueueLimit;
128 }
129 
130 bool
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 
163 bool
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
176  if (mem_side_port.reqQueueFull()) {
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 
230 void
232 {
233  if (retryReq) {
234  DPRINTF(SerialLink, "Request waiting for retry, now retrying\n");
235  retryReq = false;
236  sendRetryReq();
237  }
238 }
239 
240 void
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 
257 void
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 
271 void
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 
314 void
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 
362 void
364 {
365  trySendTiming();
366 }
367 
368 void
370 {
371  trySendTiming();
372 }
373 
374 Tick
376 {
377  return delay * serial_link.clockPeriod() + mem_side_port.sendAtomic(pkt);
378 }
379 
380 void
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 
404 bool
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
gem5::curTick
Tick curTick()
The universal simulation clock.
Definition: cur_tick.hh:46
fatal
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:189
gem5::PortID
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
Definition: types.hh:252
gem5::Packet::cmdString
const std::string & cmdString() const
Return the string name of the cmd field (for debugging and tracing).
Definition: packet.hh:577
gem5::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:126
gem5::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:464
gem5::Packet::cacheResponding
bool cacheResponding() const
Definition: packet.hh:646
std::vector
STL vector class.
Definition: stl.hh:37
gem5::ArmISA::i
Bitfield< 7 > i
Definition: misc_types.hh:66
gem5::Packet::headerDelay
uint32_t headerDelay
The extra delay from seeing the packet until the header is transmitted.
Definition: packet.hh:420
gem5::RequestPort
A RequestPort is a specialisation of a Port, which implements the default protocol for the three diff...
Definition: port.hh:77
gem5::Cycles
Cycles is a wrapper class for representing cycle counts, i.e.
Definition: types.hh:78
gem5::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:438
gem5::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:485
gem5::Named::name
virtual std::string name() const
Definition: named.hh:47
DPRINTF
#define DPRINTF(x,...)
Definition: trace.hh:186
gem5::Packet
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:283
gem5::MipsISA::p
Bitfield< 0 > p
Definition: pra_constants.hh:326
gem5::Tick
uint64_t Tick
Tick count type.
Definition: types.hh:58
gem5::Port::isConnected
bool isConnected() const
Is this port currently connected to a peer?
Definition: port.hh:133
gem5::Packet::pushLabel
void pushLabel(const std::string &lbl)
Push label for PrintReq (safe to call unconditionally).
Definition: packet.hh:1420
gem5::ArmISA::t
Bitfield< 5 > t
Definition: misc_types.hh:70
gem5::Packet::popLabel
void popLabel()
Pop label for PrintReq (safe to call unconditionally).
Definition: packet.hh:1430
gem5::Packet::needsResponse
bool needsResponse() const
Definition: packet.hh:597
gem5::ClockedObject
The ClockedObject class extends the SimObject with a clock and accessor functions to relate ticks to ...
Definition: clocked_object.hh:234
gem5::ResponsePort::sendRangeChange
void sendRangeChange() const
Called by the owner to send a range change.
Definition: port.hh:296
gem5::divCeil
static constexpr T divCeil(const T &a, const U &b)
Definition: intmath.hh:110
gem5::ResponsePort
A ResponsePort is a specialization of a port.
Definition: port.hh:268
gem5::Port
Ports are used to interface objects to each other.
Definition: port.hh:61
gem5::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:63
gem5::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:1031
gem5::Packet::trySatisfyFunctional
bool trySatisfyFunctional(PacketPtr other)
Check a functional request against a memory value stored in another packet (i.e.
Definition: packet.hh:1358
trace.hh
gem5::Clocked::ticksToCycles
Cycles ticksToCycles(Tick t) const
Definition: clocked_object.hh:222
std::list< AddrRange >
gem5::Packet::getAddr
Addr getAddr() const
Definition: packet.hh:781
gem5
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
Definition: decoder.cc:40
gem5::Packet::getSize
unsigned getSize() const
Definition: packet.hh:791
gem5::Named::_name
const std::string _name
Definition: named.hh:41

Generated on Tue Sep 21 2021 12:25:43 for gem5 by doxygen 1.8.17