tport.cc revision 5606
12068SN/A/* 22068SN/A * Copyright (c) 2006 The Regents of The University of Michigan 32188SN/A * All rights reserved. 42068SN/A * 52068SN/A * Redistribution and use in source and binary forms, with or without 62068SN/A * modification, are permitted provided that the following conditions are 72068SN/A * met: redistributions of source code must retain the above copyright 82068SN/A * notice, this list of conditions and the following disclaimer; 92068SN/A * redistributions in binary form must reproduce the above copyright 102068SN/A * notice, this list of conditions and the following disclaimer in the 112068SN/A * documentation and/or other materials provided with the distribution; 122068SN/A * neither the name of the copyright holders nor the names of its 132068SN/A * contributors may be used to endorse or promote products derived from 142068SN/A * this software without specific prior written permission. 152068SN/A * 162068SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172068SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182068SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192068SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202068SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212068SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222068SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232068SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242068SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252068SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262068SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272068SN/A * 282665Ssaidi@eecs.umich.edu * Authors: Ali Saidi 292665Ssaidi@eecs.umich.edu */ 302068SN/A 312649Ssaidi@eecs.umich.edu#include "mem/tport.hh" 322649Ssaidi@eecs.umich.edu 332649Ssaidi@eecs.umich.edubool 342649Ssaidi@eecs.umich.eduSimpleTimingPort::checkFunctional(PacketPtr pkt) 352649Ssaidi@eecs.umich.edu{ 362068SN/A DeferredPacketIterator i = transmitList.begin(); 372068SN/A DeferredPacketIterator end = transmitList.end(); 382068SN/A 392068SN/A for (; i != end; ++i) { 402068SN/A PacketPtr target = i->pkt; 412068SN/A // If the target contains data, and it overlaps the 422068SN/A // probed request, need to update data 432068SN/A if (pkt->checkFunctional(target)) { 442075SN/A return true; 452075SN/A } 462075SN/A } 472075SN/A 482075SN/A return false; 492075SN/A} 502735Sktlim@umich.edu 512069SN/Avoid 522069SN/ASimpleTimingPort::recvFunctional(PacketPtr pkt) 532075SN/A{ 542735Sktlim@umich.edu if (!checkFunctional(pkt)) { 552068SN/A // Just do an atomic access and throw away the returned latency 562068SN/A recvAtomic(pkt); 572068SN/A } 582075SN/A} 592075SN/A 602068SN/Abool 612068SN/ASimpleTimingPort::recvTiming(PacketPtr pkt) 622075SN/A{ 632075SN/A // If the device is only a slave, it should only be sending 642068SN/A // responses, which should never get nacked. There used to be 652068SN/A // code to hanldle nacks here, but I'm pretty sure it didn't work 662068SN/A // correctly with the drain code, so that would need to be fixed 672075SN/A // if we ever added it back. 682075SN/A assert(pkt->isRequest()); 692075SN/A 702075SN/A if (pkt->memInhibitAsserted()) { 712075SN/A // snooper will supply based on copy of packet 722075SN/A // still target's responsibility to delete packet 732075SN/A delete pkt; 742735Sktlim@umich.edu return true; 752069SN/A } 762069SN/A 772075SN/A bool needsResponse = pkt->needsResponse(); 782735Sktlim@umich.edu Tick latency = recvAtomic(pkt); 792068SN/A // turn packet around to go back to requester if response expected 802068SN/A if (needsResponse) { 812068SN/A // recvAtomic() should already have turned packet into 822075SN/A // atomic response 832068SN/A assert(pkt->isResponse()); 842069SN/A schedSendTiming(pkt, curTick + latency); 852068SN/A } else { 862068SN/A delete pkt; 872336SN/A } 882075SN/A 892068SN/A return true; 902069SN/A} 912068SN/A 922068SN/A 932068SN/Avoid 942068SN/ASimpleTimingPort::schedSendTiming(PacketPtr pkt, Tick when) 952068SN/A{ 962068SN/A assert(when > curTick); 972068SN/A assert(when < curTick + Clock::Int::ms); 982068SN/A 992336SN/A // Nothing is on the list: add it and schedule an event 1002068SN/A if (transmitList.empty() || when < transmitList.front().tick) { 1012068SN/A transmitList.push_front(DeferredPacket(when, pkt)); 1022068SN/A schedSendEvent(when); 1032068SN/A return; 1042068SN/A } 1052068SN/A 1062068SN/A // list is non-empty & this belongs at the end 1072068SN/A if (when >= transmitList.back().tick) { 1082068SN/A transmitList.push_back(DeferredPacket(when, pkt)); 1092068SN/A return; 1102068SN/A } 1112068SN/A 1122147SN/A // this belongs in the middle somewhere 1132068SN/A DeferredPacketIterator i = transmitList.begin(); 1142068SN/A i++; // already checked for insertion at front 1152068SN/A DeferredPacketIterator end = transmitList.end(); 1162068SN/A 1172068SN/A for (; i != end; ++i) { 1182068SN/A if (when < i->tick) { 1192068SN/A transmitList.insert(i, DeferredPacket(when, pkt)); 1202068SN/A return; 1212068SN/A } 1222068SN/A } 1232068SN/A assert(false); // should never get here 1242147SN/A} 1252068SN/A 1262068SN/A 1272068SN/Avoid 1282068SN/ASimpleTimingPort::sendDeferredPacket() 1292068SN/A{ 1302068SN/A assert(deferredPacketReady()); 1312068SN/A // take packet off list here; if recvTiming() on the other side 1322068SN/A // calls sendTiming() back on us (like SimpleTimingCpu does), then 1332068SN/A // we get confused by having a non-active packet on transmitList 1342068SN/A DeferredPacket dp = transmitList.front(); 1352068SN/A transmitList.pop_front(); 1362068SN/A bool success = sendTiming(dp.pkt); 1372068SN/A 1382147SN/A if (success) { 1392068SN/A if (!transmitList.empty() && !sendEvent->scheduled()) { 1402068SN/A Tick time = transmitList.front().tick; 1412068SN/A schedule(sendEvent, time <= curTick ? curTick+1 : time); 1422068SN/A } 1432068SN/A 1442068SN/A if (transmitList.empty() && drainEvent) { 1452068SN/A drainEvent->process(); 1462068SN/A drainEvent = NULL; 1472068SN/A } 1482068SN/A } else { 1492068SN/A // Unsuccessful, need to put back on transmitList. Callee 1502068SN/A // should not have messed with it (since it didn't accept that 1512068SN/A // packet), so we can just push it back on the front. 1522147SN/A assert(!sendEvent->scheduled()); 1532068SN/A transmitList.push_front(dp); 1542068SN/A } 1552068SN/A 1562068SN/A waitingOnRetry = !success; 1572068SN/A 1582068SN/A if (waitingOnRetry) { 1592068SN/A DPRINTF(Bus, "Send failed, waiting on retry\n"); 1602068SN/A } 1612068SN/A} 1622068SN/A 1632068SN/A 1642068SN/Avoid 1652068SN/ASimpleTimingPort::recvRetry() 1662068SN/A{ 1672068SN/A DPRINTF(Bus, "Received retry\n"); 1682068SN/A assert(waitingOnRetry); 1692068SN/A sendDeferredPacket(); 1702068SN/A} 1712068SN/A 1722068SN/A 1732068SN/Avoid 1742068SN/ASimpleTimingPort::processSendEvent() 1752068SN/A{ 1762068SN/A assert(!waitingOnRetry); 1772068SN/A sendDeferredPacket(); 1782068SN/A} 1792068SN/A 1802068SN/A 1812068SN/Aunsigned int 1822068SN/ASimpleTimingPort::drain(Event *de) 1832068SN/A{ 1842068SN/A if (transmitList.size() == 0) 1852068SN/A return 0; 1862068SN/A drainEvent = de; 1872068SN/A return 1; 1882068SN/A} 1892068SN/A