tport.cc revision 5606
11689SN/A/*
22329SN/A * Copyright (c) 2006 The Regents of The University of Michigan
31689SN/A * All rights reserved.
41689SN/A *
51689SN/A * Redistribution and use in source and binary forms, with or without
61689SN/A * modification, are permitted provided that the following conditions are
71689SN/A * met: redistributions of source code must retain the above copyright
81689SN/A * notice, this list of conditions and the following disclaimer;
91689SN/A * redistributions in binary form must reproduce the above copyright
101689SN/A * notice, this list of conditions and the following disclaimer in the
111689SN/A * documentation and/or other materials provided with the distribution;
121689SN/A * neither the name of the copyright holders nor the names of its
131689SN/A * contributors may be used to endorse or promote products derived from
141689SN/A * this software without specific prior written permission.
151689SN/A *
161689SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
171689SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
181689SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
191689SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
201689SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
211689SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
221689SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
231689SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
241689SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
251689SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
261689SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu *
282665Ssaidi@eecs.umich.edu * Authors: Ali Saidi
291689SN/A */
301689SN/A
312292SN/A#include "mem/tport.hh"
322292SN/A
331060SN/Abool
341061SN/ASimpleTimingPort::checkFunctional(PacketPtr pkt)
351684SN/A{
367720Sgblack@eecs.umich.edu    DeferredPacketIterator i = transmitList.begin();
376216Snate@binkert.org    DeferredPacketIterator end = transmitList.end();
386216Snate@binkert.org
392980Sgblack@eecs.umich.edu    for (; i != end; ++i) {
401060SN/A        PacketPtr target = i->pkt;
412292SN/A        // If the target contains data, and it overlaps the
422292SN/A        // probed request, need to update data
432292SN/A        if (pkt->checkFunctional(target)) {
441060SN/A            return true;
451060SN/A        }
462348SN/A    }
471060SN/A
482292SN/A    return false;
492292SN/A}
502292SN/A
512292SN/Avoid
522292SN/ASimpleTimingPort::recvFunctional(PacketPtr pkt)
532292SN/A{
542292SN/A    if (!checkFunctional(pkt)) {
552292SN/A        // Just do an atomic access and throw away the returned latency
562292SN/A        recvAtomic(pkt);
572292SN/A    }
582292SN/A}
592348SN/A
602292SN/Abool
612292SN/ASimpleTimingPort::recvTiming(PacketPtr pkt)
621061SN/A{
631061SN/A    // If the device is only a slave, it should only be sending
641061SN/A    // responses, which should never get nacked.  There used to be
651061SN/A    // code to hanldle nacks here, but I'm pretty sure it didn't work
661461SN/A    // correctly with the drain code, so that would need to be fixed
671060SN/A    // if we ever added it back.
681060SN/A    assert(pkt->isRequest());
692348SN/A
701060SN/A    if (pkt->memInhibitAsserted()) {
712292SN/A        // snooper will supply based on copy of packet
721061SN/A        // still target's responsibility to delete packet
731061SN/A        delete pkt;
741061SN/A        return true;
751061SN/A    }
761461SN/A
771060SN/A    bool needsResponse = pkt->needsResponse();
781060SN/A    Tick latency = recvAtomic(pkt);
792348SN/A    // turn packet around to go back to requester if response expected
801060SN/A    if (needsResponse) {
812292SN/A        // recvAtomic() should already have turned packet into
821061SN/A        // atomic response
831061SN/A        assert(pkt->isResponse());
841061SN/A        schedSendTiming(pkt, curTick + latency);
851061SN/A    } else {
861461SN/A        delete pkt;
871062SN/A    }
882292SN/A
892292SN/A    return true;
902292SN/A}
914636Sgblack@eecs.umich.edu
927720Sgblack@eecs.umich.edu
932292SN/Avoid
942292SN/ASimpleTimingPort::schedSendTiming(PacketPtr pkt, Tick when)
952292SN/A{
961060SN/A    assert(when > curTick);
971060SN/A    assert(when < curTick + Clock::Int::ms);
981060SN/A
991060SN/A    // Nothing is on the list: add it and schedule an event
1001061SN/A    if (transmitList.empty() || when < transmitList.front().tick) {
1011061SN/A        transmitList.push_front(DeferredPacket(when, pkt));
1021061SN/A        schedSendEvent(when);
1031061SN/A        return;
1041461SN/A    }
1051060SN/A
1061060SN/A    // list is non-empty & this belongs at the end
1072348SN/A    if (when >= transmitList.back().tick) {
1082292SN/A        transmitList.push_back(DeferredPacket(when, pkt));
1091060SN/A        return;
1101060SN/A    }
1111060SN/A
1121060SN/A    // this belongs in the middle somewhere
1131060SN/A    DeferredPacketIterator i = transmitList.begin();
1141060SN/A    i++; // already checked for insertion at front
1151062SN/A    DeferredPacketIterator end = transmitList.end();
1161062SN/A
1172292SN/A    for (; i != end; ++i) {
1181062SN/A        if (when < i->tick) {
1191061SN/A            transmitList.insert(i, DeferredPacket(when, pkt));
1201061SN/A            return;
1214636Sgblack@eecs.umich.edu        }
1227720Sgblack@eecs.umich.edu    }
1232292SN/A    assert(false); // should never get here
1242292SN/A}
1251060SN/A
1261060SN/A
1272292SN/Avoid
1281060SN/ASimpleTimingPort::sendDeferredPacket()
1291060SN/A{
1301060SN/A    assert(deferredPacketReady());
1311060SN/A    // take packet off list here; if recvTiming() on the other side
1322292SN/A    // calls sendTiming() back on us (like SimpleTimingCpu does), then
1331060SN/A    // we get confused by having a non-active packet on transmitList
1341060SN/A    DeferredPacket dp = transmitList.front();
1352292SN/A    transmitList.pop_front();
1362292SN/A    bool success = sendTiming(dp.pkt);
1372292SN/A
1382292SN/A    if (success) {
1392292SN/A        if (!transmitList.empty() && !sendEvent->scheduled()) {
1401060SN/A            Tick time = transmitList.front().tick;
1412292SN/A            schedule(sendEvent, time <= curTick ? curTick+1 : time);
1422292SN/A        }
1432292SN/A
1442292SN/A        if (transmitList.empty() && drainEvent) {
1452292SN/A            drainEvent->process();
1461060SN/A            drainEvent = NULL;
1471060SN/A        }
1482292SN/A    } else {
1491060SN/A        // Unsuccessful, need to put back on transmitList.  Callee
1501060SN/A        // should not have messed with it (since it didn't accept that
1512292SN/A        // packet), so we can just push it back on the front.
1522292SN/A        assert(!sendEvent->scheduled());
1532292SN/A        transmitList.push_front(dp);
1542292SN/A    }
1551060SN/A
1562292SN/A    waitingOnRetry = !success;
1571060SN/A
1581061SN/A    if (waitingOnRetry) {
1591061SN/A        DPRINTF(Bus, "Send failed, waiting on retry\n");
1604636Sgblack@eecs.umich.edu    }
1617720Sgblack@eecs.umich.edu}
1621060SN/A
1631060SN/A
1641060SN/Avoid
1651060SN/ASimpleTimingPort::recvRetry()
1661060SN/A{
1671061SN/A    DPRINTF(Bus, "Received retry\n");
1682292SN/A    assert(waitingOnRetry);
1692292SN/A    sendDeferredPacket();
1702292SN/A}
1712292SN/A
1721061SN/A
1731061SN/Avoid
1741061SN/ASimpleTimingPort::processSendEvent()
1751061SN/A{
1762292SN/A    assert(!waitingOnRetry);
1772292SN/A    sendDeferredPacket();
1782292SN/A}
1792292SN/A
1802292SN/A
1812292SN/Aunsigned int
1822292SN/ASimpleTimingPort::drain(Event *de)
1832292SN/A{
1841060SN/A    if (transmitList.size() == 0)
1851060SN/A        return 0;
1862292SN/A    drainEvent = de;
1872292SN/A    return 1;
1882292SN/A}
1892292SN/A