packet_queue.cc revision 4666
1955SN/A/*
2955SN/A * Copyright (c) 2006 The Regents of The University of Michigan
31762SN/A * All rights reserved.
4955SN/A *
5955SN/A * Redistribution and use in source and binary forms, with or without
6955SN/A * modification, are permitted provided that the following conditions are
7955SN/A * met: redistributions of source code must retain the above copyright
8955SN/A * notice, this list of conditions and the following disclaimer;
9955SN/A * redistributions in binary form must reproduce the above copyright
10955SN/A * notice, this list of conditions and the following disclaimer in the
11955SN/A * documentation and/or other materials provided with the distribution;
12955SN/A * neither the name of the copyright holders nor the names of its
13955SN/A * contributors may be used to endorse or promote products derived from
14955SN/A * this software without specific prior written permission.
15955SN/A *
16955SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17955SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18955SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19955SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20955SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21955SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22955SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23955SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24955SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25955SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26955SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27955SN/A *
282665Ssaidi@eecs.umich.edu * Authors: Ali Saidi
294762Snate@binkert.org */
30955SN/A
315522Snate@binkert.org#include "mem/tport.hh"
326143Snate@binkert.org
334762Snate@binkert.orgvoid
345522Snate@binkert.orgSimpleTimingPort::checkFunctional(PacketPtr pkt)
35955SN/A{
365522Snate@binkert.org    DeferredPacketIterator i = transmitList.begin();
37955SN/A    DeferredPacketIterator end = transmitList.end();
385522Snate@binkert.org
394202Sbinkertn@umich.edu    for (; i != end; ++i) {
405742Snate@binkert.org        PacketPtr target = i->pkt;
41955SN/A        // If the target contains data, and it overlaps the
424381Sbinkertn@umich.edu        // probed request, need to update data
434381Sbinkertn@umich.edu        if (target->intersect(pkt)) {
448334Snate@binkert.org            if (!fixPacket(pkt, target)) {
45955SN/A                // fixPacket returns true for continue, false for done
46955SN/A                return;
474202Sbinkertn@umich.edu            }
48955SN/A        }
494382Sbinkertn@umich.edu    }
504382Sbinkertn@umich.edu}
514382Sbinkertn@umich.edu
526654Snate@binkert.orgvoid
535517Snate@binkert.orgSimpleTimingPort::recvFunctional(PacketPtr pkt)
548614Sgblack@eecs.umich.edu{
557674Snate@binkert.org    checkFunctional(pkt);
566143Snate@binkert.org
576143Snate@binkert.org    // Just do an atomic access and throw away the returned latency
586143Snate@binkert.org    if (pkt->result != Packet::Success)
598233Snate@binkert.org        recvAtomic(pkt);
608233Snate@binkert.org}
618233Snate@binkert.org
628233Snate@binkert.orgbool
638233Snate@binkert.orgSimpleTimingPort::recvTiming(PacketPtr pkt)
648334Snate@binkert.org{
658334Snate@binkert.org    // If the device is only a slave, it should only be sending
668233Snate@binkert.org    // responses, which should never get nacked.  There used to be
678233Snate@binkert.org    // code to hanldle nacks here, but I'm pretty sure it didn't work
688233Snate@binkert.org    // correctly with the drain code, so that would need to be fixed
698233Snate@binkert.org    // if we ever added it back.
708233Snate@binkert.org    assert(pkt->isRequest());
718233Snate@binkert.org    assert(pkt->result == Packet::Unknown);
726143Snate@binkert.org    bool needsResponse = pkt->needsResponse();
738233Snate@binkert.org    Tick latency = recvAtomic(pkt);
748233Snate@binkert.org    // turn packet around to go back to requester if response expected
758233Snate@binkert.org    if (needsResponse) {
766143Snate@binkert.org        // recvAtomic() should already have turned packet into atomic response
776143Snate@binkert.org        assert(pkt->isResponse());
786143Snate@binkert.org        pkt->convertAtomicToTimingResponse();
796143Snate@binkert.org        schedSendTiming(pkt, curTick + latency);
808233Snate@binkert.org    } else {
818233Snate@binkert.org        delete pkt->req;
828233Snate@binkert.org        delete pkt;
836143Snate@binkert.org    }
848233Snate@binkert.org    return true;
858233Snate@binkert.org}
868233Snate@binkert.org
878233Snate@binkert.org
886143Snate@binkert.orgvoid
896143Snate@binkert.orgSimpleTimingPort::schedSendTiming(PacketPtr pkt, Tick when)
906143Snate@binkert.org{
914762Snate@binkert.org    assert(when > curTick);
926143Snate@binkert.org
938233Snate@binkert.org    // Nothing is on the list: add it and schedule an event
948233Snate@binkert.org    if (transmitList.empty() || when < transmitList.front().tick) {
958233Snate@binkert.org        transmitList.push_front(DeferredPacket(when, pkt));
968233Snate@binkert.org        schedSendEvent(when);
978233Snate@binkert.org        return;
986143Snate@binkert.org    }
998233Snate@binkert.org
1008233Snate@binkert.org    // list is non-empty and this is not the head, so event should
1018233Snate@binkert.org    // already be scheduled
1028233Snate@binkert.org    assert(waitingOnRetry ||
1036143Snate@binkert.org           (sendEvent->scheduled() && sendEvent->when() <= when));
1046143Snate@binkert.org
1056143Snate@binkert.org    // list is non-empty & this belongs at the end
1066143Snate@binkert.org    if (when >= transmitList.back().tick) {
1076143Snate@binkert.org        transmitList.push_back(DeferredPacket(when, pkt));
1086143Snate@binkert.org        return;
1096143Snate@binkert.org    }
1106143Snate@binkert.org
1116143Snate@binkert.org    // this belongs in the middle somewhere
1127065Snate@binkert.org    DeferredPacketIterator i = transmitList.begin();
1136143Snate@binkert.org    i++; // already checked for insertion at front
1148233Snate@binkert.org    DeferredPacketIterator end = transmitList.end();
1158233Snate@binkert.org
1168233Snate@binkert.org    for (; i != end; ++i) {
1178233Snate@binkert.org        if (when < i->tick) {
1188233Snate@binkert.org            transmitList.insert(i, DeferredPacket(when, pkt));
1198233Snate@binkert.org            return;
1208233Snate@binkert.org        }
1218233Snate@binkert.org    }
1228233Snate@binkert.org    assert(false); // should never get here
1238233Snate@binkert.org}
1248233Snate@binkert.org
1258233Snate@binkert.org
1268233Snate@binkert.orgvoid
1278233Snate@binkert.orgSimpleTimingPort::sendDeferredPacket()
1288233Snate@binkert.org{
1298233Snate@binkert.org    assert(deferredPacketReady());
1308233Snate@binkert.org    bool success = sendTiming(transmitList.front().pkt);
1318233Snate@binkert.org
1328233Snate@binkert.org    if (success) {
1338233Snate@binkert.org        //send successful, remove packet
1348233Snate@binkert.org        transmitList.pop_front();
1358233Snate@binkert.org        if (!transmitList.empty()) {
1368233Snate@binkert.org            Tick time = transmitList.front().tick;
1378233Snate@binkert.org            sendEvent->schedule(time <= curTick ? curTick+1 : time);
1388233Snate@binkert.org        }
1398233Snate@binkert.org
1408233Snate@binkert.org        if (transmitList.empty() && drainEvent) {
1418233Snate@binkert.org            drainEvent->process();
1428233Snate@binkert.org            drainEvent = NULL;
1438233Snate@binkert.org        }
1448233Snate@binkert.org    }
1456143Snate@binkert.org
1466143Snate@binkert.org    waitingOnRetry = !success;
1476143Snate@binkert.org
1486143Snate@binkert.org    if (waitingOnRetry) {
1496143Snate@binkert.org        DPRINTF(Bus, "Send failed, waiting on retry\n");
1506143Snate@binkert.org    }
1516143Snate@binkert.org}
1526143Snate@binkert.org
1536143Snate@binkert.org
1548945Ssteve.reinhardt@amd.comvoid
1558233Snate@binkert.orgSimpleTimingPort::recvRetry()
1568233Snate@binkert.org{
1576143Snate@binkert.org    DPRINTF(Bus, "Received retry\n");
1588945Ssteve.reinhardt@amd.com    assert(waitingOnRetry);
1596143Snate@binkert.org    sendDeferredPacket();
1606143Snate@binkert.org}
1616143Snate@binkert.org
1626143Snate@binkert.org
1635522Snate@binkert.orgvoid
1646143Snate@binkert.orgSimpleTimingPort::processSendEvent()
1656143Snate@binkert.org{
1666143Snate@binkert.org    assert(!waitingOnRetry);
1676143Snate@binkert.org    sendDeferredPacket();
1688233Snate@binkert.org}
1698233Snate@binkert.org
1708233Snate@binkert.org
1716143Snate@binkert.orgunsigned int
1726143Snate@binkert.orgSimpleTimingPort::drain(Event *de)
1736143Snate@binkert.org{
1746143Snate@binkert.org    if (transmitList.size() == 0)
1755522Snate@binkert.org        return 0;
1765522Snate@binkert.org    drainEvent = de;
1775522Snate@binkert.org    return 1;
1785522Snate@binkert.org}
1795604Snate@binkert.org