base.hh revision 3606
18504SN/A/*
28504SN/A * Copyright (c) 2003-2005 The Regents of The University of Michigan
38504SN/A * All rights reserved.
48825Snilay@cs.wisc.edu *
58504SN/A * Redistribution and use in source and binary forms, with or without
68504SN/A * modification, are permitted provided that the following conditions are
78504SN/A * met: redistributions of source code must retain the above copyright
88504SN/A * notice, this list of conditions and the following disclaimer;
98504SN/A * redistributions in binary form must reproduce the above copyright
108504SN/A * notice, this list of conditions and the following disclaimer in the
118835SAli.Saidi@ARM.com * documentation and/or other materials provided with the distribution;
128504SN/A * neither the name of the copyright holders nor the names of its
138504SN/A * contributors may be used to endorse or promote products derived from
148504SN/A * this software without specific prior written permission.
158504SN/A *
168504SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
178504SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
189039Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
198504SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
208504SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
218504SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
228673SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
238504SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
248504SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
258504SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
268504SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
278504SN/A *
288504SN/A * Authors: Erik Hallnor
298504SN/A */
308504SN/A
318504SN/A/**
328504SN/A * @file
338963Sgblack@eecs.umich.edu * Declares a basic cache interface BaseCache.
348504SN/A */
358504SN/A
368504SN/A#ifndef __BASE_CACHE_HH__
378504SN/A#define __BASE_CACHE_HH__
388504SN/A
398504SN/A#include <vector>
408504SN/A#include <string>
418504SN/A#include <list>
428504SN/A#include <inttypes.h>
438504SN/A
448504SN/A#include "base/misc.hh"
458504SN/A#include "base/statistics.hh"
468504SN/A#include "base/trace.hh"
478504SN/A#include "mem/mem_object.hh"
488504SN/A#include "mem/packet.hh"
498504SN/A#include "mem/port.hh"
508504SN/A#include "mem/request.hh"
518504SN/A#include "sim/eventq.hh"
528835SAli.Saidi@ARM.com
538835SAli.Saidi@ARM.com/**
548835SAli.Saidi@ARM.com * Reasons for Caches to be Blocked.
558835SAli.Saidi@ARM.com */
568835SAli.Saidi@ARM.comenum BlockedCause{
578835SAli.Saidi@ARM.com    Blocked_NoMSHRs,
588835SAli.Saidi@ARM.com    Blocked_NoTargets,
598835SAli.Saidi@ARM.com    Blocked_NoWBBuffers,
608963Sgblack@eecs.umich.edu    Blocked_Coherence,
618963Sgblack@eecs.umich.edu    NUM_BLOCKED_CAUSES
628835SAli.Saidi@ARM.com};
638504SN/A
648504SN/A/**
658504SN/A * Reasons for cache to request a bus.
668504SN/A */
678721SN/Aenum RequestCause{
688721SN/A    Request_MSHR,
698721SN/A    Request_WB,
708504SN/A    Request_Coherence,
718963Sgblack@eecs.umich.edu    Request_PF
728963Sgblack@eecs.umich.edu};
738504SN/A
748504SN/Aclass MSHR;
758504SN/A/**
768504SN/A * A basic cache interface. Implements some common functions for speed.
778504SN/A */
788504SN/Aclass BaseCache : public MemObject
798504SN/A{
808504SN/A    class CachePort : public Port
818504SN/A    {
828504SN/A      public:
838504SN/A        BaseCache *cache;
848504SN/A
858504SN/A        CachePort(const std::string &_name, BaseCache *_cache, bool _isCpuSide);
868504SN/A
878504SN/A      protected:
888504SN/A        virtual bool recvTiming(PacketPtr pkt);
898504SN/A
908504SN/A        virtual Tick recvAtomic(PacketPtr pkt);
918504SN/A
928504SN/A        virtual void recvFunctional(PacketPtr pkt);
938504SN/A
948504SN/A        virtual void recvStatusChange(Status status);
958504SN/A
968504SN/A        virtual void getDeviceAddressRanges(AddrRangeList &resp,
978504SN/A                                            AddrRangeList &snoop);
988504SN/A
998504SN/A        virtual int deviceBlockSize();
1008504SN/A
1018504SN/A        virtual void recvRetry();
1028504SN/A
1038504SN/A      public:
1048504SN/A        void setBlocked();
1058504SN/A
1068504SN/A        void clearBlocked();
1078504SN/A
1088504SN/A        bool checkFunctional(PacketPtr pkt);
1098504SN/A
1108504SN/A        void checkAndSendFunctional(PacketPtr pkt);
1118504SN/A
1128504SN/A        bool canDrain() { return drainList.empty() && transmitList.empty(); }
1138504SN/A
1148504SN/A        bool blocked;
1158504SN/A
1168504SN/A        bool mustSendRetry;
1178504SN/A
1188504SN/A        bool isCpuSide;
1198504SN/A
1208504SN/A        bool waitingOnRetry;
1218504SN/A
1228504SN/A        std::list<PacketPtr> drainList;
1238504SN/A
1248504SN/A        std::list<std::pair<Tick,PacketPtr> > transmitList;
1258504SN/A    };
1268504SN/A
1278504SN/A    struct CacheEvent : public Event
1288504SN/A    {
1298504SN/A        CachePort *cachePort;
1308504SN/A        PacketPtr pkt;
1318504SN/A        bool newResponse;
1328504SN/A
1338504SN/A        CacheEvent(CachePort *_cachePort, bool response);
1348504SN/A        void process();
1358728SN/A        const char *description();
1368504SN/A    };
1378504SN/A
1388504SN/A  public: //Made public so coherence can get at it.
1398504SN/A    CachePort *cpuSidePort;
1408504SN/A
1418504SN/A    CacheEvent *sendEvent;
1428504SN/A    CacheEvent *memSendEvent;
1438504SN/A
1448504SN/A  protected:
1458504SN/A    CachePort *memSidePort;
1468504SN/A
1478504SN/A    bool snoopRangesSent;
1488504SN/A
1498504SN/A  public:
1508504SN/A    virtual Port *getPort(const std::string &if_name, int idx = -1);
1518504SN/A
1528504SN/A  private:
1538504SN/A    //To be defined in cache_impl.hh not in base class
1548504SN/A    virtual bool doTimingAccess(PacketPtr pkt, CachePort *cachePort, bool isCpuSide)
1558504SN/A    {
1568504SN/A        fatal("No implementation");
1578504SN/A    }
1588504SN/A
1598504SN/A    virtual Tick doAtomicAccess(PacketPtr pkt, bool isCpuSide)
1608504SN/A    {
1618521SN/A        fatal("No implementation");
1628504SN/A    }
1638504SN/A
1648504SN/A    virtual void doFunctionalAccess(PacketPtr pkt, bool isCpuSide)
1658504SN/A    {
1668504SN/A        fatal("No implementation");
1678825Snilay@cs.wisc.edu    }
1688504SN/A
1698504SN/A    void recvStatusChange(Port::Status status, bool isCpuSide)
1708504SN/A    {
1718504SN/A        if (status == Port::RangeChange){
1728504SN/A            if (!isCpuSide) {
1738963Sgblack@eecs.umich.edu                cpuSidePort->sendStatusChange(Port::RangeChange);
1748504SN/A                if (!snoopRangesSent) {
1758504SN/A                    snoopRangesSent = true;
1768504SN/A                    memSidePort->sendStatusChange(Port::RangeChange);
1778504SN/A                }
1788504SN/A            }
1798504SN/A            else {
1808504SN/A                memSidePort->sendStatusChange(Port::RangeChange);
1818504SN/A            }
1828504SN/A        }
1838835SAli.Saidi@ARM.com    }
1848504SN/A
1858504SN/A    virtual PacketPtr getPacket()
1868504SN/A    {
1878504SN/A        fatal("No implementation");
1888835SAli.Saidi@ARM.com    }
1898504SN/A
1908504SN/A    virtual PacketPtr getCoherencePacket()
1918504SN/A    {
1928504SN/A        fatal("No implementation");
1938504SN/A    }
1948963Sgblack@eecs.umich.edu
1958504SN/A    virtual void sendResult(PacketPtr &pkt, MSHR* mshr, bool success)
1968504SN/A    {
1978504SN/A
1988504SN/A        fatal("No implementation");
1998504SN/A    }
2008504SN/A
2018504SN/A    virtual void sendCoherenceResult(PacketPtr &pkt, MSHR* mshr, bool success)
2028504SN/A    {
2038504SN/A
2048504SN/A        fatal("No implementation");
2058504SN/A    }
2068504SN/A
2078504SN/A    /**
2088504SN/A     * Bit vector of the blocking reasons for the access path.
2098963Sgblack@eecs.umich.edu     * @sa #BlockedCause
2108504SN/A     */
2118504SN/A    uint8_t blocked;
2128504SN/A
2138504SN/A    /**
2148504SN/A     * Bit vector for the blocking reasons for the snoop path.
2158504SN/A     * @sa #BlockedCause
2168504SN/A     */
2178504SN/A    uint8_t blockedSnoop;
2188504SN/A
2198835SAli.Saidi@ARM.com    /**
2208504SN/A     * Bit vector for the outstanding requests for the master interface.
2218504SN/A     */
2228504SN/A    uint8_t masterRequests;
2238504SN/A
2248835SAli.Saidi@ARM.com    /**
2258504SN/A     * Bit vector for the outstanding requests for the slave interface.
2268504SN/A     */
2278504SN/A    uint8_t slaveRequests;
2288504SN/A
2298504SN/A  protected:
2308963Sgblack@eecs.umich.edu
2318504SN/A    /** Stores time the cache blocked for statistics. */
2328504SN/A    Tick blockedCycle;
2338504SN/A
2348504SN/A    /** Block size of this cache */
2358504SN/A    const int blkSize;
2368504SN/A
2378504SN/A    /** The number of misses to trigger an exit event. */
2388504SN/A    Counter missCount;
2398504SN/A
2408504SN/A    /** The drain event. */
2418504SN/A    Event *drainEvent;
2428504SN/A
2438504SN/A  public:
2448504SN/A    // Statistics
2458504SN/A    /**
2468504SN/A     * @addtogroup CacheStatistics
2478504SN/A     * @{
2488504SN/A     */
2498504SN/A
2508504SN/A    /** Number of hits per thread for each type of command. @sa Packet::Command */
2518504SN/A    Stats::Vector<> hits[NUM_MEM_CMDS];
2528504SN/A    /** Number of hits for demand accesses. */
2538504SN/A    Stats::Formula demandHits;
2548504SN/A    /** Number of hit for all accesses. */
2558504SN/A    Stats::Formula overallHits;
2568504SN/A
2578504SN/A    /** Number of misses per thread for each type of command. @sa Packet::Command */
2588504SN/A    Stats::Vector<> misses[NUM_MEM_CMDS];
2598504SN/A    /** Number of misses for demand accesses. */
2608504SN/A    Stats::Formula demandMisses;
2618504SN/A    /** Number of misses for all accesses. */
2628504SN/A    Stats::Formula overallMisses;
2638504SN/A
2648504SN/A    /**
2658504SN/A     * Total number of cycles per thread/command spent waiting for a miss.
2668504SN/A     * Used to calculate the average miss latency.
2678504SN/A     */
2688504SN/A    Stats::Vector<> missLatency[NUM_MEM_CMDS];
2698504SN/A    /** Total number of cycles spent waiting for demand misses. */
2708504SN/A    Stats::Formula demandMissLatency;
2718504SN/A    /** Total number of cycles spent waiting for all misses. */
2728504SN/A    Stats::Formula overallMissLatency;
2738504SN/A
2748504SN/A    /** The number of accesses per command and thread. */
2758504SN/A    Stats::Formula accesses[NUM_MEM_CMDS];
2768504SN/A    /** The number of demand accesses. */
2778504SN/A    Stats::Formula demandAccesses;
2788504SN/A    /** The number of overall accesses. */
2798504SN/A    Stats::Formula overallAccesses;
2808504SN/A
2818504SN/A    /** The miss rate per command and thread. */
2828504SN/A    Stats::Formula missRate[NUM_MEM_CMDS];
2838504SN/A    /** The miss rate of all demand accesses. */
2848504SN/A    Stats::Formula demandMissRate;
2858504SN/A    /** The miss rate for all accesses. */
2868504SN/A    Stats::Formula overallMissRate;
2878504SN/A
2888504SN/A    /** The average miss latency per command and thread. */
2898504SN/A    Stats::Formula avgMissLatency[NUM_MEM_CMDS];
2908504SN/A    /** The average miss latency for demand misses. */
2918504SN/A    Stats::Formula demandAvgMissLatency;
2928504SN/A    /** The average miss latency for all misses. */
2938504SN/A    Stats::Formula overallAvgMissLatency;
2948504SN/A
2958504SN/A    /** The total number of cycles blocked for each blocked cause. */
2968504SN/A    Stats::Vector<> blocked_cycles;
2978504SN/A    /** The number of times this cache blocked for each blocked cause. */
2988504SN/A    Stats::Vector<> blocked_causes;
2998504SN/A
3008504SN/A    /** The average number of cycles blocked for each blocked cause. */
3018504SN/A    Stats::Formula avg_blocked;
3028504SN/A
3038504SN/A    /** The number of fast writes (WH64) performed. */
3048504SN/A    Stats::Scalar<> fastWrites;
3058504SN/A
3068504SN/A    /** The number of cache copies performed. */
3078504SN/A    Stats::Scalar<> cacheCopies;
3088504SN/A
3098504SN/A    /**
3108504SN/A     * @}
3118504SN/A     */
3128504SN/A
3138504SN/A    /**
3148504SN/A     * Register stats for this object.
3158504SN/A     */
3168504SN/A    virtual void regStats();
3178504SN/A
3188504SN/A  public:
3198504SN/A
3208504SN/A    class Params
3218504SN/A    {
3228504SN/A      public:
3238504SN/A        /** List of address ranges of this cache. */
3248504SN/A        std::vector<Range<Addr> > addrRange;
3258504SN/A        /** The hit latency for this cache. */
3268504SN/A        int hitLatency;
3278504SN/A        /** The block size of this cache. */
3288504SN/A        int blkSize;
3298504SN/A        /**
3308504SN/A         * The maximum number of misses this cache should handle before
3318504SN/A         * ending the simulation.
3328504SN/A         */
3338504SN/A        Counter maxMisses;
3348504SN/A
3358504SN/A        /**
3368504SN/A         * Construct an instance of this parameter class.
3378504SN/A         */
3388504SN/A        Params(std::vector<Range<Addr> > addr_range,
3398504SN/A               int hit_latency, int _blkSize, Counter max_misses)
3408504SN/A            : addrRange(addr_range), hitLatency(hit_latency), blkSize(_blkSize),
3418504SN/A              maxMisses(max_misses)
3428504SN/A        {
3438504SN/A        }
3448504SN/A    };
3458504SN/A
3468504SN/A    /**
3478504SN/A     * Create and initialize a basic cache object.
3488504SN/A     * @param name The name of this cache.
3498504SN/A     * @param hier_params Pointer to the HierParams object for this hierarchy
3508504SN/A     * of this cache.
3518504SN/A     * @param params The parameter object for this BaseCache.
3528504SN/A     */
3538504SN/A    BaseCache(const std::string &name, Params &params)
3548504SN/A        : MemObject(name), blocked(0), blockedSnoop(0), masterRequests(0),
3558504SN/A          slaveRequests(0), blkSize(params.blkSize),
3568504SN/A          missCount(params.maxMisses), drainEvent(NULL)
3578504SN/A    {
3588504SN/A        //Start ports at null if more than one is created we should panic
3598504SN/A        cpuSidePort = NULL;
3608504SN/A        memSidePort = NULL;
3618504SN/A        snoopRangesSent = false;
3628504SN/A    }
3638504SN/A
3648504SN/A    ~BaseCache()
3658504SN/A    {
3668504SN/A        delete sendEvent;
3678504SN/A        delete memSendEvent;
3688504SN/A    }
3698504SN/A
3708504SN/A    virtual void init();
3718504SN/A
3728504SN/A    /**
3738504SN/A     * Query block size of a cache.
3748504SN/A     * @return  The block size
3758504SN/A     */
3768504SN/A    int getBlockSize() const
3778504SN/A    {
3788504SN/A        return blkSize;
3798504SN/A    }
3808504SN/A
3818504SN/A    /**
3828504SN/A     * Returns true if the cache is blocked for accesses.
3838504SN/A     */
3848504SN/A    bool isBlocked()
3858504SN/A    {
3868504SN/A        return blocked != 0;
3878504SN/A    }
3888504SN/A
3898504SN/A    /**
3908504SN/A     * Returns true if the cache is blocked for snoops.
3918504SN/A     */
3928504SN/A    bool isBlockedForSnoop()
3938504SN/A    {
3948504SN/A        return blockedSnoop != 0;
3958504SN/A    }
3968504SN/A
3978504SN/A    /**
3988504SN/A     * Marks the access path of the cache as blocked for the given cause. This
3998504SN/A     * also sets the blocked flag in the slave interface.
4008504SN/A     * @param cause The reason for the cache blocking.
4018504SN/A     */
4028504SN/A    void setBlocked(BlockedCause cause)
4038504SN/A    {
4048504SN/A        uint8_t flag = 1 << cause;
4058504SN/A        if (blocked == 0) {
4068504SN/A            blocked_causes[cause]++;
4078504SN/A            blockedCycle = curTick;
4088504SN/A        }
4098504SN/A        int old_state = blocked;
4108504SN/A        if (!(blocked & flag)) {
4118504SN/A            //Wasn't already blocked for this cause
4128504SN/A            blocked |= flag;
4138504SN/A            DPRINTF(Cache,"Blocking for cause %s\n", cause);
4148504SN/A            if (!old_state)
4158504SN/A                cpuSidePort->setBlocked();
4168504SN/A        }
4178504SN/A    }
4188504SN/A
4198504SN/A    /**
4208504SN/A     * Marks the snoop path of the cache as blocked for the given cause. This
4218504SN/A     * also sets the blocked flag in the master interface.
4228504SN/A     * @param cause The reason to block the snoop path.
4238504SN/A     */
4248504SN/A    void setBlockedForSnoop(BlockedCause cause)
4258504SN/A    {
4268504SN/A        uint8_t flag = 1 << cause;
4278504SN/A        uint8_t old_state = blockedSnoop;
4288504SN/A        if (!(blockedSnoop & flag)) {
4298504SN/A            //Wasn't already blocked for this cause
4308504SN/A            blockedSnoop |= flag;
4318504SN/A            if (!old_state)
4328504SN/A                memSidePort->setBlocked();
4338504SN/A        }
4348504SN/A    }
4358504SN/A
4368504SN/A    /**
4378504SN/A     * Marks the cache as unblocked for the given cause. This also clears the
4388504SN/A     * blocked flags in the appropriate interfaces.
4398504SN/A     * @param cause The newly unblocked cause.
4408504SN/A     * @warning Calling this function can cause a blocked request on the bus to
4418504SN/A     * access the cache. The cache must be in a state to handle that request.
4428504SN/A     */
4438504SN/A    void clearBlocked(BlockedCause cause)
4448504SN/A    {
4458504SN/A        uint8_t flag = 1 << cause;
4468504SN/A        DPRINTF(Cache,"Unblocking for cause %s, causes left=%i\n",
4478504SN/A                cause, blocked);
4488504SN/A        if (blocked & flag)
4498504SN/A        {
4508504SN/A            blocked &= ~flag;
4518504SN/A            if (!isBlocked()) {
4528504SN/A                blocked_cycles[cause] += curTick - blockedCycle;
4538504SN/A                DPRINTF(Cache,"Unblocking from all causes\n");
4548504SN/A                cpuSidePort->clearBlocked();
4558504SN/A            }
4568504SN/A        }
4578504SN/A        if (blockedSnoop & flag)
4588504SN/A        {
4598504SN/A            blockedSnoop &= ~flag;
4608504SN/A            if (!isBlockedForSnoop()) {
4618504SN/A                memSidePort->clearBlocked();
4628504SN/A            }
4638504SN/A        }
4648504SN/A    }
4658504SN/A
4668504SN/A    /**
4678504SN/A     * True if the master bus should be requested.
4688504SN/A     * @return True if there are outstanding requests for the master bus.
4698504SN/A     */
4708504SN/A    bool doMasterRequest()
4718504SN/A    {
4728504SN/A        return masterRequests != 0;
4738504SN/A    }
4748504SN/A
4758504SN/A    /**
4768504SN/A     * Request the master bus for the given cause and time.
4778504SN/A     * @param cause The reason for the request.
4788504SN/A     * @param time The time to make the request.
4798504SN/A     */
4808504SN/A    void setMasterRequest(RequestCause cause, Tick time)
4818504SN/A    {
4828504SN/A        if (!doMasterRequest() && !memSidePort->waitingOnRetry)
4838504SN/A        {
4848504SN/A            BaseCache::CacheEvent * reqCpu =
4858504SN/A                new BaseCache::CacheEvent(memSidePort, false);
4868504SN/A            reqCpu->schedule(time);
4878504SN/A        }
4888504SN/A        uint8_t flag = 1<<cause;
4898504SN/A        masterRequests |= flag;
4908504SN/A    }
4918504SN/A
4928504SN/A    /**
4938504SN/A     * Clear the master bus request for the given cause.
4948504SN/A     * @param cause The request reason to clear.
4958504SN/A     */
4968504SN/A    void clearMasterRequest(RequestCause cause)
4978963Sgblack@eecs.umich.edu    {
4988504SN/A        uint8_t flag = 1<<cause;
4998504SN/A        masterRequests &= ~flag;
5008504SN/A        checkDrain();
5018504SN/A    }
5028504SN/A
5038504SN/A    /**
5048504SN/A     * Return true if the slave bus should be requested.
5058504SN/A     * @return True if there are outstanding requests for the slave bus.
5068504SN/A     */
5078835SAli.Saidi@ARM.com    bool doSlaveRequest()
5088504SN/A    {
5098504SN/A        return slaveRequests != 0;
5108504SN/A    }
5118504SN/A
5128835SAli.Saidi@ARM.com    /**
5138504SN/A     * Request the slave bus for the given reason and time.
5148504SN/A     * @param cause The reason for the request.
5158504SN/A     * @param time The time to make the request.
5168504SN/A     */
5178504SN/A    void setSlaveRequest(RequestCause cause, Tick time)
5188963Sgblack@eecs.umich.edu    {
5198504SN/A        if (!doSlaveRequest() && !cpuSidePort->waitingOnRetry)
5208504SN/A        {
5218504SN/A            BaseCache::CacheEvent * reqCpu =
5228504SN/A                new BaseCache::CacheEvent(cpuSidePort, false);
5238504SN/A            reqCpu->schedule(time);
5248504SN/A        }
5258504SN/A        uint8_t flag = 1<<cause;
5268963Sgblack@eecs.umich.edu        slaveRequests |= flag;
5278963Sgblack@eecs.umich.edu    }
5288963Sgblack@eecs.umich.edu
5298504SN/A    /**
5308504SN/A     * Clear the slave bus request for the given reason.
5318504SN/A     * @param cause The request reason to clear.
5328504SN/A     */
5338504SN/A    void clearSlaveRequest(RequestCause cause)
5348504SN/A    {
5358504SN/A        uint8_t flag = 1<<cause;
5368504SN/A        slaveRequests &= ~flag;
5378504SN/A        checkDrain();
5388504SN/A    }
5398504SN/A
5408504SN/A    /**
5418504SN/A     * Send a response to the slave interface.
5428504SN/A     * @param pkt The request being responded to.
5438963Sgblack@eecs.umich.edu     * @param time The time the response is ready.
5448504SN/A     */
5458504SN/A    void respond(PacketPtr pkt, Tick time)
5468504SN/A    {
5478504SN/A        assert(time >= curTick);
5488504SN/A        if (pkt->needsResponse()) {
5498504SN/A/*            CacheEvent *reqCpu = new CacheEvent(cpuSidePort, pkt);
5508504SN/A            reqCpu->schedule(time);
5518504SN/A*/
5528504SN/A            if (cpuSidePort->transmitList.empty()) {
5538835SAli.Saidi@ARM.com                assert(!sendEvent->scheduled());
5548504SN/A                sendEvent->schedule(time);
5558504SN/A                cpuSidePort->transmitList.push_back(std::pair<Tick,PacketPtr>
5568504SN/A                                                    (time,pkt));
5578504SN/A                return;
5588835SAli.Saidi@ARM.com            }
5598504SN/A
5608504SN/A            // something is on the list and this belongs at the end
5618504SN/A            if (time >= cpuSidePort->transmitList.back().first) {
5628504SN/A                cpuSidePort->transmitList.push_back(std::pair<Tick,PacketPtr>
5638504SN/A                                                    (time,pkt));
5648963Sgblack@eecs.umich.edu                return;
5658504SN/A            }
5668504SN/A            // Something is on the list and this belongs somewhere else
5678504SN/A            std::list<std::pair<Tick,PacketPtr> >::iterator i =
5688504SN/A                cpuSidePort->transmitList.begin();
5698504SN/A            std::list<std::pair<Tick,PacketPtr> >::iterator end =
5708504SN/A                cpuSidePort->transmitList.end();
5718504SN/A            bool done = false;
5728504SN/A
5738504SN/A            while (i != end && !done) {
5748504SN/A                if (time < i->first)
5758504SN/A                    cpuSidePort->transmitList.insert(i,std::pair<Tick,PacketPtr>
5768504SN/A                                                     (time,pkt));
5778504SN/A                i++;
5788504SN/A            }
5798504SN/A        }
5808504SN/A        else {
5818504SN/A            if (pkt->cmd != Packet::UpgradeReq)
5828504SN/A            {
5838504SN/A                delete pkt->req;
5848504SN/A                delete pkt;
5858504SN/A            }
5868504SN/A        }
5878504SN/A    }
5888504SN/A
5898504SN/A    /**
5908504SN/A     * Send a reponse to the slave interface and calculate miss latency.
5918504SN/A     * @param pkt The request to respond to.
5928504SN/A     * @param time The time the response is ready.
5938504SN/A     */
5948504SN/A    void respondToMiss(PacketPtr pkt, Tick time)
5958504SN/A    {
5968504SN/A        assert(time >= curTick);
5978504SN/A        if (!pkt->req->isUncacheable()) {
5988504SN/A            missLatency[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/] +=
5998504SN/A                time - pkt->time;
6008504SN/A        }
6018504SN/A        if (pkt->needsResponse()) {
6028504SN/A/*            CacheEvent *reqCpu = new CacheEvent(cpuSidePort, pkt);
6038504SN/A            reqCpu->schedule(time);
6048504SN/A*/
6058504SN/A            if (cpuSidePort->transmitList.empty()) {
6068504SN/A                assert(!sendEvent->scheduled());
6078504SN/A                sendEvent->schedule(time);
6088504SN/A                cpuSidePort->transmitList.push_back(std::pair<Tick,PacketPtr>
6098504SN/A                                                    (time,pkt));
6108504SN/A                return;
6118504SN/A            }
6128504SN/A
6138504SN/A            // something is on the list and this belongs at the end
6148504SN/A            if (time >= cpuSidePort->transmitList.back().first) {
6158504SN/A                cpuSidePort->transmitList.push_back(std::pair<Tick,PacketPtr>
6168504SN/A                                                    (time,pkt));
6178504SN/A                return;
6188504SN/A            }
6198504SN/A            // Something is on the list and this belongs somewhere else
6208504SN/A            std::list<std::pair<Tick,PacketPtr> >::iterator i =
6218504SN/A                cpuSidePort->transmitList.begin();
6228504SN/A            std::list<std::pair<Tick,PacketPtr> >::iterator end =
6238504SN/A                cpuSidePort->transmitList.end();
6248504SN/A            bool done = false;
6258504SN/A
6268504SN/A            while (i != end && !done) {
6278504SN/A                if (time < i->first)
6288504SN/A                    cpuSidePort->transmitList.insert(i,std::pair<Tick,PacketPtr>
6298504SN/A                                                     (time,pkt));
6308504SN/A                i++;
6318504SN/A            }
6328504SN/A        }
6338504SN/A        else {
6348504SN/A            if (pkt->cmd != Packet::UpgradeReq)
6358504SN/A            {
6368504SN/A                delete pkt->req;
6378504SN/A                delete pkt;
6388504SN/A            }
6398504SN/A        }
6408504SN/A    }
6418504SN/A
6428504SN/A    /**
6438504SN/A     * Suppliess the data if cache to cache transfers are enabled.
6448504SN/A     * @param pkt The bus transaction to fulfill.
6458504SN/A     */
6468504SN/A    void respondToSnoop(PacketPtr pkt, Tick time)
6478504SN/A    {
6488504SN/A        assert(time >= curTick);
6498504SN/A        assert (pkt->needsResponse());
6508504SN/A/*        CacheEvent *reqMem = new CacheEvent(memSidePort, pkt);
6518504SN/A        reqMem->schedule(time);
6528504SN/A*/
6538504SN/A        if (memSidePort->transmitList.empty()) {
6548504SN/A            assert(!memSendEvent->scheduled());
6558504SN/A            memSendEvent->schedule(time);
6568504SN/A            memSidePort->transmitList.push_back(std::pair<Tick,PacketPtr>
6578504SN/A                                                (time,pkt));
6588504SN/A            return;
6598504SN/A        }
6608504SN/A
6618504SN/A        // something is on the list and this belongs at the end
6628504SN/A        if (time >= memSidePort->transmitList.back().first) {
6638504SN/A            memSidePort->transmitList.push_back(std::pair<Tick,PacketPtr>
6648504SN/A                                                (time,pkt));
6658504SN/A            return;
6668504SN/A        }
6678504SN/A        // Something is on the list and this belongs somewhere else
6688504SN/A        std::list<std::pair<Tick,PacketPtr> >::iterator i =
6698504SN/A            memSidePort->transmitList.begin();
6708504SN/A        std::list<std::pair<Tick,PacketPtr> >::iterator end =
6718504SN/A            memSidePort->transmitList.end();
6728504SN/A        bool done = false;
6738504SN/A
6748504SN/A        while (i != end && !done) {
6758504SN/A            if (time < i->first)
6768504SN/A                    memSidePort->transmitList.insert(i,std::pair<Tick,PacketPtr>(time,pkt));
6778504SN/A            i++;
6788504SN/A        }
6798504SN/A    }
6808504SN/A
6818504SN/A    /**
6828504SN/A     * Notification from master interface that a address range changed. Nothing
6838504SN/A     * to do for a cache.
6848504SN/A     */
6858504SN/A    void rangeChange() {}
6868504SN/A
6878504SN/A    void getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop, bool isCpuSide)
6888504SN/A    {
6898504SN/A        if (isCpuSide)
6908504SN/A        {
6918504SN/A            AddrRangeList dummy;
6928504SN/A            memSidePort->getPeerAddressRanges(resp, dummy);
6938504SN/A        }
6948504SN/A        else
6958504SN/A        {
6968504SN/A            //This is where snoops get updated
6978504SN/A            AddrRangeList dummy;
6988504SN/A            cpuSidePort->getPeerAddressRanges(dummy, snoop);
6998504SN/A            return;
7008504SN/A        }
7018504SN/A    }
7028504SN/A
7038504SN/A    virtual unsigned int drain(Event *de);
7048504SN/A
7058504SN/A    void checkDrain()
7068504SN/A    {
7078504SN/A        if (drainEvent && canDrain()) {
7088504SN/A            drainEvent->process();
7098504SN/A            changeState(SimObject::Drained);
7108504SN/A            // Clear the drain event
7118504SN/A            drainEvent = NULL;
7128504SN/A        }
7138504SN/A    }
7148504SN/A
7158504SN/A    bool canDrain()
7168504SN/A    {
7178504SN/A        if (doMasterRequest() || doSlaveRequest()) {
7188504SN/A            return false;
7198504SN/A        } else if (memSidePort && !memSidePort->canDrain()) {
7208504SN/A            return false;
7218504SN/A        } else if (cpuSidePort && !cpuSidePort->canDrain()) {
7228504SN/A            return false;
7238504SN/A        }
7248504SN/A        return true;
7258504SN/A    }
7268504SN/A};
7278504SN/A
7288504SN/A#endif //__BASE_CACHE_HH__
7298504SN/A