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