base.hh revision 4458
1/*
2 * Copyright (c) 2003-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Erik Hallnor
29 *          Steve Reinhardt
30 *          Ron Dreslinski
31 */
32
33/**
34 * @file
35 * Declares a basic cache interface BaseCache.
36 */
37
38#ifndef __BASE_CACHE_HH__
39#define __BASE_CACHE_HH__
40
41#include <vector>
42#include <string>
43#include <list>
44#include <inttypes.h>
45
46#include "base/misc.hh"
47#include "base/statistics.hh"
48#include "base/trace.hh"
49#include "mem/mem_object.hh"
50#include "mem/packet.hh"
51#include "mem/port.hh"
52#include "mem/request.hh"
53#include "sim/eventq.hh"
54
55/**
56 * Reasons for Caches to be Blocked.
57 */
58enum BlockedCause{
59    Blocked_NoMSHRs,
60    Blocked_NoTargets,
61    Blocked_NoWBBuffers,
62    Blocked_Coherence,
63    NUM_BLOCKED_CAUSES
64};
65
66/**
67 * Reasons for cache to request a bus.
68 */
69enum RequestCause{
70    Request_MSHR,
71    Request_WB,
72    Request_Coherence,
73    Request_PF
74};
75
76class MSHR;
77/**
78 * A basic cache interface. Implements some common functions for speed.
79 */
80class BaseCache : public MemObject
81{
82    class CachePort : public Port
83    {
84      public:
85        BaseCache *cache;
86
87      protected:
88        Event *responseEvent;
89
90        CachePort(const std::string &_name, BaseCache *_cache);
91
92        virtual void recvStatusChange(Status status);
93
94        virtual void getDeviceAddressRanges(AddrRangeList &resp,
95                                            AddrRangeList &snoop);
96
97        virtual int deviceBlockSize();
98
99        bool recvRetryCommon();
100
101      public:
102        void setOtherPort(CachePort *_otherPort) { otherPort = _otherPort; }
103
104        void setBlocked();
105
106        void clearBlocked();
107
108        bool checkFunctional(PacketPtr pkt);
109
110        void checkAndSendFunctional(PacketPtr pkt);
111
112        bool canDrain() { return drainList.empty() && transmitList.empty(); }
113
114        bool drainResponse();
115
116        CachePort *otherPort;
117
118        bool blocked;
119
120        bool mustSendRetry;
121
122        bool waitingOnRetry;
123
124        /**
125         * Bit vector for the outstanding requests for the master interface.
126         */
127        uint8_t requestCauses;
128
129        std::list<PacketPtr> drainList;
130
131        std::list<std::pair<Tick,PacketPtr> > transmitList;
132
133        bool isBusRequested() { return requestCauses != 0; }
134
135        // These need to be virtual since the Event objects depend on
136        // cache template parameters.
137        virtual void scheduleRequestEvent(Tick t) = 0;
138
139        void requestBus(RequestCause cause, Tick time)
140        {
141            if (!isBusRequested() && !waitingOnRetry) {
142                scheduleRequestEvent(time);
143            }
144            requestCauses |= (1 << cause);
145        }
146
147        void deassertBusRequest(RequestCause cause)
148        {
149            requestCauses &= ~(1 << cause);
150        }
151
152        void respond(PacketPtr pkt, Tick time);
153    };
154
155  public: //Made public so coherence can get at it.
156    CachePort *cpuSidePort;
157    CachePort *memSidePort;
158
159  private:
160    /**
161     * Bit vector of the blocking reasons for the access path.
162     * @sa #BlockedCause
163     */
164    uint8_t blocked;
165
166    /**
167     * Bit vector for the blocking reasons for the snoop path.
168     * @sa #BlockedCause
169     */
170    uint8_t blockedSnoop;
171
172  protected:
173
174    /** Stores time the cache blocked for statistics. */
175    Tick blockedCycle;
176
177    /** Block size of this cache */
178    const int blkSize;
179
180    /** The number of misses to trigger an exit event. */
181    Counter missCount;
182
183    /** The drain event. */
184    Event *drainEvent;
185
186  public:
187    // Statistics
188    /**
189     * @addtogroup CacheStatistics
190     * @{
191     */
192
193    /** Number of hits per thread for each type of command. @sa Packet::Command */
194    Stats::Vector<> hits[MemCmd::NUM_MEM_CMDS];
195    /** Number of hits for demand accesses. */
196    Stats::Formula demandHits;
197    /** Number of hit for all accesses. */
198    Stats::Formula overallHits;
199
200    /** Number of misses per thread for each type of command. @sa Packet::Command */
201    Stats::Vector<> misses[MemCmd::NUM_MEM_CMDS];
202    /** Number of misses for demand accesses. */
203    Stats::Formula demandMisses;
204    /** Number of misses for all accesses. */
205    Stats::Formula overallMisses;
206
207    /**
208     * Total number of cycles per thread/command spent waiting for a miss.
209     * Used to calculate the average miss latency.
210     */
211    Stats::Vector<> missLatency[MemCmd::NUM_MEM_CMDS];
212    /** Total number of cycles spent waiting for demand misses. */
213    Stats::Formula demandMissLatency;
214    /** Total number of cycles spent waiting for all misses. */
215    Stats::Formula overallMissLatency;
216
217    /** The number of accesses per command and thread. */
218    Stats::Formula accesses[MemCmd::NUM_MEM_CMDS];
219    /** The number of demand accesses. */
220    Stats::Formula demandAccesses;
221    /** The number of overall accesses. */
222    Stats::Formula overallAccesses;
223
224    /** The miss rate per command and thread. */
225    Stats::Formula missRate[MemCmd::NUM_MEM_CMDS];
226    /** The miss rate of all demand accesses. */
227    Stats::Formula demandMissRate;
228    /** The miss rate for all accesses. */
229    Stats::Formula overallMissRate;
230
231    /** The average miss latency per command and thread. */
232    Stats::Formula avgMissLatency[MemCmd::NUM_MEM_CMDS];
233    /** The average miss latency for demand misses. */
234    Stats::Formula demandAvgMissLatency;
235    /** The average miss latency for all misses. */
236    Stats::Formula overallAvgMissLatency;
237
238    /** The total number of cycles blocked for each blocked cause. */
239    Stats::Vector<> blocked_cycles;
240    /** The number of times this cache blocked for each blocked cause. */
241    Stats::Vector<> blocked_causes;
242
243    /** The average number of cycles blocked for each blocked cause. */
244    Stats::Formula avg_blocked;
245
246    /** The number of fast writes (WH64) performed. */
247    Stats::Scalar<> fastWrites;
248
249    /** The number of cache copies performed. */
250    Stats::Scalar<> cacheCopies;
251
252    /**
253     * @}
254     */
255
256    /**
257     * Register stats for this object.
258     */
259    virtual void regStats();
260
261  public:
262
263    class Params
264    {
265      public:
266        /** List of address ranges of this cache. */
267        std::vector<Range<Addr> > addrRange;
268        /** The hit latency for this cache. */
269        int hitLatency;
270        /** The block size of this cache. */
271        int blkSize;
272        /**
273         * The maximum number of misses this cache should handle before
274         * ending the simulation.
275         */
276        Counter maxMisses;
277
278        /**
279         * Construct an instance of this parameter class.
280         */
281        Params(std::vector<Range<Addr> > addr_range,
282               int hit_latency, int _blkSize, Counter max_misses)
283            : addrRange(addr_range), hitLatency(hit_latency), blkSize(_blkSize),
284              maxMisses(max_misses)
285        {
286        }
287    };
288
289    /**
290     * Create and initialize a basic cache object.
291     * @param name The name of this cache.
292     * @param hier_params Pointer to the HierParams object for this hierarchy
293     * of this cache.
294     * @param params The parameter object for this BaseCache.
295     */
296    BaseCache(const std::string &name, Params &params);
297
298    ~BaseCache()
299    {
300    }
301
302    virtual void init();
303
304    /**
305     * Query block size of a cache.
306     * @return  The block size
307     */
308    int getBlockSize() const
309    {
310        return blkSize;
311    }
312
313    /**
314     * Returns true if the cache is blocked for accesses.
315     */
316    bool isBlocked()
317    {
318        return blocked != 0;
319    }
320
321    /**
322     * Returns true if the cache is blocked for snoops.
323     */
324    bool isBlockedForSnoop()
325    {
326        return blockedSnoop != 0;
327    }
328
329    /**
330     * Marks the access path of the cache as blocked for the given cause. This
331     * also sets the blocked flag in the slave interface.
332     * @param cause The reason for the cache blocking.
333     */
334    void setBlocked(BlockedCause cause)
335    {
336        uint8_t flag = 1 << cause;
337        if (blocked == 0) {
338            blocked_causes[cause]++;
339            blockedCycle = curTick;
340        }
341        int old_state = blocked;
342        if (!(blocked & flag)) {
343            //Wasn't already blocked for this cause
344            blocked |= flag;
345            DPRINTF(Cache,"Blocking for cause %s\n", cause);
346            if (!old_state)
347                cpuSidePort->setBlocked();
348        }
349    }
350
351    /**
352     * Marks the snoop path of the cache as blocked for the given cause. This
353     * also sets the blocked flag in the master interface.
354     * @param cause The reason to block the snoop path.
355     */
356    void setBlockedForSnoop(BlockedCause cause)
357    {
358        uint8_t flag = 1 << cause;
359        uint8_t old_state = blockedSnoop;
360        if (!(blockedSnoop & flag)) {
361            //Wasn't already blocked for this cause
362            blockedSnoop |= flag;
363            if (!old_state)
364                memSidePort->setBlocked();
365        }
366    }
367
368    /**
369     * Marks the cache as unblocked for the given cause. This also clears the
370     * blocked flags in the appropriate interfaces.
371     * @param cause The newly unblocked cause.
372     * @warning Calling this function can cause a blocked request on the bus to
373     * access the cache. The cache must be in a state to handle that request.
374     */
375    void clearBlocked(BlockedCause cause)
376    {
377        uint8_t flag = 1 << cause;
378        DPRINTF(Cache,"Unblocking for cause %s, causes left=%i\n",
379                cause, blocked);
380        if (blocked & flag)
381        {
382            blocked &= ~flag;
383            if (!isBlocked()) {
384                blocked_cycles[cause] += curTick - blockedCycle;
385                DPRINTF(Cache,"Unblocking from all causes\n");
386                cpuSidePort->clearBlocked();
387            }
388        }
389        if (blockedSnoop & flag)
390        {
391            blockedSnoop &= ~flag;
392            if (!isBlockedForSnoop()) {
393                memSidePort->clearBlocked();
394            }
395        }
396    }
397
398    /**
399     * True if the memory-side bus should be requested.
400     * @return True if there are outstanding requests for the master bus.
401     */
402    bool isMemSideBusRequested()
403    {
404        return memSidePort->isBusRequested();
405    }
406
407    /**
408     * Request the master bus for the given cause and time.
409     * @param cause The reason for the request.
410     * @param time The time to make the request.
411     */
412    void requestMemSideBus(RequestCause cause, Tick time)
413    {
414        memSidePort->requestBus(cause, time);
415    }
416
417    /**
418     * Clear the master bus request for the given cause.
419     * @param cause The request reason to clear.
420     */
421    void deassertMemSideBusRequest(RequestCause cause)
422    {
423        memSidePort->deassertBusRequest(cause);
424        checkDrain();
425    }
426
427    /**
428     * Send a response to the slave interface.
429     * @param pkt The request being responded to.
430     * @param time The time the response is ready.
431     */
432    void respond(PacketPtr pkt, Tick time)
433    {
434        cpuSidePort->respond(pkt, time);
435    }
436
437    /**
438     * Suppliess the data if cache to cache transfers are enabled.
439     * @param pkt The bus transaction to fulfill.
440     */
441    void respondToSnoop(PacketPtr pkt, Tick time)
442    {
443        memSidePort->respond(pkt, time);
444    }
445
446    virtual unsigned int drain(Event *de);
447
448    void checkDrain()
449    {
450        if (drainEvent && canDrain()) {
451            drainEvent->process();
452            changeState(SimObject::Drained);
453            // Clear the drain event
454            drainEvent = NULL;
455        }
456    }
457
458    bool canDrain()
459    {
460        if (isMemSideBusRequested()) {
461            return false;
462        } else if (memSidePort && !memSidePort->canDrain()) {
463            return false;
464        } else if (cpuSidePort && !cpuSidePort->canDrain()) {
465            return false;
466        }
467        return true;
468    }
469
470    virtual bool inCache(Addr addr) = 0;
471
472    virtual bool inMissQueue(Addr addr) = 0;
473};
474
475#endif //__BASE_CACHE_HH__
476