serial_link.cc revision 11284
19792Sandreas.hansson@arm.com/*
29380SAndreas.Sandberg@ARM.com * Copyright (c) 2011-2013 ARM Limited
39380SAndreas.Sandberg@ARM.com * All rights reserved
49380SAndreas.Sandberg@ARM.com *
59380SAndreas.Sandberg@ARM.com * The license below extends only to copyright in the software and shall
69380SAndreas.Sandberg@ARM.com * not be construed as granting a license to any other intellectual
79380SAndreas.Sandberg@ARM.com * property including but not limited to intellectual property relating
89380SAndreas.Sandberg@ARM.com * to a hardware implementation of the functionality of the software
99380SAndreas.Sandberg@ARM.com * licensed hereunder.  You may use the software subject to the license
109380SAndreas.Sandberg@ARM.com * terms below provided that you ensure that this notice is replicated
119380SAndreas.Sandberg@ARM.com * unmodified and in its entirety in all distributions of the software,
129380SAndreas.Sandberg@ARM.com * modified or unmodified, in source code or in binary form.
139380SAndreas.Sandberg@ARM.com *
149380SAndreas.Sandberg@ARM.com * Copyright (c) 2006 The Regents of The University of Michigan
159380SAndreas.Sandberg@ARM.com * Copyright (c) 2015 The University of Bologna
169380SAndreas.Sandberg@ARM.com * All rights reserved.
179380SAndreas.Sandberg@ARM.com *
189380SAndreas.Sandberg@ARM.com * Redistribution and use in source and binary forms, with or without
199380SAndreas.Sandberg@ARM.com * modification, are permitted provided that the following conditions are
209380SAndreas.Sandberg@ARM.com * met: redistributions of source code must retain the above copyright
219380SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer;
229380SAndreas.Sandberg@ARM.com * redistributions in binary form must reproduce the above copyright
239380SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer in the
249380SAndreas.Sandberg@ARM.com * documentation and/or other materials provided with the distribution;
259380SAndreas.Sandberg@ARM.com * neither the name of the copyright holders nor the names of its
269380SAndreas.Sandberg@ARM.com * contributors may be used to endorse or promote products derived from
279380SAndreas.Sandberg@ARM.com * this software without specific prior written permission.
289380SAndreas.Sandberg@ARM.com *
299380SAndreas.Sandberg@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
309380SAndreas.Sandberg@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
319380SAndreas.Sandberg@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
329380SAndreas.Sandberg@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
339380SAndreas.Sandberg@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
349380SAndreas.Sandberg@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
359380SAndreas.Sandberg@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
369380SAndreas.Sandberg@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
379792Sandreas.hansson@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
389380SAndreas.Sandberg@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
399380SAndreas.Sandberg@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
409380SAndreas.Sandberg@ARM.com *
419380SAndreas.Sandberg@ARM.com * Authors: Ali Saidi
429380SAndreas.Sandberg@ARM.com *          Steve Reinhardt
439380SAndreas.Sandberg@ARM.com *          Andreas Hansson
449380SAndreas.Sandberg@ARM.com *          Erfan Azarkhish
459380SAndreas.Sandberg@ARM.com */
469380SAndreas.Sandberg@ARM.com
479654SAndreas.Sandberg@ARM.com/**
489654SAndreas.Sandberg@ARM.com * @file
499380SAndreas.Sandberg@ARM.com * Implementation of the SerialLink Class, modeling Hybrid-Memory-Cube's
509380SAndreas.Sandberg@ARM.com * serial interface.
519380SAndreas.Sandberg@ARM.com */
529380SAndreas.Sandberg@ARM.com
539380SAndreas.Sandberg@ARM.com#include "mem/serial_link.hh"
549380SAndreas.Sandberg@ARM.com
559380SAndreas.Sandberg@ARM.com#include "base/trace.hh"
569380SAndreas.Sandberg@ARM.com#include "debug/SerialLink.hh"
579380SAndreas.Sandberg@ARM.com#include "params/SerialLink.hh"
589380SAndreas.Sandberg@ARM.com
599380SAndreas.Sandberg@ARM.com
609792Sandreas.hansson@arm.comSerialLink::SerialLinkSlavePort::SerialLinkSlavePort(const std::string& _name,
6110512SAli.Saidi@ARM.com                                         SerialLink& _serial_link,
6210512SAli.Saidi@ARM.com                                         SerialLinkMasterPort& _masterPort,
639792Sandreas.hansson@arm.com                                         Cycles _delay, int _resp_limit,
649380SAndreas.Sandberg@ARM.com                                         const std::vector<AddrRange>&
659380SAndreas.Sandberg@ARM.com                                         _ranges)
669380SAndreas.Sandberg@ARM.com    : SlavePort(_name, &_serial_link), serial_link(_serial_link),
679792Sandreas.hansson@arm.com      masterPort(_masterPort), delay(_delay),
689380SAndreas.Sandberg@ARM.com      ranges(_ranges.begin(), _ranges.end()),
699380SAndreas.Sandberg@ARM.com      outstandingResponses(0), retryReq(false),
709380SAndreas.Sandberg@ARM.com      respQueueLimit(_resp_limit), sendEvent(*this)
7110512SAli.Saidi@ARM.com{
729380SAndreas.Sandberg@ARM.com}
739380SAndreas.Sandberg@ARM.com
749792Sandreas.hansson@arm.comSerialLink::SerialLinkMasterPort::SerialLinkMasterPort(const std::string&
759380SAndreas.Sandberg@ARM.com                                           _name, SerialLink& _serial_link,
769380SAndreas.Sandberg@ARM.com                                           SerialLinkSlavePort& _slavePort,
779380SAndreas.Sandberg@ARM.com                                           Cycles _delay, int _req_limit)
789380SAndreas.Sandberg@ARM.com    : MasterPort(_name, &_serial_link), serial_link(_serial_link),
799793Sakash.bagdia@arm.com      slavePort(_slavePort), delay(_delay), reqQueueLimit(_req_limit),
809380SAndreas.Sandberg@ARM.com      sendEvent(*this)
819793Sakash.bagdia@arm.com{
829793Sakash.bagdia@arm.com}
839380SAndreas.Sandberg@ARM.com
849380SAndreas.Sandberg@ARM.comSerialLink::SerialLink(SerialLinkParams *p)
859380SAndreas.Sandberg@ARM.com    : MemObject(p),
869380SAndreas.Sandberg@ARM.com      slavePort(p->name + ".slave", *this, masterPort,
879380SAndreas.Sandberg@ARM.com                ticksToCycles(p->delay), p->resp_size, p->ranges),
889380SAndreas.Sandberg@ARM.com      masterPort(p->name + ".master", *this, slavePort,
899380SAndreas.Sandberg@ARM.com                 ticksToCycles(p->delay), p->req_size),
909380SAndreas.Sandberg@ARM.com      num_lanes(p->num_lanes)
919380SAndreas.Sandberg@ARM.com{
929380SAndreas.Sandberg@ARM.com}
939380SAndreas.Sandberg@ARM.com
949380SAndreas.Sandberg@ARM.comBaseMasterPort&
959380SAndreas.Sandberg@ARM.comSerialLink::getMasterPort(const std::string &if_name, PortID idx)
969380SAndreas.Sandberg@ARM.com{
979380SAndreas.Sandberg@ARM.com    if (if_name == "master")
989380SAndreas.Sandberg@ARM.com        return masterPort;
999380SAndreas.Sandberg@ARM.com    else
1009380SAndreas.Sandberg@ARM.com        // pass it along to our super class
1019380SAndreas.Sandberg@ARM.com        return MemObject::getMasterPort(if_name, idx);
1029380SAndreas.Sandberg@ARM.com}
1039380SAndreas.Sandberg@ARM.com
1049380SAndreas.Sandberg@ARM.comBaseSlavePort&
1059380SAndreas.Sandberg@ARM.comSerialLink::getSlavePort(const std::string &if_name, PortID idx)
1069380SAndreas.Sandberg@ARM.com{
10710720Sandreas.hansson@arm.com    if (if_name == "slave")
1089793Sakash.bagdia@arm.com        return slavePort;
1099793Sakash.bagdia@arm.com    else
1109380SAndreas.Sandberg@ARM.com        // pass it along to our super class
1119380SAndreas.Sandberg@ARM.com        return MemObject::getSlavePort(if_name, idx);
1129380SAndreas.Sandberg@ARM.com}
1139380SAndreas.Sandberg@ARM.com
1149674Snilay@cs.wisc.eduvoid
1159380SAndreas.Sandberg@ARM.comSerialLink::init()
1169380SAndreas.Sandberg@ARM.com{
1179380SAndreas.Sandberg@ARM.com    // make sure both sides are connected and have the same block size
1189380SAndreas.Sandberg@ARM.com    if (!slavePort.isConnected() || !masterPort.isConnected())
1199380SAndreas.Sandberg@ARM.com        fatal("Both ports of a serial_link must be connected.\n");
1209380SAndreas.Sandberg@ARM.com
1219674Snilay@cs.wisc.edu    // notify the master side  of our address ranges
1229674Snilay@cs.wisc.edu    slavePort.sendRangeChange();
1239674Snilay@cs.wisc.edu}
1249674Snilay@cs.wisc.edu
1259674Snilay@cs.wisc.edubool
1269380SAndreas.Sandberg@ARM.comSerialLink::SerialLinkSlavePort::respQueueFull() const
1279654SAndreas.Sandberg@ARM.com{
1289654SAndreas.Sandberg@ARM.com    return outstandingResponses == respQueueLimit;
1299654SAndreas.Sandberg@ARM.com}
1309654SAndreas.Sandberg@ARM.com
1319654SAndreas.Sandberg@ARM.combool
1329654SAndreas.Sandberg@ARM.comSerialLink::SerialLinkMasterPort::reqQueueFull() const
1339654SAndreas.Sandberg@ARM.com{
1349654SAndreas.Sandberg@ARM.com    return transmitList.size() == reqQueueLimit;
1359380SAndreas.Sandberg@ARM.com}
1369380SAndreas.Sandberg@ARM.com
1379380SAndreas.Sandberg@ARM.combool
1389380SAndreas.Sandberg@ARM.comSerialLink::SerialLinkMasterPort::recvTimingResp(PacketPtr pkt)
1399380SAndreas.Sandberg@ARM.com{
1409380SAndreas.Sandberg@ARM.com    // all checks are done when the request is accepted on the slave
1419793Sakash.bagdia@arm.com    // side, so we are guaranteed to have space for the response
1429793Sakash.bagdia@arm.com    DPRINTF(SerialLink, "recvTimingResp: %s addr 0x%x\n",
1439380SAndreas.Sandberg@ARM.com            pkt->cmdString(), pkt->getAddr());
1449654SAndreas.Sandberg@ARM.com
1459654SAndreas.Sandberg@ARM.com    DPRINTF(SerialLink, "Request queue size: %d\n", transmitList.size());
1469654SAndreas.Sandberg@ARM.com
1479654SAndreas.Sandberg@ARM.com    // @todo: We need to pay for this and not just zero it out
1489380SAndreas.Sandberg@ARM.com    pkt->headerDelay = pkt->payloadDelay = 0;
1499380SAndreas.Sandberg@ARM.com
1509674Snilay@cs.wisc.edu    // This is similar to what happens for the request packets:
1519380SAndreas.Sandberg@ARM.com    // The serializer will start serialization as soon as it receives the
1529793Sakash.bagdia@arm.com    // first flit, but the deserializer (at the host side in this case), will
1539793Sakash.bagdia@arm.com    // have to wait to receive the whole packet. So we only account for the
1549793Sakash.bagdia@arm.com    // deserialization latency.
1559793Sakash.bagdia@arm.com    Cycles cycles = delay;
1569827Sakash.bagdia@arm.com    cycles += Cycles(divCeil(pkt->getSize() * 8, serial_link.num_lanes));
1579827Sakash.bagdia@arm.com    Tick t = serial_link.clockEdge(cycles);
1589827Sakash.bagdia@arm.com
1599827Sakash.bagdia@arm.com    //@todo: If the processor sends two uncached requests towards HMC and the
1609793Sakash.bagdia@arm.com    // second one is smaller than the first one. It may happen that the second
1619793Sakash.bagdia@arm.com    // one crosses this link faster than the first one (because the packet
1629793Sakash.bagdia@arm.com    // waits in the link based on its size). This can reorder the received
1639827Sakash.bagdia@arm.com    // response.
1649827Sakash.bagdia@arm.com    slavePort.schedTimingResp(pkt, t);
1659827Sakash.bagdia@arm.com
1669793Sakash.bagdia@arm.com    return true;
1679380SAndreas.Sandberg@ARM.com}
1689380SAndreas.Sandberg@ARM.com
1699380SAndreas.Sandberg@ARM.combool
1709380SAndreas.Sandberg@ARM.comSerialLink::SerialLinkSlavePort::recvTimingReq(PacketPtr pkt)
1719380SAndreas.Sandberg@ARM.com{
1729380SAndreas.Sandberg@ARM.com    DPRINTF(SerialLink, "recvTimingReq: %s addr 0x%x\n",
1739380SAndreas.Sandberg@ARM.com            pkt->cmdString(), pkt->getAddr());
1749380SAndreas.Sandberg@ARM.com
1759380SAndreas.Sandberg@ARM.com    // we should not see a timing request if we are already in a retry
1769380SAndreas.Sandberg@ARM.com    assert(!retryReq);
1779380SAndreas.Sandberg@ARM.com
1789792Sandreas.hansson@arm.com    DPRINTF(SerialLink, "Response queue size: %d outresp: %d\n",
1799792Sandreas.hansson@arm.com            transmitList.size(), outstandingResponses);
1809792Sandreas.hansson@arm.com
1819792Sandreas.hansson@arm.com    // if the request queue is full then there is no hope
1829792Sandreas.hansson@arm.com    if (masterPort.reqQueueFull()) {
1839792Sandreas.hansson@arm.com        DPRINTF(SerialLink, "Request queue full\n");
1849792Sandreas.hansson@arm.com        retryReq = true;
1859792Sandreas.hansson@arm.com    } else if ( !retryReq ) {
1869792Sandreas.hansson@arm.com        // look at the response queue if we expect to see a response
1879792Sandreas.hansson@arm.com        bool expects_response = pkt->needsResponse() &&
1889792Sandreas.hansson@arm.com            !pkt->cacheResponding();
18910720Sandreas.hansson@arm.com        if (expects_response) {
1909792Sandreas.hansson@arm.com            if (respQueueFull()) {
1919792Sandreas.hansson@arm.com                DPRINTF(SerialLink, "Response queue full\n");
1929792Sandreas.hansson@arm.com                retryReq = true;
1939792Sandreas.hansson@arm.com            } else {
1949792Sandreas.hansson@arm.com                // ok to send the request with space for the response
1959792Sandreas.hansson@arm.com                DPRINTF(SerialLink, "Reserving space for response\n");
1969792Sandreas.hansson@arm.com                assert(outstandingResponses != respQueueLimit);
1979792Sandreas.hansson@arm.com                ++outstandingResponses;
1989792Sandreas.hansson@arm.com
1999792Sandreas.hansson@arm.com                // no need to set retryReq to false as this is already the
2009792Sandreas.hansson@arm.com                // case
2019792Sandreas.hansson@arm.com            }
2029792Sandreas.hansson@arm.com        }
2039792Sandreas.hansson@arm.com
2049792Sandreas.hansson@arm.com        if (!retryReq) {
2059792Sandreas.hansson@arm.com            // @todo: We need to pay for this and not just zero it out
2069792Sandreas.hansson@arm.com            pkt->headerDelay = pkt->payloadDelay = 0;
2079792Sandreas.hansson@arm.com
2089792Sandreas.hansson@arm.com            // We assume that the serializer component at the transmitter side
2099792Sandreas.hansson@arm.com            // does not need to receive the whole packet to start the
2109792Sandreas.hansson@arm.com            // serialization (this assumption is consistent with the HMC
2119792Sandreas.hansson@arm.com            // standard). But the deserializer waits for the complete packet
2129792Sandreas.hansson@arm.com            // to check its integrity first. So everytime a packet crosses a
2139792Sandreas.hansson@arm.com            // serial link, we should account for its deserialization latency
2149792Sandreas.hansson@arm.com            // only.
2159792Sandreas.hansson@arm.com            Cycles cycles = delay;
2169792Sandreas.hansson@arm.com            cycles += Cycles(divCeil(pkt->getSize() * 8,
2179792Sandreas.hansson@arm.com                serial_link.num_lanes));
2189792Sandreas.hansson@arm.com            Tick t = serial_link.clockEdge(cycles);
2199792Sandreas.hansson@arm.com
2209792Sandreas.hansson@arm.com            //@todo: If the processor sends two uncached requests towards HMC
2219792Sandreas.hansson@arm.com            // and the second one is smaller than the first one. It may happen
2229380SAndreas.Sandberg@ARM.com            // that the second one crosses this link faster than the first one
2239380SAndreas.Sandberg@ARM.com            // (because the packet waits in the link based on its size).
2249380SAndreas.Sandberg@ARM.com            // This can reorder the received response.
2259380SAndreas.Sandberg@ARM.com            masterPort.schedTimingReq(pkt, t);
2269380SAndreas.Sandberg@ARM.com        }
2279380SAndreas.Sandberg@ARM.com    }
2289380SAndreas.Sandberg@ARM.com
2299380SAndreas.Sandberg@ARM.com    // remember that we are now stalling a packet and that we have to
2309380SAndreas.Sandberg@ARM.com    // tell the sending master to retry once space becomes available,
2319826Sandreas.hansson@arm.com    // we make no distinction whether the stalling is due to the
2329826Sandreas.hansson@arm.com    // request queue or response queue being full
2339835Sandreas.hansson@arm.com    return !retryReq;
2349826Sandreas.hansson@arm.com}
2359826Sandreas.hansson@arm.com
2369826Sandreas.hansson@arm.comvoid
2379826Sandreas.hansson@arm.comSerialLink::SerialLinkSlavePort::retryStalledReq()
2389788Sakash.bagdia@arm.com{
2399788Sakash.bagdia@arm.com    if (retryReq) {
2409380SAndreas.Sandberg@ARM.com        DPRINTF(SerialLink, "Request waiting for retry, now retrying\n");
2419380SAndreas.Sandberg@ARM.com        retryReq = false;
2429380SAndreas.Sandberg@ARM.com        sendRetryReq();
2439380SAndreas.Sandberg@ARM.com    }
2449380SAndreas.Sandberg@ARM.com}
2459380SAndreas.Sandberg@ARM.com
2469380SAndreas.Sandberg@ARM.comvoid
2479380SAndreas.Sandberg@ARM.comSerialLink::SerialLinkMasterPort::schedTimingReq(PacketPtr pkt, Tick when)
2489380SAndreas.Sandberg@ARM.com{
2499380SAndreas.Sandberg@ARM.com    // If we're about to put this packet at the head of the queue, we
2509380SAndreas.Sandberg@ARM.com    // need to schedule an event to do the transmit.  Otherwise there
2519380SAndreas.Sandberg@ARM.com    // should already be an event scheduled for sending the head
2529380SAndreas.Sandberg@ARM.com    // packet.
2539380SAndreas.Sandberg@ARM.com    if (transmitList.empty()) {
2549380SAndreas.Sandberg@ARM.com        serial_link.schedule(sendEvent, when);
2559380SAndreas.Sandberg@ARM.com    }
2569380SAndreas.Sandberg@ARM.com
2579380SAndreas.Sandberg@ARM.com    assert(transmitList.size() != reqQueueLimit);
2589380SAndreas.Sandberg@ARM.com
2599380SAndreas.Sandberg@ARM.com    transmitList.emplace_back(DeferredPacket(pkt, when));
2609380SAndreas.Sandberg@ARM.com}
2619380SAndreas.Sandberg@ARM.com
2629380SAndreas.Sandberg@ARM.com
2639380SAndreas.Sandberg@ARM.comvoid
2649380SAndreas.Sandberg@ARM.comSerialLink::SerialLinkSlavePort::schedTimingResp(PacketPtr pkt, Tick when)
2659447SAndreas.Sandberg@ARM.com{
2669447SAndreas.Sandberg@ARM.com    // If we're about to put this packet at the head of the queue, we
2679447SAndreas.Sandberg@ARM.com    // need to schedule an event to do the transmit.  Otherwise there
2689447SAndreas.Sandberg@ARM.com    // should already be an event scheduled for sending the head
2699447SAndreas.Sandberg@ARM.com    // packet.
2709447SAndreas.Sandberg@ARM.com    if (transmitList.empty()) {
2719447SAndreas.Sandberg@ARM.com        serial_link.schedule(sendEvent, when);
2729447SAndreas.Sandberg@ARM.com    }
2739793Sakash.bagdia@arm.com
2749793Sakash.bagdia@arm.com    transmitList.emplace_back(DeferredPacket(pkt, when));
2759793Sakash.bagdia@arm.com}
2769793Sakash.bagdia@arm.com
2779447SAndreas.Sandberg@ARM.comvoid
2789447SAndreas.Sandberg@ARM.comSerialLink::SerialLinkMasterPort::trySendTiming()
2799447SAndreas.Sandberg@ARM.com{
280    assert(!transmitList.empty());
281
282    DeferredPacket req = transmitList.front();
283
284    assert(req.tick <= curTick());
285
286    PacketPtr pkt = req.pkt;
287
288    DPRINTF(SerialLink, "trySend request addr 0x%x, queue size %d\n",
289            pkt->getAddr(), transmitList.size());
290
291    if (sendTimingReq(pkt)) {
292        // send successful
293        transmitList.pop_front();
294
295        DPRINTF(SerialLink, "trySend request successful\n");
296
297        // If there are more packets to send, schedule event to try again.
298        if (!transmitList.empty()) {
299            DeferredPacket next_req = transmitList.front();
300            DPRINTF(SerialLink, "Scheduling next send\n");
301
302            // Make sure bandwidth limitation is met
303            Cycles cycles = Cycles(divCeil(pkt->getSize() * 8,
304                serial_link.num_lanes));
305            Tick t = serial_link.clockEdge(cycles);
306            serial_link.schedule(sendEvent, std::max(next_req.tick, t));
307        }
308
309        // if we have stalled a request due to a full request queue,
310        // then send a retry at this point, also note that if the
311        // request we stalled was waiting for the response queue
312        // rather than the request queue we might stall it again
313        slavePort.retryStalledReq();
314    }
315
316    // if the send failed, then we try again once we receive a retry,
317    // and therefore there is no need to take any action
318}
319
320void
321SerialLink::SerialLinkSlavePort::trySendTiming()
322{
323    assert(!transmitList.empty());
324
325    DeferredPacket resp = transmitList.front();
326
327    assert(resp.tick <= curTick());
328
329    PacketPtr pkt = resp.pkt;
330
331    DPRINTF(SerialLink, "trySend response addr 0x%x, outstanding %d\n",
332            pkt->getAddr(), outstandingResponses);
333
334    if (sendTimingResp(pkt)) {
335        // send successful
336        transmitList.pop_front();
337        DPRINTF(SerialLink, "trySend response successful\n");
338
339        assert(outstandingResponses != 0);
340        --outstandingResponses;
341
342        // If there are more packets to send, schedule event to try again.
343        if (!transmitList.empty()) {
344            DeferredPacket next_resp = transmitList.front();
345            DPRINTF(SerialLink, "Scheduling next send\n");
346
347            // Make sure bandwidth limitation is met
348            Cycles cycles = Cycles(divCeil(pkt->getSize() * 8,
349                serial_link.num_lanes));
350            Tick t = serial_link.clockEdge(cycles);
351            serial_link.schedule(sendEvent, std::max(next_resp.tick, t));
352        }
353
354        // if there is space in the request queue and we were stalling
355        // a request, it will definitely be possible to accept it now
356        // since there is guaranteed space in the response queue
357        if (!masterPort.reqQueueFull() && retryReq) {
358            DPRINTF(SerialLink, "Request waiting for retry, now retrying\n");
359            retryReq = false;
360            sendRetryReq();
361        }
362    }
363
364    // if the send failed, then we try again once we receive a retry,
365    // and therefore there is no need to take any action
366}
367
368void
369SerialLink::SerialLinkMasterPort::recvReqRetry()
370{
371    trySendTiming();
372}
373
374void
375SerialLink::SerialLinkSlavePort::recvRespRetry()
376{
377    trySendTiming();
378}
379
380Tick
381SerialLink::SerialLinkSlavePort::recvAtomic(PacketPtr pkt)
382{
383    return delay * serial_link.clockPeriod() + masterPort.sendAtomic(pkt);
384}
385
386void
387SerialLink::SerialLinkSlavePort::recvFunctional(PacketPtr pkt)
388{
389    pkt->pushLabel(name());
390
391    // check the response queue
392    for (auto i = transmitList.begin();  i != transmitList.end(); ++i) {
393        if (pkt->checkFunctional((*i).pkt)) {
394            pkt->makeResponse();
395            return;
396        }
397    }
398
399    // also check the master port's request queue
400    if (masterPort.checkFunctional(pkt)) {
401        return;
402    }
403
404    pkt->popLabel();
405
406    // fall through if pkt still not satisfied
407    masterPort.sendFunctional(pkt);
408}
409
410bool
411SerialLink::SerialLinkMasterPort::checkFunctional(PacketPtr pkt)
412{
413    bool found = false;
414    auto i = transmitList.begin();
415
416    while(i != transmitList.end() && !found) {
417        if (pkt->checkFunctional((*i).pkt)) {
418            pkt->makeResponse();
419            found = true;
420        }
421        ++i;
422    }
423
424    return found;
425}
426
427AddrRangeList
428SerialLink::SerialLinkSlavePort::getAddrRanges() const
429{
430    return ranges;
431}
432
433SerialLink *
434SerialLinkParams::create()
435{
436    return new SerialLink(this);
437}
438