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