tport.cc revision 8708
12914Ssaidi@eecs.umich.edu/* 22914Ssaidi@eecs.umich.edu * Copyright (c) 2006 The Regents of The University of Michigan 32914Ssaidi@eecs.umich.edu * All rights reserved. 42914Ssaidi@eecs.umich.edu * 52914Ssaidi@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 62914Ssaidi@eecs.umich.edu * modification, are permitted provided that the following conditions are 72914Ssaidi@eecs.umich.edu * met: redistributions of source code must retain the above copyright 82914Ssaidi@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 92914Ssaidi@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 102914Ssaidi@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 112914Ssaidi@eecs.umich.edu * documentation and/or other materials provided with the distribution; 122914Ssaidi@eecs.umich.edu * neither the name of the copyright holders nor the names of its 132914Ssaidi@eecs.umich.edu * contributors may be used to endorse or promote products derived from 142914Ssaidi@eecs.umich.edu * this software without specific prior written permission. 152914Ssaidi@eecs.umich.edu * 162914Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172914Ssaidi@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182914Ssaidi@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192914Ssaidi@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202914Ssaidi@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212914Ssaidi@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222914Ssaidi@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232914Ssaidi@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242914Ssaidi@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252914Ssaidi@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262914Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272914Ssaidi@eecs.umich.edu * 282914Ssaidi@eecs.umich.edu * Authors: Ali Saidi 292914Ssaidi@eecs.umich.edu */ 302914Ssaidi@eecs.umich.edu 318232Snate@binkert.org#include "debug/Bus.hh" 328708Sandreas.hansson@arm.com#include "mem/mem_object.hh" 332914Ssaidi@eecs.umich.edu#include "mem/tport.hh" 342914Ssaidi@eecs.umich.edu 355740Snate@binkert.orgusing namespace std; 365740Snate@binkert.org 375740Snate@binkert.orgSimpleTimingPort::SimpleTimingPort(string pname, MemObject *_owner) 388708Sandreas.hansson@arm.com : Port(pname, _owner), sendEvent(NULL), drainEvent(NULL), 395740Snate@binkert.org waitingOnRetry(false) 405740Snate@binkert.org{ 415740Snate@binkert.org sendEvent = new EventWrapper<SimpleTimingPort, 425740Snate@binkert.org &SimpleTimingPort::processSendEvent>(this); 435740Snate@binkert.org} 445740Snate@binkert.org 455740Snate@binkert.orgSimpleTimingPort::~SimpleTimingPort() 465740Snate@binkert.org{ 475740Snate@binkert.org delete sendEvent; 485740Snate@binkert.org} 495740Snate@binkert.org 504929Sstever@gmail.combool 514490Sstever@eecs.umich.eduSimpleTimingPort::checkFunctional(PacketPtr pkt) 523091Sstever@eecs.umich.edu{ 534490Sstever@eecs.umich.edu DeferredPacketIterator i = transmitList.begin(); 544490Sstever@eecs.umich.edu DeferredPacketIterator end = transmitList.end(); 553296Ssaidi@eecs.umich.edu 564492Sstever@eecs.umich.edu for (; i != end; ++i) { 574490Sstever@eecs.umich.edu PacketPtr target = i->pkt; 583284Srdreslin@umich.edu // If the target contains data, and it overlaps the 593284Srdreslin@umich.edu // probed request, need to update data 604874Sstever@eecs.umich.edu if (pkt->checkFunctional(target)) { 614929Sstever@gmail.com return true; 624490Sstever@eecs.umich.edu } 633284Srdreslin@umich.edu } 644929Sstever@gmail.com 654929Sstever@gmail.com return false; 664490Sstever@eecs.umich.edu} 673342Srdreslin@umich.edu 684490Sstever@eecs.umich.eduvoid 694490Sstever@eecs.umich.eduSimpleTimingPort::recvFunctional(PacketPtr pkt) 704490Sstever@eecs.umich.edu{ 714929Sstever@gmail.com if (!checkFunctional(pkt)) { 724929Sstever@gmail.com // Just do an atomic access and throw away the returned latency 733296Ssaidi@eecs.umich.edu recvAtomic(pkt); 744929Sstever@gmail.com } 753091Sstever@eecs.umich.edu} 763091Sstever@eecs.umich.edu 773091Sstever@eecs.umich.edubool 783349Sbinkertn@umich.eduSimpleTimingPort::recvTiming(PacketPtr pkt) 793091Sstever@eecs.umich.edu{ 803091Sstever@eecs.umich.edu // If the device is only a slave, it should only be sending 813091Sstever@eecs.umich.edu // responses, which should never get nacked. There used to be 823091Sstever@eecs.umich.edu // code to hanldle nacks here, but I'm pretty sure it didn't work 833091Sstever@eecs.umich.edu // correctly with the drain code, so that would need to be fixed 843091Sstever@eecs.umich.edu // if we ever added it back. 854670Sstever@eecs.umich.edu 864670Sstever@eecs.umich.edu if (pkt->memInhibitAsserted()) { 874670Sstever@eecs.umich.edu // snooper will supply based on copy of packet 884670Sstever@eecs.umich.edu // still target's responsibility to delete packet 894670Sstever@eecs.umich.edu delete pkt; 904670Sstever@eecs.umich.edu return true; 914670Sstever@eecs.umich.edu } 924670Sstever@eecs.umich.edu 934626Sstever@eecs.umich.edu bool needsResponse = pkt->needsResponse(); 943091Sstever@eecs.umich.edu Tick latency = recvAtomic(pkt); 953175Srdreslin@umich.edu // turn packet around to go back to requester if response expected 964626Sstever@eecs.umich.edu if (needsResponse) { 974670Sstever@eecs.umich.edu // recvAtomic() should already have turned packet into 984670Sstever@eecs.umich.edu // atomic response 994626Sstever@eecs.umich.edu assert(pkt->isResponse()); 1007823Ssteve.reinhardt@amd.com schedSendTiming(pkt, curTick() + latency); 1014626Sstever@eecs.umich.edu } else { 1024490Sstever@eecs.umich.edu delete pkt; 1033309Srdreslin@umich.edu } 1044670Sstever@eecs.umich.edu 1053091Sstever@eecs.umich.edu return true; 1063091Sstever@eecs.umich.edu} 1073091Sstever@eecs.umich.edu 1088708Sandreas.hansson@arm.comvoid 1098708Sandreas.hansson@arm.comSimpleTimingPort::schedSendEvent(Tick when) 1108708Sandreas.hansson@arm.com{ 1118708Sandreas.hansson@arm.com if (waitingOnRetry) { 1128708Sandreas.hansson@arm.com assert(!sendEvent->scheduled()); 1138708Sandreas.hansson@arm.com return; 1148708Sandreas.hansson@arm.com } 1158708Sandreas.hansson@arm.com 1168708Sandreas.hansson@arm.com if (!sendEvent->scheduled()) { 1178708Sandreas.hansson@arm.com owner->schedule(sendEvent, when); 1188708Sandreas.hansson@arm.com } else if (sendEvent->when() > when) { 1198708Sandreas.hansson@arm.com owner->reschedule(sendEvent, when); 1208708Sandreas.hansson@arm.com } 1218708Sandreas.hansson@arm.com} 1222914Ssaidi@eecs.umich.edu 1232914Ssaidi@eecs.umich.eduvoid 1244492Sstever@eecs.umich.eduSimpleTimingPort::schedSendTiming(PacketPtr pkt, Tick when) 1253403Ssaidi@eecs.umich.edu{ 1267823Ssteve.reinhardt@amd.com assert(when > curTick()); 1277823Ssteve.reinhardt@amd.com assert(when < curTick() + SimClock::Int::ms); 1284492Sstever@eecs.umich.edu 1293450Ssaidi@eecs.umich.edu // Nothing is on the list: add it and schedule an event 1304666Sstever@eecs.umich.edu if (transmitList.empty() || when < transmitList.front().tick) { 1314666Sstever@eecs.umich.edu transmitList.push_front(DeferredPacket(when, pkt)); 1324666Sstever@eecs.umich.edu schedSendEvent(when); 1334666Sstever@eecs.umich.edu return; 1344666Sstever@eecs.umich.edu } 1354666Sstever@eecs.umich.edu 1364666Sstever@eecs.umich.edu // list is non-empty & this belongs at the end 1374666Sstever@eecs.umich.edu if (when >= transmitList.back().tick) { 1384492Sstever@eecs.umich.edu transmitList.push_back(DeferredPacket(when, pkt)); 1393450Ssaidi@eecs.umich.edu return; 1403403Ssaidi@eecs.umich.edu } 1413450Ssaidi@eecs.umich.edu 1424666Sstever@eecs.umich.edu // this belongs in the middle somewhere 1434490Sstever@eecs.umich.edu DeferredPacketIterator i = transmitList.begin(); 1444666Sstever@eecs.umich.edu i++; // already checked for insertion at front 1454490Sstever@eecs.umich.edu DeferredPacketIterator end = transmitList.end(); 1463450Ssaidi@eecs.umich.edu 1474492Sstever@eecs.umich.edu for (; i != end; ++i) { 1484492Sstever@eecs.umich.edu if (when < i->tick) { 1494492Sstever@eecs.umich.edu transmitList.insert(i, DeferredPacket(when, pkt)); 1504492Sstever@eecs.umich.edu return; 1513610Srdreslin@umich.edu } 1523450Ssaidi@eecs.umich.edu } 1534492Sstever@eecs.umich.edu assert(false); // should never get here 1543403Ssaidi@eecs.umich.edu} 1553403Ssaidi@eecs.umich.edu 1564492Sstever@eecs.umich.edu 1573403Ssaidi@eecs.umich.eduvoid 1584492Sstever@eecs.umich.eduSimpleTimingPort::sendDeferredPacket() 1592914Ssaidi@eecs.umich.edu{ 1604492Sstever@eecs.umich.edu assert(deferredPacketReady()); 1614870Sstever@eecs.umich.edu // take packet off list here; if recvTiming() on the other side 1624870Sstever@eecs.umich.edu // calls sendTiming() back on us (like SimpleTimingCpu does), then 1634870Sstever@eecs.umich.edu // we get confused by having a non-active packet on transmitList 1644870Sstever@eecs.umich.edu DeferredPacket dp = transmitList.front(); 1654870Sstever@eecs.umich.edu transmitList.pop_front(); 1664870Sstever@eecs.umich.edu bool success = sendTiming(dp.pkt); 1674492Sstever@eecs.umich.edu 1684492Sstever@eecs.umich.edu if (success) { 1694870Sstever@eecs.umich.edu if (!transmitList.empty() && !sendEvent->scheduled()) { 1704490Sstever@eecs.umich.edu Tick time = transmitList.front().tick; 1718708Sandreas.hansson@arm.com owner->schedule(sendEvent, time <= curTick() ? curTick()+1 : time); 1723263Srdreslin@umich.edu } 1734492Sstever@eecs.umich.edu 1747510Stjones1@inf.ed.ac.uk if (transmitList.empty() && drainEvent && !sendEvent->scheduled()) { 1754490Sstever@eecs.umich.edu drainEvent->process(); 1764490Sstever@eecs.umich.edu drainEvent = NULL; 1773091Sstever@eecs.umich.edu } 1784870Sstever@eecs.umich.edu } else { 1794870Sstever@eecs.umich.edu // Unsuccessful, need to put back on transmitList. Callee 1804870Sstever@eecs.umich.edu // should not have messed with it (since it didn't accept that 1814870Sstever@eecs.umich.edu // packet), so we can just push it back on the front. 1824870Sstever@eecs.umich.edu assert(!sendEvent->scheduled()); 1834870Sstever@eecs.umich.edu transmitList.push_front(dp); 1843091Sstever@eecs.umich.edu } 1854492Sstever@eecs.umich.edu 1864492Sstever@eecs.umich.edu waitingOnRetry = !success; 1874492Sstever@eecs.umich.edu 1884492Sstever@eecs.umich.edu if (waitingOnRetry) { 1894492Sstever@eecs.umich.edu DPRINTF(Bus, "Send failed, waiting on retry\n"); 1904492Sstever@eecs.umich.edu } 1914492Sstever@eecs.umich.edu} 1924492Sstever@eecs.umich.edu 1934492Sstever@eecs.umich.edu 1944492Sstever@eecs.umich.eduvoid 1954492Sstever@eecs.umich.eduSimpleTimingPort::recvRetry() 1964492Sstever@eecs.umich.edu{ 1974492Sstever@eecs.umich.edu DPRINTF(Bus, "Received retry\n"); 1984492Sstever@eecs.umich.edu assert(waitingOnRetry); 1994492Sstever@eecs.umich.edu sendDeferredPacket(); 2004492Sstever@eecs.umich.edu} 2014492Sstever@eecs.umich.edu 2024492Sstever@eecs.umich.edu 2034492Sstever@eecs.umich.eduvoid 2044492Sstever@eecs.umich.eduSimpleTimingPort::processSendEvent() 2054492Sstever@eecs.umich.edu{ 2064492Sstever@eecs.umich.edu assert(!waitingOnRetry); 2074492Sstever@eecs.umich.edu sendDeferredPacket(); 2082914Ssaidi@eecs.umich.edu} 2092914Ssaidi@eecs.umich.edu 2102914Ssaidi@eecs.umich.edu 2112914Ssaidi@eecs.umich.eduunsigned int 2122914Ssaidi@eecs.umich.eduSimpleTimingPort::drain(Event *de) 2132914Ssaidi@eecs.umich.edu{ 2147510Stjones1@inf.ed.ac.uk if (transmitList.size() == 0 && !sendEvent->scheduled()) 2152914Ssaidi@eecs.umich.edu return 0; 2162914Ssaidi@eecs.umich.edu drainEvent = de; 2172914Ssaidi@eecs.umich.edu return 1; 2182914Ssaidi@eecs.umich.edu} 219